React-навигация: глубокая связь с аутентификацией - PullRequest
0 голосов
/ 24 января 2019

Я создаю мобильное приложение с реагирующим и библиотекой реагирования для управления навигацией в моем приложении.Прямо сейчас мое приложение выглядит примерно так:

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

Я интегрировал Deep Linking с вышеприведенными шаблонами для экранов Home, Profile и Notifications, и он работает, как и ожидалось.Проблема, с которой я сталкиваюсь, заключается в том, как управлять аутентификацией моего пользователя при использовании глубокой ссылки.Прямо сейчас, когда я открываю глубокую ссылку (например, myapp://profile), приложение выводит меня на экран независимо от того, аутентифицирована ли я.Я бы хотел, чтобы в AsyncStorage до этого было проверено, есть ли userToken, а если нет или больше не действует, просто перенаправьте на экран Auth.

Я настроил поток аутентификации почти точно так же, как описано здесь .Поэтому, когда мое приложение запускает экран Splash, он проверяет наличие в телефоне пользователя действительного токена и отправляет его либо на экран Auth, либо на экран Home.

Единственное решение, которое я нашелс сейчас - это направить каждую глубокую ссылку на Splash, аутентифицировать моего пользователя, а затем проанализировать ссылку, чтобы перейти к хорошему экрану.Так, например, когда пользователь открывает myapp://profile, я открываю приложение на Splash, проверяю токен, затем анализирую URL (/profile) и, наконец, перенаправляю на Auth или Profile.

Это хороший способ сделать это, или реагирующая навигация предоставляет лучший способ сделать это?Страница Deep linking на их веб-сайте немного освещена.

Спасибо за помощь!

Ответы [ 2 ]

0 голосов
/ 16 апреля 2019

В итоге я использовал пользовательский URI для перехвата запуска Deeplink, а затем передал эти параметры намеченному маршруту. Мой экран загрузки обрабатывает проверку подлинности.

const previousGetActionForPathAndParams = AppContainer.router.getActionForPathAndParams

Object.assign(AppContainer.router, {
  getActionForPathAndParams (path, params) {
    if (path === 'auth' && params.routeName && params.userId ) {
      // returns a profile navigate action for myApp://auth?routeName=chat&userId=1234
      return NavigationActions.navigate({
        routeName: 'Loading',
          params: { ...params, path },
      })
    }
    return previousGetActionForPathAndParams(path, params)
  },
})

https://reactnavigation.org/docs/en/routers.html#handling-custom-uris

Затем в моем маршруте загрузки я анализирую параметры, как обычно, но затем направляю их в нужное место, пропуская их еще раз.

const userId = this.props.navigation.getParam('userId')

https://reactnavigation.org/docs/en/params.html

0 голосов
/ 08 марта 2019

Мои настройки похожи на ваши.Я следовал за потоками аутентификации · Реагируйте с навигацией и SplashScreen - Expo Documentation , чтобы настроить мой поток аутентификации, поэтому я был немного разочарован тем, что получить глубокие ссылки через него было сложнотакже.Я смог заставить это работать, настроив навигатор главного переключателя, подход похож на то, что вы заявили, было решение, которое у вас есть на данный момент.Я просто хотел поделиться своим решением для этого, так что есть конкретный пример того, как можно начать работать.Мой навигатор главного переключателя настроен так (также я использую TypeScript, поэтому игнорируйте определения типов, если они незнакомы):

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:

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, поэтому шрифты не были загружены.

Подход вышеобъявляет переменную action, которая, если она не установлена, ничего не будет делать.Если параметр запроса routeName не undefined, я устанавливаю переменную action.Это делается так, как только маршрутизатор коммутатора решает, какой путь выбрать на основе аутентификации (Onboarding или App), этот маршрут получает дочернее действие и переходит к routeName после выхода из потока загрузки auth / splash.

Вот пример ссылки, которую я создал, которая отлично работает с этой системой: exp://192.168.1.7:19000/--/auth-link?routeName=ForgotPasswordChange&cacheKey=a9b3ra50-5fc2-4er7-b4e7-0d6c0925c536

Надеемся, что авторы библиотеки сделают эту функцию изначально поддерживаемой, поэтому взломы не нужны.Мне бы тоже хотелось посмотреть, что вы придумали!

...