延迟通知深度链接,直到 react-native expo 应用程序完全加载后
Defer notification deep linking until after react-native expo app is fully loaded
我想推迟与通知相关的深度 link 导航事件,直到我的 react-native 应用程序在通知点击时打开后应用程序完全加载。
目前,我的通知侦听器在我的 App.tsx
文件中。当应用程序处于后台时,深度 linking 按预期工作,但是当通知触发应用程序打开时,导航事件在应用程序有机会完全加载之前被启动。这意味着虽然我确实深入 linked 到正确的位置,但我的一些资产尚未加载并且我的身份验证逻辑全部被绕过。
有没有办法让通知打开应用程序,但要等到所有内容都加载完毕(特别是 AppLoading 组件已完成 运行 其功能)才能导航到深层 linking 位置?我可以想到一些看似 hack-y 的方法来做到这一点,但是否有一种常用的既定模式?
好的,所以我不确定这是否是处理此问题的最佳方法,但我找到了一种让我的通知正常工作的方法。
(1) 我创建了一个名为 registerAppLoaded
的动作和一个状态变量 appLoaded
,一旦我的 AppLoading
组件完成其 startAsync
函数,我就会发送该变量。
(2) 当收到通知时,我首先检查 appLoaded
是否为真。如果是这样,我将导航到与通知一起发送的目的地。如果没有,我将通知放入商店并继续启动应用程序。
(3) 在AppLoading
onFinish
函数中,我查看是否有通知。如果是这样,并且它被标记为 new
,我会抓住它并使用参数进行导航。然后我发送一个设置 navigation.new = false
的动作
似乎完全按照我需要的方式工作!
如果其他人正在处理这个问题,这是我的代码:
App.tsx:
export default class App extends React.Component {
componentDidMount() {
Notifications.addListener((notification) => {
if (notification.origin === "received") {
return;
} else {
const appLoaded = store.getState().general.appLoaded
if (appLoaded) {
NavigationService.navigate(notification.data.navigate, {id:notification.data.id , shouldRefresh: true})
} else {
// save notification as new
store.dispatch(addNotification(notification, true));
}
};
})
}
render() {
return (
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<View style={styles.container}>
{Platform.OS === "ios" && <StatusBar barStyle="default" />}
<ErrorBoundary backup={<AppError />}>
<AppNavigator />
</ErrorBoundary>
</View>
</PersistGate>
</Provider>
);
}
}
AppLoading.tsx:
class AppLoadingScreen extends React.Component {
_loadResourcesAsync = async() => {
await this.props.fetchUserOnboarding(this.props.userId);
if (this.props.userDevice && this.props.userDevice.id) {
this.props.registerUserDevice(this.props.userId, this.props.userDevice.id)
}
// register that the app has finished loading in the store; this will be used to determine if a notification's deep
// link should be immediatedly navigated to or if the navigation even shuold be deferred until after the app
// finishes loading
await this.props.registerAppLoaded()
};
_handleFinishLoading = async () => {
// if a notification triggers the event listener but the app is not yet fully loaded, the deep link will be
// navigated to here instead of directly from the listener
const notification = this.props.userNotifications && this.props.userNotifications[0]
if (notification && notification.new && notification.origin != 'recieved') {
this.props.addNotification(notification, false) // set notification.new = false
this.props.navigation.navigate(notification.data.navigate, {id: notification.data.id, shouldRefresh: true})
} else if (this.props.showGoalsPrompt) {
this.props.navigation.navigate("Goal");
} else {
this.props.navigation.navigate("HomeFeed");
}
};
render() {
return (
<AppLoading
startAsync={this._loadResourcesAsync}
onFinish={this._handleFinishLoading}
/>
);
}
}
actions.tsx:
export const registerAppLoaded = () => {
return dispatch => {
dispatch({
type: types.REGISTER_APP_LOADED,
payload: true
});
};
}
export const addNotification = (notification, isNew=false) => {
return dispatch => {
notification.new = isNew // indicate whether this is a new notification or if it has been seen
dispatch({
type:types.ADD_USER_NOTIFICATION,
payload: notification,
})
};
}
我想推迟与通知相关的深度 link 导航事件,直到我的 react-native 应用程序在通知点击时打开后应用程序完全加载。
目前,我的通知侦听器在我的 App.tsx
文件中。当应用程序处于后台时,深度 linking 按预期工作,但是当通知触发应用程序打开时,导航事件在应用程序有机会完全加载之前被启动。这意味着虽然我确实深入 linked 到正确的位置,但我的一些资产尚未加载并且我的身份验证逻辑全部被绕过。
有没有办法让通知打开应用程序,但要等到所有内容都加载完毕(特别是 AppLoading 组件已完成 运行 其功能)才能导航到深层 linking 位置?我可以想到一些看似 hack-y 的方法来做到这一点,但是否有一种常用的既定模式?
好的,所以我不确定这是否是处理此问题的最佳方法,但我找到了一种让我的通知正常工作的方法。
(1) 我创建了一个名为 registerAppLoaded
的动作和一个状态变量 appLoaded
,一旦我的 AppLoading
组件完成其 startAsync
函数,我就会发送该变量。
(2) 当收到通知时,我首先检查 appLoaded
是否为真。如果是这样,我将导航到与通知一起发送的目的地。如果没有,我将通知放入商店并继续启动应用程序。
(3) 在AppLoading
onFinish
函数中,我查看是否有通知。如果是这样,并且它被标记为 new
,我会抓住它并使用参数进行导航。然后我发送一个设置 navigation.new = false
似乎完全按照我需要的方式工作!
如果其他人正在处理这个问题,这是我的代码:
App.tsx:
export default class App extends React.Component {
componentDidMount() {
Notifications.addListener((notification) => {
if (notification.origin === "received") {
return;
} else {
const appLoaded = store.getState().general.appLoaded
if (appLoaded) {
NavigationService.navigate(notification.data.navigate, {id:notification.data.id , shouldRefresh: true})
} else {
// save notification as new
store.dispatch(addNotification(notification, true));
}
};
})
}
render() {
return (
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<View style={styles.container}>
{Platform.OS === "ios" && <StatusBar barStyle="default" />}
<ErrorBoundary backup={<AppError />}>
<AppNavigator />
</ErrorBoundary>
</View>
</PersistGate>
</Provider>
);
}
}
AppLoading.tsx:
class AppLoadingScreen extends React.Component {
_loadResourcesAsync = async() => {
await this.props.fetchUserOnboarding(this.props.userId);
if (this.props.userDevice && this.props.userDevice.id) {
this.props.registerUserDevice(this.props.userId, this.props.userDevice.id)
}
// register that the app has finished loading in the store; this will be used to determine if a notification's deep
// link should be immediatedly navigated to or if the navigation even shuold be deferred until after the app
// finishes loading
await this.props.registerAppLoaded()
};
_handleFinishLoading = async () => {
// if a notification triggers the event listener but the app is not yet fully loaded, the deep link will be
// navigated to here instead of directly from the listener
const notification = this.props.userNotifications && this.props.userNotifications[0]
if (notification && notification.new && notification.origin != 'recieved') {
this.props.addNotification(notification, false) // set notification.new = false
this.props.navigation.navigate(notification.data.navigate, {id: notification.data.id, shouldRefresh: true})
} else if (this.props.showGoalsPrompt) {
this.props.navigation.navigate("Goal");
} else {
this.props.navigation.navigate("HomeFeed");
}
};
render() {
return (
<AppLoading
startAsync={this._loadResourcesAsync}
onFinish={this._handleFinishLoading}
/>
);
}
}
actions.tsx:
export const registerAppLoaded = () => {
return dispatch => {
dispatch({
type: types.REGISTER_APP_LOADED,
payload: true
});
};
}
export const addNotification = (notification, isNew=false) => {
return dispatch => {
notification.new = isNew // indicate whether this is a new notification or if it has been seen
dispatch({
type:types.ADD_USER_NOTIFICATION,
payload: notification,
})
};
}