React-navigation:与身份验证的深度链接 [英] React-navigation: Deep linking with authentication

查看:62
本文介绍了React-navigation:与身份验证的深度链接的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在构建一个带有 react-native 和 react-navigation 库的移动应用程序,用于管理我的应用程序中的导航.现在,我的应用看起来像这样:

I am building a mobile app with react-native and the react-navigation library for managing the navigation in my app. Right now, my app looks something like that:

App [SwitchNavigator]
    Splash [Screen]
    Auth [Screen]
    MainApp [StackNavigator]
        Home [Screen]            (/home)
        Profile [Screen]         (/profile)
        Notifications [Screen]   (/notifications)

我已将深度链接与上述屏幕HomeProfileNotifications 的模式集成,并且它按预期工作.我面临的问题是如何在使用深层链接时管理我的用户身份验证.现在,每当我打开一个深层链接(例如 myapp://profile)时,无论我是否通过身份验证,该应用程序都会将我带到屏幕上.我希望它做的是在 AsyncStorage 之前检查是否有 userToken,如果没有或它不再有效,则只需重定向到 Auth 屏幕.

I have integrated Deep Linking with the patterns above for the screens Home, Profile and Notifications, and it works as expected. The issue I am facing is how to manage my user's authentication when using a deep link. Right now whenever I open a deep link (myapp://profile for instance) the app takes me on the screen whether or not I am authenticated. What I would want it to do is to check before in AsyncStorage if there is a userToken and if there isn't or it is not valid anymore then just redirect on the Auth screen.

我以与此处描述的几乎完全相同的方式设置了身份验证流程.因此,当我的应用程序启动时,Splash 屏幕会检查用户的手机是否存在有效令牌,并在 Auth 屏幕或 Home 上向他发送屏幕.

I set up the authentication flow in almost exactly the same way as described here. So when my application starts the Splash screen checks in the user's phone if there is a valid token and sends him either on the Auth screen or Home screen.

我现在想出的唯一解决方案是将每个深层链接指向 Splash,验证我的用户,然后解析链接以导航到正确的屏幕.例如,当用户打开 myapp://profile 时,我在 Splash 上打开应用程序,验证令牌,然后解析 url (/profilecode>),最后重定向到 AuthProfile.

The only solution I have come up with for now is to direct every deep link to Splash, authentify my user, and then parse the link to navigate to the good screen. So for example when a user opens myapp://profile, I open the app on Splash, validate the token, then parse the url (/profile), and finally redirect either to Auth or Profile.

这是这样做的好方法,还是反应导航提供了更好的方法来做到这一点?他们网站上的深度链接页面有点亮.

Is that the good way to do so, or does react-navigation provide a better way to do this ? The Deep linking page on their website is a little light.

感谢您的帮助!

推荐答案

我的设置与您的类似.我遵循了身份验证流程·反应导航SplashScreen - Expo 文档 来设置我的 Auth 流程,所以我有点失望,因为这是一个挑战获得深层链接也可以通过它.我能够通过自定义我的主开关导航器来实现这一点,该方法类似于您所说的您现在拥有的解决方案.我只是想分享我的解决方案,所以有一个具体的例子来说明如何开始工作.我的主开关导航器是这样设置的(我也在使用 TypeScript,所以如果不熟悉可以忽略类型定义):

My setup is similar to yours. I followed Authentication flows · React Navigation and SplashScreen - Expo Documentation to set up my Auth flow, so I was a little disappointed that it was a challenge to get deep links to flow through it as well. I was able to get this working by customizing my main switch navigator, the approach is similar to what you stated was the solution you have for now. I just wanted to share my solution for this so there’s a concrete example of how it’s possible to get working. I have my main switch navigator set up like this (also I’m using TypeScript so ignore the type definitions if they are unfamiliar):

const MainNavigation = createSwitchNavigator(
  {
    SplashLoading,
    Onboarding: OnboardingStackNavigator,
    App: AppNavigator,
  },
  {
    initialRouteName: 'SplashLoading',
  }
);

const previousGetActionForPathAndParams =
  MainNavigation.router.getActionForPathAndParams;

Object.assign(MainNavigation.router, {
  getActionForPathAndParams(path: string, params: any) {
    const isAuthLink = path.startsWith('auth-link');

    if (isAuthLink) {
      return NavigationActions.navigate({
        routeName: 'SplashLoading',
        params: { ...params, path },
      });
    }

    return previousGetActionForPathAndParams(path, params);
  },
});

export const AppNavigation = createAppContainer(MainNavigation);

您想要通过身份验证流路由的任何深层链接都需要以 auth-link 开头,或者您选择添加的任何内容.下面是 SplashLoading 的样子:

Any deep link you want to route through your auth flow will need to start with auth-link, or whatever you choose to prepend it with. Here is what SplashLoading looks like:

export const SplashLoading = (props: NavigationScreenProps) => {
  const [isSplashReady, setIsSplashReady] = useState(false);

  const _cacheFonts: CacheFontsFn = fonts =>
    fonts.map(font => Font.loadAsync(font as any));

  const _cacheSplashAssets = () => {
    const splashIcon = require(splashIconPath);
    return Asset.fromModule(splashIcon).downloadAsync();
  };

  const _cacheAppAssets = async () => {
    SplashScreen.hide();
    const fontAssetPromises = _cacheFonts(fontMap);
    return Promise.all([...fontAssetPromises]);
  };

  const _initializeApp = async () => {
    // Cache assets
    await _cacheAppAssets();

    // Check if user is logged in
    const sessionId = await SecureStore.getItemAsync(CCSID_KEY);

      // Get deep linking params
    const params = props.navigation.state.params;
    let action: any;

    if (params && params.routeName) {
      const { routeName, ...routeParams } = params;
      action = NavigationActions.navigate({ routeName, params: routeParams });
    }

    // If not logged in, navigate to Auth flow
    if (!sessionId) {
      return props.navigation.dispatch(
        NavigationActions.navigate({
          routeName: 'Onboarding',
          action,
        })
      );
    }

    // Otherwise, navigate to App flow
    return props.navigation.navigate(
      NavigationActions.navigate({
        routeName: 'App',
        action,
      })
    );
  };

  if (!isSplashReady) {
    return (
      <AppLoading
        startAsync={_cacheSplashAssets}
        onFinish={() => setIsSplashReady(true)}
        onError={console.warn}
        autoHideSplash={false}
      />
    );
  }

  return (
    <View style={{ flex: 1 }}>
      <Image source={require(splashIconPath)} onLoad={_initializeApp} />
    </View>
  );
};

我使用 routeName 查询参数创建深层链接,这是执行身份验证检查后要导航到的屏幕的名称(您显然可以添加任何其他需要的查询参数).由于我的 SplashLoading 屏幕处理加载所有字体/资产以及身份验证检查,我需要每个深层链接来路由它.我面临的问题是,我会手动退出多任务处理应用程序,点击深层链接网址,然后应用程序崩溃,因为深层链接绕过了 SplashLoading,因此未加载字体.

I create the deep link with a routeName query param, which is the name of the screen to navigate to after the auth check has been performed (you can obviously add whatever other query params you need). Since my SplashLoading screen handles loading all fonts/assets as well as auth checking, I need every deep link to route through it. I was facing the issue where I would manually quit the app from multitasking, tap a deep link url, and have the app crash because the deep link bypassed SplashLoading so fonts weren’t loaded.

上面的方法声明了一个 action 变量,如果没有设置它什么也不做.如果 routeName 查询参数不是 undefined,我设置 action 变量.这使得一旦 Switch 路由器根据身份验证(OnboardingApp)决定采用哪条路径,该路由就会获取子操作并导航到 routeName 退出认证/启动加载流程后.

The approach above declares an action variable, which if not set will do nothing. If the routeName query param is not undefined, I set the action variable. This makes it so once the Switch router decides which path to take based on auth (Onboarding or App), that route gets the child action and navigates to the routeName after exiting the auth/splash loading flow.

这是我创建的一个示例链接,它在这个系统上运行良好:exp://192.168.1.7:19000/--/auth-link?routeName=ForgotPasswordChange&cacheKey=a9b3ra50-5fc2-4er7-b4e7-0d6c0925c536

Here’s an example link I created that is working fine with this system: exp://192.168.1.7:19000/--/auth-link?routeName=ForgotPasswordChange&cacheKey=a9b3ra50-5fc2-4er7-b4e7-0d6c0925c536

希望库作者在未来将其作为本机支持的功能,这样就不需要进行黑客攻击.我也很想看看你想出了什么!

Hopefully the library authors will make this a natively supported feature in the future so the hacks aren’t necessary. I'd love to see what you came up with as well!

这篇关于React-navigation:与身份验证的深度链接的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆