延迟通知深度链接,直到 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,
    })
  };
}