React Native × React Navigation v5 で Deep linking

# はじめに
またしても React Navigation v5 の記事です。
今回は Deep linking を実装していきます。

# 下準備
iOS 用の設定をします。

`URL Types`の設定をおこないます。

![Screen Shot 2020-03-19 at 19.39.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43625/685c69fd-42db-433e-da17-b3d3c67d2c42.png)


次に、 `AppDelegate.m`を修正します。

![Screen Shot 2020-03-19 at 19.48.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43625/ced74d66-10cf-b4db-e869-c9926f44368f.png)

コードはこちらです。

```swift
#import "AppDelegate.h" // 元からある
#import <React/RCTLinkingManager.h>

...

- (BOOL)application:(UIApplication *)application
   openURL:(NSURL *)url
   options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
{
  return [RCTLinkingManager application:application openURL:url options:options];
}

- (BOOL)application:(UIApplication *)application continueUserActivity:(nonnull NSUserActivity *)userActivity
 restorationHandler:(nonnull void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler
{
 return [RCTLinkingManager application:application
                  continueUserActivity:userActivity
                    restorationHandler:restorationHandler];
}
```

これだけで、 Safari などで`<URL Schemas>://xxxx`のように入力すれば、アプリを開くことができます。
![Simulator Screen Shot - iPhone 11 Pro Max - 2020-03-19 at 22.44.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43625/cffcf989-3b5c-1322-6f94-8add7ed2918d.png)

これでアプリへのアクセスはできるようになりました。
各ページへの遷移は React Navigation と組み合わせて使うと便利です。
以下ではその方法を実装していきます。

# React Navigation v5 で Deep linking
[公式ドキュメント](https://reactnavigation.org/docs/deep-linking/)を参考に、`useLinking`を使用します。

```tsx
const App: React.FunctionComponent = () => {
  const ref = useRef();
  const { getInitialState } = useLinking(ref, {
    prefixes: ['srn5://'],
    config: {
      Details: 'details',
    },
  });
  const [isReady, setIsReady] = useState(false);
  const [initialState, setInitialState] = useState();

  useEffect(() => {
    Promise.race([
      getInitialState(),
      new Promise((resolve) => setTimeout(resolve, 150)),
    ])
      .catch((e) => {
        console.error(e);
      })
      .then((state) => {
        if (state !== undefined) {
          setInitialState(state);
        }

        setIsReady(true);
      });
  }, [getInitialState]);

  if (!isReady) {
    return null;
  }

  return (
    <AuthProvider>
      <NavigationContainer initialState={initialState} ref={ref}>
        <HomeNavigator />
      </NavigationContainer>
    </AuthProvider>
  );
}
```

`ref`を定義して、`NavigationContainer`と`useLinking`に渡しています。
`useLinking`の`config`でパスと画面を紐づけています。

`HomeNavigator`は下記の形で定義しています。

```tsx
import { createStackNavigator } from '@react-navigation/stack';
import React from 'react';

const Stack = createStackNavigator();
const HomeNavigator = () => (
  <Stack.Navigator>
    <Stack.Screen name="Home" component={Home} />
    <Stack.Screen name="Details" component={Details} />
  </Stack.Navigator>
)
```

通常のアクセスだと`Home`が表示されますが、`srn5://details`にアクセスすると`Details`が直接開きます。

# おわりに
今回は、 Deep linking の実装について紹介しました。

実際に利用する場合、ユニバーサルリンク（`https://~~~`）という形で利用するのが現実的かと思いますが、まずはこの方法で簡易的なアプリへのリンクを設定することができます。

# 参考
https://reactnative.dev/docs/linking#handling-deep-links
https://reactnavigation.org/docs/deep-linking/