[FIX] Deep linking and other connectivity issues (#2894)
* Navigate from push notification only if necessary * Use JS SDK branch * Stop reconnecting if it's already connected * Fix RoomsListView forever loading after tapping push notification of another server * Execute fewer operations on app/index * Remove roomsRequest call from onForeground * Apply check and reopen * Stop opening in-app notification when the app is on backgorund * Connecting tweaks * Fix deep linking not working if the app is on background * Force reset yarn cache * Upgrade JS SDK * Remove listener on unmount * Fix resume on Android after back button is pressed * Fix local authentication resume * Fix back button android * Change JS SDK branch
This commit is contained in:
parent
40c075d748
commit
cc8dc6a75a
|
@ -29,7 +29,7 @@
|
|||
android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
|
||||
android:exported="true"
|
||||
android:label="@string/app_name"
|
||||
android:launchMode="singleTop"
|
||||
android:launchMode="singleTask"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.DOWNLOAD_COMPLETE" />
|
||||
|
|
|
@ -11,8 +11,12 @@ import { getActiveRoute } from '../../utils/navigation';
|
|||
|
||||
export const INAPP_NOTIFICATION_EMITTER = 'NotificationInApp';
|
||||
|
||||
const InAppNotification = memo(({ rooms }) => {
|
||||
const InAppNotification = memo(({ rooms, appState }) => {
|
||||
const show = (notification) => {
|
||||
if (appState !== 'foreground') {
|
||||
return;
|
||||
}
|
||||
|
||||
const { payload } = notification;
|
||||
const state = Navigation.navigationRef.current?.getRootState();
|
||||
const route = getActiveRoute(state);
|
||||
|
@ -41,11 +45,13 @@ const InAppNotification = memo(({ rooms }) => {
|
|||
}, (prevProps, nextProps) => dequal(prevProps.rooms, nextProps.rooms));
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
rooms: state.room.rooms
|
||||
rooms: state.room.rooms,
|
||||
appState: state.app.ready && state.app.foreground ? 'foreground' : 'background'
|
||||
});
|
||||
|
||||
InAppNotification.propTypes = {
|
||||
rooms: PropTypes.array
|
||||
rooms: PropTypes.array,
|
||||
appState: PropTypes.string
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps)(InAppNotification);
|
||||
|
|
21
app/index.js
21
app/index.js
|
@ -112,16 +112,25 @@ export default class Root extends React.Component {
|
|||
|
||||
init = async() => {
|
||||
UserPreferences.getMapAsync(THEME_PREFERENCES_KEY).then(this.setTheme);
|
||||
const [notification, deepLinking] = await Promise.all([initializePushNotifications(), Linking.getInitialURL()]);
|
||||
const parsedDeepLinkingURL = parseDeepLinking(deepLinking);
|
||||
store.dispatch(appInitLocalSettings());
|
||||
|
||||
// Open app from push notification
|
||||
const notification = await initializePushNotifications();
|
||||
if (notification) {
|
||||
onNotification(notification);
|
||||
} else if (parsedDeepLinkingURL) {
|
||||
store.dispatch(deepLinkingOpen(parsedDeepLinkingURL));
|
||||
} else {
|
||||
store.dispatch(appInit());
|
||||
return;
|
||||
}
|
||||
|
||||
// Open app from deep linking
|
||||
const deepLinking = await Linking.getInitialURL();
|
||||
const parsedDeepLinkingURL = parseDeepLinking(deepLinking);
|
||||
if (parsedDeepLinkingURL) {
|
||||
store.dispatch(deepLinkingOpen(parsedDeepLinkingURL));
|
||||
return;
|
||||
}
|
||||
|
||||
// Open app from app icon
|
||||
store.dispatch(appInit());
|
||||
}
|
||||
|
||||
getMasterDetail = (width) => {
|
||||
|
|
|
@ -407,7 +407,7 @@ export default function subscribeRooms() {
|
|||
};
|
||||
|
||||
connectedListener = this.sdk.onStreamData('connected', handleConnection);
|
||||
disconnectedListener = this.sdk.onStreamData('close', handleConnection);
|
||||
// disconnectedListener = this.sdk.onStreamData('close', handleConnection);
|
||||
streamListener = this.sdk.onStreamData('stream-notify-user', handleStreamMessageReceived);
|
||||
|
||||
try {
|
||||
|
|
|
@ -177,9 +177,16 @@ const RocketChat = {
|
|||
}
|
||||
this.controller = new AbortController();
|
||||
},
|
||||
checkAndReopen() {
|
||||
return this?.sdk?.checkAndReopen();
|
||||
},
|
||||
connect({ server, user, logoutOnError = false }) {
|
||||
return new Promise((resolve) => {
|
||||
if (!this.sdk || this.sdk.client.host !== server) {
|
||||
if (this?.sdk?.client?.host === server) {
|
||||
return resolve();
|
||||
} else {
|
||||
this.sdk?.disconnect?.();
|
||||
this.sdk = null;
|
||||
database.setActiveDB(server);
|
||||
}
|
||||
reduxStore.dispatch(connectRequest());
|
||||
|
@ -208,11 +215,6 @@ const RocketChat = {
|
|||
|
||||
EventEmitter.emit('INQUIRY_UNSUBSCRIBE');
|
||||
|
||||
if (this.sdk) {
|
||||
this.sdk.disconnect();
|
||||
this.sdk = null;
|
||||
}
|
||||
|
||||
if (this.code) {
|
||||
this.code = null;
|
||||
}
|
||||
|
@ -240,6 +242,10 @@ const RocketChat = {
|
|||
|
||||
sdkConnect();
|
||||
|
||||
this.connectedListener = this.sdk.onStreamData('connecting', () => {
|
||||
reduxStore.dispatch(connectRequest());
|
||||
});
|
||||
|
||||
this.connectedListener = this.sdk.onStreamData('connected', () => {
|
||||
reduxStore.dispatch(connectSuccess());
|
||||
});
|
||||
|
|
|
@ -31,6 +31,14 @@ const handleInviteLink = function* handleInviteLink({ params, requireLogin = fal
|
|||
}
|
||||
};
|
||||
|
||||
const popToRoot = function popToRoot({ isMasterDetail }) {
|
||||
if (isMasterDetail) {
|
||||
Navigation.navigate('DrawerNavigator');
|
||||
} else {
|
||||
Navigation.navigate('RoomsListView');
|
||||
}
|
||||
};
|
||||
|
||||
const navigate = function* navigate({ params }) {
|
||||
yield put(appStart({ root: ROOT_INSIDE }));
|
||||
if (params.path) {
|
||||
|
@ -38,19 +46,28 @@ const navigate = function* navigate({ params }) {
|
|||
if (type !== 'invite') {
|
||||
const room = yield RocketChat.canOpenRoom(params);
|
||||
if (room) {
|
||||
const isMasterDetail = yield select(state => state.app.isMasterDetail);
|
||||
if (isMasterDetail) {
|
||||
Navigation.navigate('DrawerNavigator');
|
||||
} else {
|
||||
Navigation.navigate('RoomsListView');
|
||||
}
|
||||
const item = {
|
||||
name,
|
||||
t: roomTypes[type],
|
||||
roomUserId: RocketChat.getUidDirectMessage(room),
|
||||
...room
|
||||
};
|
||||
yield goRoom({ item, isMasterDetail });
|
||||
|
||||
const isMasterDetail = yield select(state => state.app.isMasterDetail);
|
||||
const focusedRooms = yield select(state => state.room.rooms);
|
||||
|
||||
if (focusedRooms.includes(room.rid)) {
|
||||
// if there's one room on the list or last room is the one
|
||||
if (focusedRooms.length === 1 || focusedRooms[0] === room.rid) {
|
||||
yield goRoom({ item, isMasterDetail });
|
||||
} else {
|
||||
popToRoot({ isMasterDetail });
|
||||
yield goRoom({ item, isMasterDetail });
|
||||
}
|
||||
} else {
|
||||
popToRoot({ isMasterDetail });
|
||||
yield goRoom({ item, isMasterDetail });
|
||||
}
|
||||
|
||||
if (params.isCall) {
|
||||
RocketChat.callJitsi(item);
|
||||
|
@ -121,10 +138,10 @@ const handleOpen = function* handleOpen({ params }) {
|
|||
} else {
|
||||
// search if deep link's server already exists
|
||||
try {
|
||||
const servers = yield serversCollection.find(host);
|
||||
if (servers && user) {
|
||||
const hostServerRecord = yield serversCollection.find(host);
|
||||
if (hostServerRecord && user) {
|
||||
yield localAuthenticate(host);
|
||||
yield put(selectServerRequest(host));
|
||||
yield put(selectServerRequest(host, hostServerRecord.version, true, true));
|
||||
yield take(types.LOGIN.SUCCESS);
|
||||
yield navigate({ params });
|
||||
return;
|
||||
|
|
|
@ -12,13 +12,14 @@ const appHasComeBackToForeground = function* appHasComeBackToForeground() {
|
|||
if (appRoot === ROOT_OUTSIDE) {
|
||||
return;
|
||||
}
|
||||
const auth = yield select(state => state.login.isAuthenticated);
|
||||
if (!auth) {
|
||||
const login = yield select(state => state.login);
|
||||
const server = yield select(state => state.server);
|
||||
if (!login.isAuthenticated || login.isFetching || server.connecting || server.loading || server.changingServer) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const server = yield select(state => state.server.server);
|
||||
yield localAuthenticate(server);
|
||||
yield localAuthenticate(server.server);
|
||||
RocketChat.checkAndReopen();
|
||||
setBadgeCount();
|
||||
return yield RocketChat.setUserPresenceOnline();
|
||||
} catch (e) {
|
||||
|
@ -31,14 +32,6 @@ const appHasComeBackToBackground = function* appHasComeBackToBackground() {
|
|||
if (appRoot === ROOT_OUTSIDE) {
|
||||
return;
|
||||
}
|
||||
const auth = yield select(state => state.login.isAuthenticated);
|
||||
if (!auth) {
|
||||
return;
|
||||
}
|
||||
const localAuthenticated = yield select(state => state.login.isLocalAuthenticated);
|
||||
if (!localAuthenticated) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const server = yield select(state => state.server.server);
|
||||
yield saveLastLocalAuthenticationSession(server);
|
||||
|
|
|
@ -102,9 +102,6 @@ export const localAuthenticate = async(server) => {
|
|||
|
||||
// if screen lock is enabled
|
||||
if (serverRecord?.autoLock) {
|
||||
// set isLocalAuthenticated to false
|
||||
store.dispatch(setLocalAuthenticated(false));
|
||||
|
||||
// Make sure splash screen has been hidden
|
||||
RNBootSplash.hide();
|
||||
|
||||
|
@ -118,6 +115,9 @@ export const localAuthenticate = async(server) => {
|
|||
|
||||
// if last authenticated session is older than configured auto lock time, authentication is required
|
||||
if (diffToLastSession >= serverRecord?.autoLockTime) {
|
||||
// set isLocalAuthenticated to false
|
||||
store.dispatch(setLocalAuthenticated(false));
|
||||
|
||||
let hasBiometry = false;
|
||||
|
||||
// if biometry is enabled on the app
|
||||
|
|
|
@ -89,7 +89,6 @@ const shouldUpdateProps = [
|
|||
'showUnread',
|
||||
'useRealName',
|
||||
'StoreLastMessage',
|
||||
'appState',
|
||||
'theme',
|
||||
'isMasterDetail',
|
||||
'refreshing',
|
||||
|
@ -126,7 +125,6 @@ class RoomsListView extends React.Component {
|
|||
showUnread: PropTypes.bool,
|
||||
refreshing: PropTypes.bool,
|
||||
StoreLastMessage: PropTypes.bool,
|
||||
appState: PropTypes.string,
|
||||
theme: PropTypes.string,
|
||||
toggleSortDropdown: PropTypes.func,
|
||||
openSearchHeader: PropTypes.func,
|
||||
|
@ -135,7 +133,6 @@ class RoomsListView extends React.Component {
|
|||
roomsRequest: PropTypes.func,
|
||||
closeServerDropdown: PropTypes.func,
|
||||
useRealName: PropTypes.bool,
|
||||
connected: PropTypes.bool,
|
||||
isMasterDetail: PropTypes.bool,
|
||||
rooms: PropTypes.array,
|
||||
width: PropTypes.number,
|
||||
|
@ -276,9 +273,6 @@ class RoomsListView extends React.Component {
|
|||
groupByType,
|
||||
showFavorites,
|
||||
showUnread,
|
||||
appState,
|
||||
connected,
|
||||
roomsRequest,
|
||||
rooms,
|
||||
isMasterDetail,
|
||||
insets
|
||||
|
@ -294,12 +288,6 @@ class RoomsListView extends React.Component {
|
|||
)
|
||||
) {
|
||||
this.getSubscriptions();
|
||||
} else if (
|
||||
appState === 'foreground'
|
||||
&& appState !== prevProps.appState
|
||||
&& connected
|
||||
) {
|
||||
roomsRequest();
|
||||
}
|
||||
// Update current item in case of another action triggers an update on rooms reducer
|
||||
if (isMasterDetail && item?.rid !== rooms[0] && !dequal(rooms, prevProps.rooms)) {
|
||||
|
@ -319,6 +307,9 @@ class RoomsListView extends React.Component {
|
|||
if (this.unsubscribeBlur) {
|
||||
this.unsubscribeBlur();
|
||||
}
|
||||
if (this.backHandler && this.backHandler.remove) {
|
||||
this.backHandler.remove();
|
||||
}
|
||||
if (isTablet) {
|
||||
EventEmitter.removeListener(KEY_COMMAND, this.handleCommands);
|
||||
}
|
||||
|
@ -1018,7 +1009,6 @@ const mapStateToProps = state => ({
|
|||
isMasterDetail: state.app.isMasterDetail,
|
||||
server: state.server.server,
|
||||
changingServer: state.server.changingServer,
|
||||
connected: state.server.connected,
|
||||
searchText: state.rooms.searchText,
|
||||
loadingServer: state.server.loading,
|
||||
showServerDropdown: state.rooms.showServerDropdown,
|
||||
|
@ -1029,7 +1019,6 @@ const mapStateToProps = state => ({
|
|||
showFavorites: state.sortPreferences.showFavorites,
|
||||
showUnread: state.sortPreferences.showUnread,
|
||||
useRealName: state.settings.UI_Use_Real_Name,
|
||||
appState: state.app.ready && state.app.foreground ? 'foreground' : 'background',
|
||||
StoreLastMessage: state.settings.Store_Last_Message,
|
||||
rooms: state.room.rooms,
|
||||
queueSize: getInquiryQueueSelector(state).length,
|
||||
|
|
|
@ -48,6 +48,9 @@ class ReplyNotification: RNNotificationEventHandler {
|
|||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let body = RNNotificationParser.parseNotificationResponse(response)
|
||||
RNEventEmitter.sendEvent(RNNotificationOpened, body: body)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
#import <react-native-notifications/RNNotificationEventHandler.h>
|
||||
#import <react-native-notifications/RNNotificationCenter.h>
|
||||
#import <react-native-notifications/RCTConvert+RNNotifications.h>
|
||||
#import <react-native-notifications/RNEventEmitter.h>
|
||||
#import <react-native-notifications/RNNotificationParser.h>
|
||||
#import <react-native-simple-crypto/Aes.h>
|
||||
#import <react-native-simple-crypto/Rsa.h>
|
||||
#import <react-native-simple-crypto/Shared.h>
|
||||
|
|
|
@ -120,7 +120,7 @@
|
|||
"reselect": "4.0.0",
|
||||
"rn-extensions-share": "RocketChat/rn-extensions-share",
|
||||
"rn-fetch-blob": "0.12.0",
|
||||
"rn-root-view": "^1.0.3",
|
||||
"rn-root-view": "1.0.3",
|
||||
"semver": "7.3.2",
|
||||
"ua-parser-js": "^0.7.21",
|
||||
"url-parse": "^1.4.7",
|
||||
|
|
|
@ -2274,7 +2274,7 @@
|
|||
|
||||
"@rocket.chat/sdk@RocketChat/Rocket.Chat.js.SDK#mobile":
|
||||
version "1.0.0-mobile"
|
||||
resolved "https://codeload.github.com/RocketChat/Rocket.Chat.js.SDK/tar.gz/0a97c818e60670d7660868ea107b96e5ebb631af"
|
||||
resolved "https://codeload.github.com/RocketChat/Rocket.Chat.js.SDK/tar.gz/0241e2fc0c29827c51655f2d46d96e7a7720d2b6"
|
||||
dependencies:
|
||||
js-sha256 "^0.9.0"
|
||||
lru-cache "^4.1.1"
|
||||
|
@ -13788,7 +13788,7 @@ rn-host-detect@1.2.0:
|
|||
resolved "https://registry.yarnpkg.com/rn-host-detect/-/rn-host-detect-1.2.0.tgz#8b0396fc05631ec60c1cb8789e5070cdb04d0da0"
|
||||
integrity sha512-btNg5kzHcjZZ7t7mvvV/4wNJ9e3MPgrWivkRgWURzXL0JJ0pwWlU4zrbmdlz3HHzHOxhBhHB4D+/dbMFfu4/4A==
|
||||
|
||||
rn-root-view@^1.0.3:
|
||||
rn-root-view@1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/rn-root-view/-/rn-root-view-1.0.3.tgz#a2cddc717278cb2175fb29b7c006e407b7f0d0e2"
|
||||
integrity sha512-BIKm8hY5q8+pxK9B5ugYjqutoI9xn2JfxIZKWoaFmAl1bOIM4oXjwFQrRM1e6lFgzz99MN6Mf2dK3Alsywnvvw==
|
||||
|
|
Loading…
Reference in New Issue