diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index ec1522f83..58303e7b6 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -33,11 +33,19 @@
android:name=".MainActivity"
android:label="@string/app_name"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
+ android:launchMode="singleTop"
android:windowSoftInputMode="adjustResize">
+
+
+
+
+
+
+
diff --git a/app/actions/actionsTypes.js b/app/actions/actionsTypes.js
index c6cbe5daf..a125553a4 100644
--- a/app/actions/actionsTypes.js
+++ b/app/actions/actionsTypes.js
@@ -93,6 +93,7 @@ export const PINNED_MESSAGES = createRequestTypes('PINNED_MESSAGES', ['OPEN', 'R
export const MENTIONED_MESSAGES = createRequestTypes('MENTIONED_MESSAGES', ['OPEN', 'READY', 'CLOSE', 'MESSAGES_RECEIVED']);
export const SNIPPETED_MESSAGES = createRequestTypes('SNIPPETED_MESSAGES', ['OPEN', 'READY', 'CLOSE', 'MESSAGES_RECEIVED']);
export const ROOM_FILES = createRequestTypes('ROOM_FILES', ['OPEN', 'READY', 'CLOSE', 'MESSAGES_RECEIVED']);
+export const DEEP_LINKING = createRequestTypes('DEEP_LINKING', ['OPEN']);
export const INCREMENT = 'INCREMENT';
export const DECREMENT = 'DECREMENT';
diff --git a/app/actions/deepLinking.js b/app/actions/deepLinking.js
new file mode 100644
index 000000000..dfd540b6f
--- /dev/null
+++ b/app/actions/deepLinking.js
@@ -0,0 +1,8 @@
+import * as types from './actionsTypes';
+
+export function deepLinkingOpen(params) {
+ return {
+ type: types.DEEP_LINKING.OPEN,
+ params
+ };
+}
diff --git a/app/containers/Routes.js b/app/containers/Routes.js
index 067327970..bb20c90b8 100644
--- a/app/containers/Routes.js
+++ b/app/containers/Routes.js
@@ -1,13 +1,16 @@
import PropTypes from 'prop-types';
import React from 'react';
+import { Linking } from 'react-native';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import SplashScreen from 'react-native-splash-screen';
-import { appInit } from '../actions';
+import { appInit } from '../actions';
+import { deepLinkingOpen } from '../actions/deepLinking';
import AuthRoutes from './routes/AuthRoutes';
import PublicRoutes from './routes/PublicRoutes';
import * as NavigationService from './routes/NavigationService';
+import parseQuery from '../lib/methods/helpers/parseQuery';
@connect(
state => ({
@@ -16,7 +19,7 @@ import * as NavigationService from './routes/NavigationService';
background: state.app.background
}),
dispatch => bindActionCreators({
- appInit
+ appInit, deepLinkingOpen
}, dispatch)
)
export default class Routes extends React.Component {
@@ -26,11 +29,22 @@ export default class Routes extends React.Component {
appInit: PropTypes.func.isRequired
}
+ constructor(props) {
+ super(props);
+ this.handleOpenURL = this.handleOpenURL.bind(this);
+ }
+
componentDidMount() {
if (this.props.app.ready) {
return SplashScreen.hide();
}
this.props.appInit();
+
+ Linking
+ .getInitialURL()
+ .then(url => this.handleOpenURL({ url }))
+ .catch(console.error);
+ Linking.addEventListener('url', this.handleOpenURL);
}
componentWillReceiveProps(nextProps) {
@@ -43,6 +57,18 @@ export default class Routes extends React.Component {
NavigationService.setNavigator(this.navigator);
}
+ handleOpenURL({ url }) {
+ if (url) {
+ url = url.replace(/rocketchat:\/\/|https:\/\/go.rocket.chat\//, '');
+ const regex = /^(room|auth)\?/;
+ if (url.match(regex)) {
+ url = url.replace(regex, '');
+ const params = parseQuery(url);
+ this.props.deepLinkingOpen(params);
+ }
+ }
+ }
+
render() {
const { login } = this.props;
diff --git a/app/containers/routes/NavigationService.js b/app/containers/routes/NavigationService.js
index 11de166e9..ad53eb8ed 100644
--- a/app/containers/routes/NavigationService.js
+++ b/app/containers/routes/NavigationService.js
@@ -34,7 +34,7 @@ export function goRoomsList() {
export function goRoom({ rid, name }, counter = 0) {
// about counter: we can call this method before navigator be set. so we have to wait, if we tried a lot, we give up ...
- if (!rid || !name || counter > 10) {
+ if (!rid || counter > 10) {
return;
}
if (!config.navigator) {
diff --git a/app/lib/ddp.js b/app/lib/ddp.js
index a6fd91c34..e42ec8666 100644
--- a/app/lib/ddp.js
+++ b/app/lib/ddp.js
@@ -224,6 +224,8 @@ export default class Socket extends EventEmitter {
}
disconnect() {
this._close();
+ this._login = null;
+ this.subscriptions = {};
}
async reconnect() {
if (this._timer) {
diff --git a/app/lib/methods/canOpenRoom.js b/app/lib/methods/canOpenRoom.js
new file mode 100644
index 000000000..a7625b97a
--- /dev/null
+++ b/app/lib/methods/canOpenRoom.js
@@ -0,0 +1,51 @@
+import { post } from './helpers/rest';
+import database from '../realm';
+
+// TODO: api fix
+const ddpTypes = {
+ channel: 'c', direct: 'd', group: 'p'
+};
+const restTypes = {
+ channel: 'channels', direct: 'im', group: 'groups'
+};
+
+async function canOpenRoomREST({ type, rid }) {
+ try {
+ const { token, id } = this.ddp._login;
+ const server = this.ddp.url.replace('ws', 'http');
+ await post({ token, id, server }, `${ restTypes[type] }.open`, { roomId: rid });
+ return true;
+ } catch (error) {
+ // TODO: workround for 'already open for the sender' error
+ if (!error.errorType) {
+ return true;
+ }
+ return false;
+ }
+}
+
+async function canOpenRoomDDP(...args) {
+ try {
+ const [{ type, name }] = args;
+ await this.ddp.call('getRoomByTypeAndName', ddpTypes[type], name);
+ return true;
+ } catch (error) {
+ if (error.isClientSafe) {
+ return false;
+ }
+ return canOpenRoomREST.call(this, ...args);
+ }
+}
+
+export default async function canOpenRoom({ rid, path }) {
+ const { database: db } = database;
+ const room = db.objects('subscriptions').filtered('rid == $0', rid);
+ if (room.length) {
+ return true;
+ }
+
+ const [type, name] = path.split('/');
+ // eslint-disable-next-line
+ const data = await (this.ddp && this.ddp.status ? canOpenRoomDDP.call(this, { rid, type, name }) : canOpenRoomREST.call(this, { type, rid }));
+ return data;
+}
diff --git a/app/lib/methods/helpers/parseQuery.js b/app/lib/methods/helpers/parseQuery.js
new file mode 100644
index 000000000..d60610e8a
--- /dev/null
+++ b/app/lib/methods/helpers/parseQuery.js
@@ -0,0 +1,9 @@
+export default function(query) {
+ return (/^[?#]/.test(query) ? query.slice(1) : query)
+ .split('&')
+ .reduce((params, param) => {
+ const [key, value] = param.split('=');
+ params[key] = value ? decodeURIComponent(value.replace(/\+/g, ' ')) : '';
+ return params;
+ }, { });
+}
diff --git a/app/lib/methods/subscriptions/room.js b/app/lib/methods/subscriptions/room.js
index 6c045e6b8..b54d0091a 100644
--- a/app/lib/methods/subscriptions/room.js
+++ b/app/lib/methods/subscriptions/room.js
@@ -21,8 +21,10 @@ const stop = (ddp) => {
promises = false;
}
- ddp.removeListener('logged', logged);
- ddp.removeListener('disconnected', disconnected);
+ if (ddp) {
+ ddp.removeListener('logged', logged);
+ ddp.removeListener('disconnected', disconnected);
+ }
logged = false;
disconnected = false;
@@ -50,18 +52,21 @@ export default async function subscribeRoom({ rid, t }) {
}, 5000);
};
-
- logged = this.ddp.on('logged', () => {
- clearTimeout(timer);
- timer = false;
- promises = subscribe(this.ddp, rid);
- });
-
- disconnected = this.ddp.on('disconnected', () => { loop(); });
-
- if (!this.ddp.status) {
+ if (!this.ddp || !this.ddp.status) {
loop();
} else {
+ logged = this.ddp.on('logged', () => {
+ clearTimeout(timer);
+ timer = false;
+ promises = subscribe(this.ddp, rid);
+ });
+
+ disconnected = this.ddp.on('disconnected', () => {
+ if (this._login) {
+ loop();
+ }
+ });
+
promises = subscribe(this.ddp, rid);
}
diff --git a/app/lib/methods/subscriptions/rooms.js b/app/lib/methods/subscriptions/rooms.js
index 4302568b2..8ac87806e 100644
--- a/app/lib/methods/subscriptions/rooms.js
+++ b/app/lib/methods/subscriptions/rooms.js
@@ -24,35 +24,41 @@ export default async function subscribeRooms(id) {
}, 5000);
};
- this.ddp.on('logged', () => {
- clearTimeout(timer);
- timer = false;
- });
+ if (this.ddp) {
+ this.ddp.on('logged', () => {
+ clearTimeout(timer);
+ timer = false;
+ });
- this.ddp.on('logout', () => {
- clearTimeout(timer);
- timer = true;
- });
+ this.ddp.on('logout', () => {
+ clearTimeout(timer);
+ timer = true;
+ });
- this.ddp.on('disconnected', () => { loop(); });
+ this.ddp.on('disconnected', () => {
+ if (this._login) {
+ loop();
+ }
+ });
- this.ddp.on('stream-notify-user', (ddpMessage) => {
- const [type, data] = ddpMessage.fields.args;
- const [, ev] = ddpMessage.fields.eventName.split('/');
- if (/subscriptions/.test(ev)) {
- const tpm = merge(data);
- return database.write(() => {
- database.create('subscriptions', tpm, true);
- });
- }
- if (/rooms/.test(ev) && type === 'updated') {
- const [sub] = database.objects('subscriptions').filtered('rid == $0', data._id);
- database.write(() => {
- merge(sub, data);
- });
- }
- });
+ this.ddp.on('stream-notify-user', (ddpMessage) => {
+ const [type, data] = ddpMessage.fields.args;
+ const [, ev] = ddpMessage.fields.eventName.split('/');
+ if (/subscriptions/.test(ev)) {
+ const tpm = merge(data);
+ return database.write(() => {
+ database.create('subscriptions', tpm, true);
+ });
+ }
+ if (/rooms/.test(ev) && type === 'updated') {
+ const [sub] = database.objects('subscriptions').filtered('rid == $0', data._id);
+ database.write(() => {
+ merge(sub, data);
+ });
+ }
+ });
+ }
await subscriptions;
- console.log(this.ddp.subscriptions);
+ // console.log(this.ddp.subscriptions);
}
diff --git a/app/lib/rocketchat.js b/app/lib/rocketchat.js
index 834c9dd98..c8f08750f 100644
--- a/app/lib/rocketchat.js
+++ b/app/lib/rocketchat.js
@@ -35,7 +35,7 @@ import getSettings from './methods/getSettings';
import getRooms from './methods/getRooms';
import getPermissions from './methods/getPermissions';
import getCustomEmoji from './methods/getCustomEmojis';
-
+import canOpenRoom from './methods/canOpenRoom';
import _buildMessage from './methods/helpers/buildMessage';
import loadMessagesForRoom from './methods/loadMessagesForRoom';
@@ -51,6 +51,7 @@ const RocketChat = {
TOKEN_KEY,
subscribeRooms,
subscribeRoom,
+ canOpenRoom,
createChannel({ name, users, type }) {
return call(type ? 'createChannel' : 'createPrivateGroup', name, users, type);
},
diff --git a/app/sagas/connect.js b/app/sagas/connect.js
index 7c494275d..e7495efd6 100644
--- a/app/sagas/connect.js
+++ b/app/sagas/connect.js
@@ -17,7 +17,10 @@ const getToken = function* getToken() {
}
return JSON.parse(user);
}
- return yield put(setToken());
+
+ yield AsyncStorage.removeItem(RocketChat.TOKEN_KEY);
+ yield put(setToken());
+ return null;
};
diff --git a/app/sagas/deepLinking.js b/app/sagas/deepLinking.js
new file mode 100644
index 000000000..59b3e7d2f
--- /dev/null
+++ b/app/sagas/deepLinking.js
@@ -0,0 +1,57 @@
+import { AsyncStorage } from 'react-native';
+import { delay } from 'redux-saga';
+import { takeLatest, take, select, call, put } from 'redux-saga/effects';
+import * as types from '../actions/actionsTypes';
+import { setServer, addServer } from '../actions/server';
+import * as NavigationService from '../containers/routes/NavigationService';
+import database from '../lib/realm';
+import RocketChat from '../lib/rocketchat';
+
+const navigate = function* go({ server, params, sameServer = true }) {
+ const user = yield AsyncStorage.getItem(`${ RocketChat.TOKEN_KEY }-${ server }`);
+ if (user) {
+ const { rid, path } = params;
+ if (rid) {
+ const canOpenRoom = yield RocketChat.canOpenRoom({ rid, path });
+ if (canOpenRoom) {
+ return yield call(NavigationService.goRoom, { rid: params.rid });
+ }
+ }
+ if (!sameServer) {
+ yield call(NavigationService.goRoomsList);
+ }
+ }
+};
+
+const handleOpen = function* handleOpen({ params }) {
+ const isReady = yield select(state => state.app.ready);
+ const server = yield select(state => state.server.server);
+
+ if (!isReady) {
+ yield take(types.APP.READY);
+ }
+
+ const host = `https://${ params.host }`;
+
+ // TODO: needs better test
+ // if deep link is from same server
+ if (server === host) {
+ yield navigate({ server, params });
+ } else { // if deep link is from a different server
+ // search if deep link's server already exists
+ const servers = yield database.databases.serversDB.objects('servers').filtered('id = $0', host); // TODO: need better test
+ if (servers.length) {
+ // if server exists, select it
+ yield put(setServer(servers[0].id));
+ yield delay(2000);
+ yield navigate({ server: servers[0].id, params, sameServer: false });
+ } else {
+ yield put(addServer(host));
+ }
+ }
+};
+
+const root = function* root() {
+ yield takeLatest(types.DEEP_LINKING.OPEN, handleOpen);
+};
+export default root;
diff --git a/app/sagas/index.js b/app/sagas/index.js
index 6489d7a32..7547ed382 100644
--- a/app/sagas/index.js
+++ b/app/sagas/index.js
@@ -12,6 +12,7 @@ import pinnedMessages from './pinnedMessages';
import mentionedMessages from './mentionedMessages';
import snippetedMessages from './snippetedMessages';
import roomFiles from './roomFiles';
+import deepLinking from './deepLinking';
const root = function* root() {
yield all([
@@ -27,7 +28,8 @@ const root = function* root() {
pinnedMessages(),
mentionedMessages(),
snippetedMessages(),
- roomFiles()
+ roomFiles(),
+ deepLinking()
]);
};
diff --git a/app/sagas/selectServer.js b/app/sagas/selectServer.js
index 6aaf7ae3f..8513138fb 100644
--- a/app/sagas/selectServer.js
+++ b/app/sagas/selectServer.js
@@ -1,14 +1,14 @@
-import { put, call, takeLatest, race, take } from 'redux-saga/effects';
+import { put, call, takeLatest, take } from 'redux-saga/effects';
import { delay } from 'redux-saga';
import { AsyncStorage } from 'react-native';
-import { SERVER } from '../actions/actionsTypes';
+import { SERVER, LOGIN } from '../actions/actionsTypes';
import * as actions from '../actions';
import { connectRequest } from '../actions/connect';
-import { serverSuccess, serverFailure, serverRequest, setServer } from '../actions/server';
+import { serverSuccess, serverFailure, setServer } from '../actions/server';
import { setRoles } from '../actions/roles';
import RocketChat from '../lib/rocketchat';
import database from '../lib/realm';
-import * as NavigationService from '../containers/routes/NavigationService';
+import { navigate } from '../containers/routes/NavigationService';
const validate = function* validate(server) {
return yield RocketChat.testServer(server);
@@ -21,6 +21,7 @@ const selectServer = function* selectServer({ server }) {
// yield RocketChat.disconnect();
yield call([AsyncStorage, 'setItem'], 'currentServer', server);
+ // yield AsyncStorage.removeItem(RocketChat.TOKEN_KEY);
const settings = database.objects('settings');
yield put(actions.setAllSettings(RocketChat.parseSettings(settings.slice(0, settings.length))));
const permissions = database.objects('permissions');
@@ -33,7 +34,7 @@ const selectServer = function* selectServer({ server }) {
return result;
}, {})));
- yield put(connectRequest(server));
+ yield put(connectRequest());
} catch (e) {
console.warn('selectServer', e);
}
@@ -51,23 +52,17 @@ const validateServer = function* validateServer({ server }) {
};
const addServer = function* addServer({ server }) {
- yield put(serverRequest(server));
-
- const { error } = yield race({
- error: take(SERVER.FAILURE),
- success: take(SERVER.SUCCESS)
+ database.databases.serversDB.write(() => {
+ database.databases.serversDB.create('servers', { id: server, current: false }, true);
});
- if (!error) {
- database.databases.serversDB.write(() => {
- database.databases.serversDB.create('servers', { id: server, current: false }, true);
- });
- yield put(setServer(server));
- }
+ yield put(setServer(server));
+ yield take(LOGIN.SET_TOKEN);
+ navigate('LoginSignup');
};
const handleGotoAddServer = function* handleGotoAddServer() {
yield call(AsyncStorage.removeItem, RocketChat.TOKEN_KEY);
- yield call(NavigationService.navigate, 'AddServer');
+ yield call(navigate, 'AddServer');
};
const root = function* root() {
diff --git a/app/views/NewServerView.js b/app/views/NewServerView.js
index 86e2bc579..8d536b48a 100644
--- a/app/views/NewServerView.js
+++ b/app/views/NewServerView.js
@@ -49,7 +49,6 @@ export default class NewServerView extends LoggedView {
submit = () => {
this.props.addServer(this.completeUrl(this.state.text));
- this.props.navigation.navigate('LoginSignup');
}
completeUrl = (url) => {
diff --git a/app/views/RoomView/Header/index.js b/app/views/RoomView/Header/index.js
index 7d21e00c0..d7cb05cba 100644
--- a/app/views/RoomView/Header/index.js
+++ b/app/views/RoomView/Header/index.js
@@ -54,16 +54,22 @@ export default class RoomHeaderView extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
- room: realm.objects('subscriptions').filtered('rid = $0', this.rid)[0] || {},
- roomName: props.navigation.state.params.room.name
+ room: props.navigation.state.params.room
};
- this.rid = props.navigation.state.params.room.rid;
- this.room = realm.objects('subscriptions').filtered('rid = $0', this.rid);
- this.room.addListener(this.updateState);
+ this.room = realm.objects('subscriptions').filtered('rid = $0', this.state.room.rid);
}
componentDidMount() {
this.updateState();
+ this.room.addListener(this.updateState);
+ }
+
+ componentWillReceiveProps(nextProps) {
+ if (nextProps.navigation.state.params.room !== this.props.navigation.state.params.room) {
+ this.room.removeAllListeners();
+ this.room = realm.objects('subscriptions').filtered('rid = $0', nextProps.navigation.state.params.room.rid);
+ this.room.addListener(this.updateState);
+ }
}
componentWillUnmount() {
@@ -71,7 +77,7 @@ export default class RoomHeaderView extends React.PureComponent {
}
getUserStatus() {
- const userId = this.rid.replace(this.props.user.id, '').trim();
+ const userId = this.state.room.rid.replace(this.props.user.id, '').trim();
const userInfo = this.props.activeUsers[userId];
return (userInfo && userInfo.status) || 'offline';
}
@@ -82,7 +88,9 @@ export default class RoomHeaderView extends React.PureComponent {
}
updateState = () => {
- this.setState({ room: this.room[0] });
+ if (this.room.length > 0) {
+ this.setState({ room: this.room[0] });
+ }
};
isDirect = () => this.state.room && this.state.room.t === 'd';
@@ -98,11 +106,11 @@ export default class RoomHeaderView extends React.PureComponent {
/>);
renderCenter() {
- if (!this.state.roomName) {
+ if (!this.state.room.name) {
return null;
}
- let accessibilityLabel = this.state.roomName;
+ let accessibilityLabel = this.state.room.name;
if (this.isDirect()) {
accessibilityLabel += `, ${ this.getUserStatusLabel() }`;
@@ -125,11 +133,11 @@ export default class RoomHeaderView extends React.PureComponent {
style={styles.titleContainer}
accessibilityLabel={accessibilityLabel}
accessibilityTraits='header'
- onPress={() => this.props.navigation.navigate({ key: 'RoomInfo', routeName: 'RoomInfo', params: { rid: this.rid } })}
+ onPress={() => this.props.navigation.navigate({ key: 'RoomInfo', routeName: 'RoomInfo', params: { rid: this.state.rid } })}
>
- {this.state.roomName}
+ {this.state.room.name}
{ t && {t}}
diff --git a/app/views/RoomView/index.js b/app/views/RoomView/index.js
index 8b0eab1b0..29f481c09 100644
--- a/app/views/RoomView/index.js
+++ b/app/views/RoomView/index.js
@@ -65,22 +65,17 @@ export default class RoomView extends LoggedView {
this.rid =
props.rid ||
props.navigation.state.params.room.rid;
- this.name = props.name ||
- props.navigation.state.params.name ||
- props.navigation.state.params.room.name;
this.rooms = database.objects('subscriptions').filtered('rid = $0', this.rid);
this.state = {
loaded: true,
joined: typeof props.rid === 'undefined',
- room: JSON.parse(JSON.stringify(this.rooms[0]))
+ room: {}
};
this.onReactionPress = this.onReactionPress.bind(this);
}
async componentDidMount() {
- this.props.navigation.setParams({
- title: this.name
- });
+ await this.updateRoom();
await this.props.openRoom({
...this.state.room
});
@@ -89,7 +84,6 @@ export default class RoomView extends LoggedView {
} else {
this.props.setLastOpen(null);
}
-
this.rooms.addListener(this.updateRoom);
}
shouldComponentUpdate(nextProps, nextState) {
@@ -129,8 +123,10 @@ export default class RoomView extends LoggedView {
RocketChat.setReaction(shortname, messageId);
};
- updateRoom = () => {
- this.setState({ room: JSON.parse(JSON.stringify(this.rooms[0])) });
+ updateRoom = async() => {
+ if (this.rooms.length > 0) {
+ await this.setState({ room: JSON.parse(JSON.stringify(this.rooms[0])) });
+ }
}
sendMessage = (message) => {
diff --git a/app/views/RoomsListView/index.js b/app/views/RoomsListView/index.js
index 52949b126..776b4a5ea 100644
--- a/app/views/RoomsListView/index.js
+++ b/app/views/RoomsListView/index.js
@@ -123,13 +123,17 @@ export default class RoomsListView extends LoggedView {
}
_onPressItem = async(item = {}) => {
- // if user is using the search we need first to join/create room
if (!item.search) {
- return this.props.navigation.navigate({ key: `Room-${ item._id }`, routeName: 'Room', params: { room: item, ...item } });
+ return goRoom({ rid: item.rid });
}
if (item.t === 'd') {
- const sub = await RocketChat.createDirectMessageAndWait(item.username);
- return goRoom({ room: sub, name: sub.name });
+ // if user is using the search we need first to join/create room
+ try {
+ const sub = await RocketChat.createDirectMessage(item.username);
+ return goRoom(sub);
+ } catch (error) {
+ console.warn('_onPressItem', error);
+ }
}
return goRoom(item);
}
diff --git a/ios/RocketChatRN/AppDelegate.m b/ios/RocketChatRN/AppDelegate.m
index d95a78284..99fba08a3 100644
--- a/ios/RocketChatRN/AppDelegate.m
+++ b/ios/RocketChatRN/AppDelegate.m
@@ -15,6 +15,7 @@
#import "SplashScreen.h"
#import
#import
+#import
@implementation AppDelegate
@@ -70,4 +71,20 @@
{
[RCTPushNotificationManager didReceiveLocalNotification:notification];
}
+
+- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url
+ sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
+{
+ return [RCTLinkingManager application:application openURL:url
+ sourceApplication:sourceApplication annotation:annotation];
+}
+
+// Only if your app is using [Universal Links](https://developer.apple.com/library/prerelease/ios/documentation/General/Conceptual/AppSearch/UniversalLinks.html).
+- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity
+ restorationHandler:(void (^)(NSArray * _Nullable))restorationHandler
+{
+ return [RCTLinkingManager application:application
+ continueUserActivity:userActivity
+ restorationHandler:restorationHandler];
+}
@end
diff --git a/ios/RocketChatRN/Info.plist b/ios/RocketChatRN/Info.plist
index 18e208096..accf9760b 100644
--- a/ios/RocketChatRN/Info.plist
+++ b/ios/RocketChatRN/Info.plist
@@ -20,6 +20,20 @@
1.0.0
CFBundleSignature
????
+ CFBundleURLTypes
+
+
+ CFBundleTypeRole
+ Editor
+ CFBundleURLName
+ rocketchat
+ CFBundleURLSchemes
+
+ rocketchat
+ https://go.rocket.chat
+
+
+
CFBundleVersion
100
Fabric