こんにちは、クックパッド事業本部 買物サービス開発部の佐藤(@n_atmark)です。 普段はクックパッドiOS/Androidアプリ向けの買い物機能の開発に従事しています。
さて、タイトルにある通り、今回は Android App Links の話を書こうと思います。
付録: ディープリンク用語まとめ
この記事ではDeepLinkに関連する用語がいくつか登場するため、説明のためにできるだけわかりやすく図示してみました。
Android App Links とは
アプリとウェブサイトURLの両方の所有権を証明することによって自動的にURLインテントをアプリにルーティングする仕組みで、特定のウェブページに関連づけられたアプリがインストールされている場合に、ウェブサイト URL から直接 Android アプリ内の対応コンテンツを開けるようになります。アプリがインストールされていない場合はブラウザ上で表示を継続します。
iOSでは同様の仕組みとして Universal Links があります。
Android App Linksを検証する
アプリとウェブサイトURLの両方の所有権を証明するために以下の手順が必要です。
- アプリの自動リンク検証を有効にするために、AndroidManifest.xml でintent-filterに
autoVerify=true
を設定する (これによって intent-filter で使用されているURLドメインに属しているか検証されるようになる) - Webサイトとintent-filterの関係を宣言するために、Digital Asset Links JSONファイルを
https://domain.name/.well-known/assetlinks.json
のパスでホストする
詳しくはこちら Android アプリリンクを検証する | Android Developers
Android App Linksの複数ホスト対応と、Android App Links対応Webサイトに対して複数アプリを紐づけたくなった動機
現在私はクックパッドアプリの「買い物機能」の開発に従事しています。これは、生鮮食品ECサービス「クックパッドマート」のインフラを用いたものです。
一方で、クックパッドマートの利用に特化した専用アプリ(以下: マートアプリ)もリリースされています。
また、レシピサービスクックパッドおよび、生鮮食品ECサービスクックパッドマートそれぞれ cookpad.com
および cookpad-mart.com
というホスト名でWebページを提供しています。
クックパッドアプリやマートアプリでは、アプリ外からの流入導線として、Android App LinksやFirebase Dynamic Linksを用いており、下のような経路でアプリを起動することができるようになっています。 *1
ここで、クックパッドアプリの買い物機能のことを考えてみます。
Firebase Dynamic LinksやAndroid App Linksを設定する場合、実際にコンテンツを表示しているWebサイトのURLを利用することが多いはずです。
例えば、クックパッド買い物機能で販売しているクックパッドマートの商品などのコンテンツへの流入導線を設けたい場合、Webの商品ページは https://cookpad-mart.com/products/:id で提供しているため、バックエンドの構成を変えずにクックパッド買い物機能への流入導線を作ろうと思うとこのようになります。*2
クックパッドアプリから見た時に「複数のホスト( https://cookpad.com および https://cookpad-mart.com ) に対するAndroid App Links対応」と、「Android App Links対応Webサイト (https://cookpad-mart.com) に対して複数アプリ (クックパッドアプリ、マートアプリ)を関連付ける」場合の挙動や実現方法について調べてみました。
複数のホストに対するAndroid App Links対応
例えば https://cookpad.com
および https://cookpad-mart.com
に対応する場合、その両方を intent-filter に追加する必要があります。
詳しくは複数のホスト用のアプリリンク機能をサポートする | Android アプリリンクを検証するに記載があり、基本的にこのドキュメントに沿って準備をすれば良いのですが、注意点があり
システムは、マニフェスト内のすべてのホストで条件に合致する Digital Asset Links ファイルが見つかった場合に限り、アプリを指定 URL パターンのデフォルト ハンドラとして確立します。 たとえば、次のインテント フィルタを持つアプリの場合、https://www.example.com/.well-known/assetlinks.json と https://www.example.net/.well-known/assetlinks.json の両方で assetlinks.json ファイルが検出されなかった場合、検証は失敗になります。
という記述が日本語ドキュメントにあります。 例えばディープリンクに対応する場合も対応したディープリンクURLをintent-filterに記述する必要があるのですが、この表記を見るとintent-filterに追加されている全てのホストでAndroid App Links対応がされていない場合、Android App Linksの検証に失敗してしまうような記述があります。
上記のドキュメントの英語版であるSupporting app linking for multiple hosts | Verify Android App Linksを見ると
For example, an app with the following intent filters would pass verification only for https://www.example.com if an assetlinks.json file were found at https://www.example.com/.well-known/assetlinks.json but not https://www.example.net/.well-known/assetlinks.json
Digital Asset Linksが見つかったホストに関してのみ検証に成功するような文脈になっていて、日本語ドキュメントと文脈がやや違った記述をされています。
実際に試してみたところAndroid App Links対応されていないホストを追加した状態で、Android App Links対応されている https://cookpad.com の流入導線は正常に動作しており、英語版ドキュメントの記述が正しそうでした。
Android App Links対応Webサイトに対して複数のアプリに関連付ける
1つのウェブサイト ( https://cookpad-mart.com
) に対してマートアプリとクックパッドアプリ両方を関連づけるためにはDigital Asset Linksに二つ分のアプリ情報を記載する必要があります。こちらもドキュメントが用意されており、ドキュメントに沿って準備をしていきます。
[ { "relation": ["delegate_permission/common.handle_all_urls"], "target": { "namespace": "android_app", "package_name": "com.cookpad.android.martec", "sha256_cert_fingerprints": [ "FF:AE:BE:09:C7:A8:E3:D5:43:BD:89:21:2B:45:6D:28:DA:24:26:1A:24:88:70:DF:E1:0D:2D:AF:44:5E:BD:15" ] } }, { "relation": ["delegate_permission/common.handle_all_urls"], "target": { "namespace": "android_app", "package_name": "com.cookpad.android.activities", "sha256_cert_fingerprints": [ "14:D6:67:33:06:3D:79:53:31:35:3B:08:0C:C5:03:60:F6:96:8F:58:28:45:65:C5:73:6D:5F:89:C7:6D:2F:B8" ] } } ]
https://cookpad-mart.com/.well-known/assetlinks.json
に上記のようなDigital Asset Linksを配置しました。ここでは専用アプリであるマートアプリを先頭にしています。
Android App Links対応Webサイトに対して複数のアプリに関連付ける知見
ここで一つ気になる点があります。 https://cookpad-mart.com に対してクックパッドアプリとマートアプリ二つを紐づけた状態で、両方のアプリがインストールされている場合一体どのような挙動になるのでしょうか。 私たちとしては、あくまでもクックパッドマートのWebサイトなので、マートアプリがインストールされている場合、常にマートアプリが優先度高く開かれる状態になってるのが望ましいと考えており、理想の挙動になっているかどうか気になりました。
挙動の確認のために、クックパッドアプリ/マートアプリがそれぞれインストールされている状態でマートのWebページを開いてみました。
また、Android 12以降ではAndroid App Linksのドメイン検証に関しての変更が入っているため、Android 12未満とAndroid 12以降でそれぞれ試してみました。
詳しくは ウェブ インテントの解決 | Android 12
Android 12未満 | Android 12以降 | |
---|---|---|
マートアプリのみインストール | マートアプリが開く | マートアプリが開く |
クックパッドアプリのみインストール | クックパッドアプリが開く | 開かない |
クックパッドアプリ→マートアプリの順でインストール | マートアプリが開く | マートアプリが開く |
マートアプリ→クックパッドアプリの順でインストール | クックパッドアプリが開く | マートアプリが開く |
ここまでの結果より
- Android 12未満だと、一番直近インストールされたアプリがデフォルトで開く
- Android 12以降だとクックパッドアプリのみインストールされている状態でもクックパッドアプリが開かない(assetlinks.jsonの一番先頭に記述されたアプリのみがデフォルトでウェブインテントを紐づけられる権限を持っている)
ということが分かりました。
また、Android 12未満において直近インストールされたアプリがデフォルトで開くのですが アプリ > (ウェブインテントが紐づいた)アプリ詳細 > 規定で開く > このアプリ対応のリンクを開く「毎回確認」 にした状態で、
Android App Links対応されているページを開くと、該当ページを開くアプリケーションの選択ダイアログが表示されます。
ここでウェブインテントを紐づけたいアプリを選ぶことで、ユーザー設定によって紐づけるアプリを変えられることも確認できました。
Android 12以降の端末に関しては、クックパッドアプリのみインストールされている状態でも「サポートされているリンク」はデフォルトでオフになっていました。
これを、明示的にオンにした場合のみクックパッドアプリが開くようになることが確認できました。
また、クックパッドアプリでサポートされているリンクで cookpad-mart.com
をオンにした場合でも後からマートアプリを入れると、 cookpad-mart.com
に対するウェブインテントの紐付けはマートアプリに移ることが確認できました。
Android 12以降に関しては原則 assetlinks.json
の記述順に優先度が割り当てられていそうなことが分かりました。
まとめ
今回は Android App Links の複数ホスト対応と、Android App Links対応Webサイトに対して複数アプリを関連づけるための知見について紹介しました。
こういったケースは実際はそう多くは発生しないはずで、私たちも結果として今回の方法は採用しなかったのですが、調査した結果として分かった開かれるアプリの優先度や条件などは知見としてなかなか世間に出回っていないはずなので、今後似たようなケースに遭遇したエンジニアの役に立てれば幸いです。
最後になりますが、クックパッドではAndroidエンジニアを大募集しています。
カジュアル面談や学生インターンシップなども随時実施していますので、ぜひお気軽にご連絡ください。
【宣伝】6/6 19:30より、買い物機能のAndroid開発に携わっているエンジニア2名が雑談形式で話すイベントを開催します。
*1:実際には2022年5月時点ではクックパッドマートアプリではAndroid App Linksを使っていませんが、説明を簡単にするために記載しています
*2:例えば https://cookpad.com/kaimono/products/:id のようなルーティングを用意して https://cookpad-mart.com/products/:id へのリダイレクトを実装したり、https://kaimono.cookpad.com/products/:id のようなAndroid App Linksに対応したサブドメイン上にルーティングを用意してhttps://cookpad-mart.com/products/:id へのリダイレクトを実装するなどの方法を取れば、今回のようなケースは発生しない。