# アプリで開くURLのまとめ
# URLでアプリを開くってどういうことなの
「入力されたURLを画面遷移の情報に変換し、その結果に従って画面遷移する」という処理が組み込まれているアプリに対して、URLを入力することを指します。
URLの受け取り手はOSによって異なります。iOSであればAppDelegateだし、AndroidならActivityです。URLを入力する時、これらの受け取り手が存在しなければ、それを確保するためにOSはアプリの立ち上げを行います。その後、確保した受け取り手に対してURLを入力します。
URLを入力されたAppDelegate(Activity)は、「入力されたURLを画面遷移の情報に変換し、その結果に従って画面遷移する」というURLハンドリング処理が組み込まれていれば、それを実行します。組み込まれていない場合は何もしません。つまり、アプリの起動のみを目的とするならばURLハンドリング処理は不要です。なぜなら、AppDelegate(Activity)に対してURL(内容は何でも良い)を渡した時点で、アプリが起動は達成されているからです。
# アプリ用のURLってなんでこんなに種類あるの
アプリにURLを入力する経路には3種類あって、その経路によってURLの形も異なることが多いです。これは、経路ごとに期待される動作が異なるからです。
1. アプリからアプリへ
2. OSからアプリへ
3. ブラウザからアプリへ

期待される動作について、詳しく説明します。
## 1. アプリからアプリを開く時に期待される動作
このケースで期待される動作は、当たり前ですが
```
URLに従って画面遷移できる
```
ことです。
## 2. OSからアプリを開く時に期待される動作
このケースでは、1番の経路で期待される`URLに従って画面に遷移できる`動作に加えて、
```
アプリがインストールされていなければ、AppStoreアプリを起動して、該当アプリのインストールページに遷移できる
```
という動作が期待されます。なぜなら、1番の経路とは違いURLの入力元がアプリではないので、アプリがインストール済みである保証がないからです。アプリがインストールされていない場合、AppDelegate(Activity)を確保するためのアプリ起動が行いないので、URLの受け渡しは失敗します。
なお、OSがAndroidの場合はPlayStoreアプリです。URLの入力元がOSなので、開くストアアプリは一意に決まります。
2番の経路で期待される動作はもう1つあって、それは
```
アプリのインストールに成功したら、そのインストール後の初回起動時までURLの受け渡しを保留にできる
```
ことです。
## 3. ブラウザからアプリを開く時に期待される動作
このケースでも、2番の経路と同じ動作が期待されます。この経路で新しく期待される動作は、
```
アプリがインストールされていない時、そのアプリのOSに従って、
PlayStoreを起動するかAppStoreを起動するか決めることができる
```
です。これは、大抵のブラウザが複数のOS上で動作できるためです。
ブラウザからアプリを開く時、そのブラウザがiOSもしくはAndroidで動作している保証はありません。よって、ブラウザからアプリを開くときには次の動作も期待されます。
```
iOSでもAndroidでもないプラットフォームで開かれたときは、
アプリではなくWebページに遷移できる
```
アプリを開けなかったときのfallbackというイメージがわかりやすいかもしれません。
# アプリ用のURLの種類について具体的に詳しく
上のセクションでは、
1. アプリからアプリへ
2. OSからアプリへ
3. ブラウザからアプリへ
という3つの経路でアプリが開かれることを説明しました。これらの経路で期待される動作は、それぞれ
1. CustomUrlScheme
2. UniversalLInk(iOS)やAppLink(Android)
3. FirebaseDynamicLink
という方法を用いて達成されることが多いです。これらについて説明します。
## 1. CustomUrlScheme
1番の経路では、単に
```
URLに従って画面遷移できる
```
という動作が期待されます。これを実現するときによく使われるのがCustomUrlSchemeです。
ところで、初めの方で説明したとおり、URLのハンドリング処理の具体的な実装はデベロッパに委ねられています。従って、CustomUrlSchemeの具体的な仕様もデベロッパに一任されます。
CustomUrlSchemeという名前がついているものの、それは単に
1. URLの仕様を決める
2. URLのハンドリング処理を実装する
3. OSから受け取るURL、受け取らないURLを決める
をという工程でデベロッパが作成する任意のURIです。
一般には、URIのスキームをアプリ独自のものにし、hostとpathに画面を特定する情報を埋め込むことが多いです。
例
```
instagram://camera
```
```
twitter://post?message=hello%20world
```
もはやURIですらなくても良い気がしてきますが、3番の「OSから受け取るURL、受け取らないURLを決める」という工程において、
- iOS: 受け取るURLのSchemeをInfo.plistに書き込む
- Andoroid: 受け取るURLのScheme, Host, pathの組み合わせをAndroidManifestに書き込む
という操作が求められるので、URIの形式は保つ必要がありそうです。
CostomUrlSchemeの動作を図にすると以下のようになります。これだけじゃなんのこっちゃって感じですね(次の説明のために一応載せました)
[](https://mermaid-js.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoiZ3JhcGggVERcblxuc3ViZ3JhcGgg44Ki44OX44OqXG5hcHBb44Ki44OX44OqXVxuZW5kXG5cbmFwcC0tPnxDdXN0b21VcmxTY2hlbWV8YXBwXG4iLCJtZXJtYWlkIjp7InRoZW1lIjoiZGVmYXVsdCJ9LCJ1cGRhdGVFZGl0b3IiOmZhbHNlfQ)
## 2. UniversalLinkやAppLink
2番の経路で求められる
```
アプリがインストールされていなければ、AppStore(PayStore)アプリを起動して、
該当アプリのインストールページに遷移できる
```
動作を実現するための方法です。
予め用意しておいたCustomUrlSchemeをパラメータとして持つURLを発行します。このURLが開かれた時、アプリがインストール済みであればそのパラメータがAppDelegate(Activity)に渡されます。インストールされていなければ、AppStore(PlayStore)に遷移します。
(あまり使ったことがないので詳細な説明は割愛)
UniversalLinkの動作を図にすると以下のようになります。UniversalLinkを開くと、OSがアプリ、もしくは
[](https://mermaid-js.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoiZ3JhcGggVERcblxuc3ViZ3JhcGggT1Ncbm9zW09TXVxuc3ViZ3JhcGgg44Ki44OX44OqXG5hcHBb44Ki44OX44OqXVxuZW5kXG5zdG9yZVvjgrnjg4jjgqLjgqLjg5fjg6rjga48YnI-44Kk44Oz44K544OI44O844Or44Oa44O844K4XVxuZW5kXG5cbm9zLS0-fEN1c3RvbVVybFNjaGVtZXxhcHBcbm9zLS0-c3RvcmUiLCJtZXJtYWlkIjp7InRoZW1lIjoiZGVmYXVsdCJ9LCJ1cGRhdGVFZGl0b3IiOmZhbHNlfQ)
UniversalLinkの問題点は、iOSでしか開けないことです。AppLinkも同様です。
両方のURLを掲載すれば解決する問題ではありますが、それを1つにまとめたいと思った時、次に説明するFirebaseDynamicLinkが役に立ちます。
## 3. FirebaseDynamicLink
3番の経路で求められる
```
アプリがインストールされていない時、そのアプリのOSに従って、
PlayStoreを起動するかAppStoreを起動するか決めることができる
```
```
iOSでもAndroidでもないプラットフォームで開かれたときは、
アプリではなくWebページに遷移できる
```
を実現するための方法です。
FirebaseDynamicLinkを使うときは、**最低限ブラウザで開ける、かつ、希望するOS上のアプリでハンドリング可能なhttps形式のURL**が必要です。
FirebaseDynamicLinkを使用するデベロッパは、まず、https形式のWebページを1つ用意します。次に、「そのWebページが仮にアプリで開かれるとしたら」を想定し、そのWebページのURLのハンドリング処理をアプリに組み込みます。そうると、FirebaseDynamicLinkは「その環境に適した遷移先」を1つ決めてくれます。
ここで言う環境とは、
- アプリをインストール済みな状態のAndroid
- アプリをインストール済みな状態のiOS
- アプリをインストールしていない状態のAndroid
- アプリをインストールしていない状態のiOS
- Window
- Mac
等が挙げられます。「任意の環境で開ける1つのURL」をイメージするとわかりやすいかもしれません。
FirebaseDynamicLinkの動作を図にすると以下のようになります。一気に複雑になりましたね...
便宜上、URLと書いていますが、これは**最低限ブラウザで開ける、かつ、希望するOS上のアプリでハンドリング可能なhttps形式のURL**を指します。MacOS上ではブラウザで開けなければいけないので、このURLはCustomUrlSchemeでは不十分です。
[](https://mermaid-js.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoiZ3JhcGggVERcblxuc3ViZ3JhcGgg44OW44Op44Km44K2XG5cbmZkbFtGaXJlYmFzZUR5bmFtaWNMaW5rXVxuXG5zdWJncmFwaCBBbmRyb2lkXG5hbmRvc1tPU11cbnN1YmdyYXBoIEFuZHJvaWTjgqLjg5fjg6pcbmFuZGFwcFvjgqLjg5fjg6pdXG5lbmRcbmFuZHN0b3JlW1BsYXlTdG9yZeOBrjxicj7jgqTjg7Pjgrnjg4jjg7zjg6vjg5rjg7zjgrhdXG5lbmRcblxuYW5kb3MtLT58VVJMfGFuZGFwcFxuYW5kb3MtLT5hbmRzdG9yZVxuYW5kc3RvcmUtLT58VVJMfGFuZGFwcFxuXG5zdWJncmFwaCBpT1Ncbmlvc29zW09TXVxuc3ViZ3JhcGggaU9T44Ki44OX44OqXG5pb3NhcHBb44Ki44OX44OqXVxuZW5kXG5pb3NzdG9yZVtBcHBTdG9yZeOBrjxicj7jgqTjg7Pjgrnjg4jjg7zjg6vjg5rjg7zjgrhdXG5lbmRcblxuc3ViZ3JhcGggTWFjXG5cbm1hY29zW09TXVxuXG5lbmRcblxuaW9zb3MtLT58VVJMfGlvc2FwcFxuaW9zb3MtLT5pb3NzdG9yZVxuaW9zc3RvcmUtLT58VVJMfGlvc2FwcFxuXG5mZGwgLS0-fFVSTHxpb3Nvc1xuZmRsIC0tPnxVUkx8YW5kb3NcbmZkbCAtLT58VVJMfG1hY29zXG5lbmQiLCJtZXJtYWlkIjp7InRoZW1lIjoiZGVmYXVsdCJ9LCJ1cGRhdGVFZGl0b3IiOmZhbHNlfQ)
## 結局DeepLinkってなんなの?
結局の所、アプリを開くというコンテキストの上では、「アプリを開けるURL」の総称だと思ってます。
具体的な技術の名前ではなく総称です。実際にDeepLinkを使用する場面では、UniversalLinkだったり、FirebaseDynamicLinkだったり、の技術が用いられます。
# 実際にどんなふうに使われるか教えてよ
次の3つのURLについて、想定される使われ方を説明します。`niwatly`の部分はデベロッパが任意に変更できる部分です。
- CustomUrlScheme
- FirebaseDynamicLink
- FirebaseDynamicLinkに登録するWebページ用URL
## CustomUrlScheme
次のようなユースケースが想定されます。
- アプリ内のテキストUIにリンクを仕込んで画面遷移させたい時
- 特定の画面に遷移できるPush通知を発行した時
- 特定の画面に遷移できるボタンを持つFirebaseInAppMessagingを発行したい時
いずれのユースケースも、アプリがインストールされていることが保証されています。これが保証されないユースケースでは、CustomUrlSchemeを使った遷移は行なえません。
ところで、アプリを開発していると、開発環境のアプリと本番環境のアプリを別アプリ化したい事がよくあります。目的は1つで、同じ端末上に開発環境のアプリと本番環境のアプリを同居させたいからです。
このとき、開発環境のアプリと本番環境のアプリの両方で同じCustomUrlSchemeを登録していた場合、CustomUrlSchemeの入力先となるアプリが一意に決まらない問題が発生します(登録については[こちら](https://hackmd.io/Kvd9yPb2TVmXIzYLP3iEfQ#1-CustomUrlScheme)を参照)。
CustomUrlSchemeの入力先となるアプリが一意に決まらない場合、iOSでは、CustomUrlSchemeを開いた後の挙動が不安定になってしまいます。これを避けるため、登録するCustomUrlSchemeのSchemeは、開発環境と本番環境で分けることが望ましいです。なお、Androidでは、CustomUrlSchemeの入力先が一意に決まらなかったときにどのアプリを開くか選択することができるので、この問題は発生しません。
## FirebaseDyancmiLink
次のユースケースで使用することが想定されます。
- アプリ外の任意の場所から特定の画面に遷移させたい時
前述の通り、FirebaseDynamicLnkは環境の差分を吸収できる1つのURLです。これを使うことで、
- PCで開いてもバグらないようにする
- アプリ持ってない人が開いたらインストールページに遷移させる
- ユーザのOS(iOS, Android)に応じて遷移先を分ける
という動作をまとめて達成することができます。