App Linksに対応してみた


AndroidのApp Linksとは

公式情報
https://developer.android.com/training/app-links/

雑な理解としては、1つのサービスに対して、WebとAndroidアプリがある場合に、
Android端末上で別のアプリから https://(自分のWebサイト)... というURLに遷移した場合に、アプリがインストールされてればアプリに遷移する。
といったものです。

実装

今回は、
http://my-android-server.appspot.com/html/list.html?page_no=1&open=2
にアクセスすると、
https://play.google.com/store/apps/details?id=hm.orz.chaos114.android.tumekyouen
のアプリのステージ2の画面が表示されるようにします。

まずは、intent-filterの実装

公式情報
https://developer.android.com/training/app-links/deep-linking

今回は、AndroidManifest.xmlにて下記のように設定しました。

        <activity
            android:name=".modules.initial.InitialActivity"
            android:screenOrientation="portrait">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>

                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
            <intent-filter>
                <action android:name="android.intent.action.VIEW"/>

                <category android:name="android.intent.category.DEFAULT"/>
                <category android:name="android.intent.category.BROWSABLE"/>

                <data
                    android:host="my-android-server.appspot.com"
                    android:pathPrefix="/html/list.html"
                    android:scheme="http"/>
            </intent-filter>
        </activity>

2つ目のintent-filterが、
http://my-android-server.appspot.com/html/list.html から始まるURLが実行された場合、
という意味になります。

ここまでで、下記のコマンドを実行することで、アプリの起動ができました。(シェルによっては、"\が無くてもいいかも。。?)

adb shell am start -W -a android.intent.action.VIEW -d "http://my-android-server.appspot.com/html/list.html?page_no=1\&open=2"

ただ、このままでは、

  • アプリが起動するだけで、対象の画面に遷移しない
  • 起動時にブラウザ or 任意のアプリという選択画面が表示される

という状態になっています。順に解決していきます。

起動時のURLから、任意の画面に遷移させる

公式情報
https://developer.android.com/training/app-links/deep-linking#handling-intents

intent-filterを追加したActivityにて、getIntentの戻り値を利用して遷移を行います。

ここはアプリによって大きく変わってくるかと思います。
基本的には、getIntent().getData()をとってみて、nullだったら通常の遷移、値が入っていたらURLを解析して対象の画面に遷移させる形になるかと。

今回は https://github.com/noboru-i/kyouen-android/commit/362ccff367b4bc24ac91b5c2abd9c130b34abee8#diff-ae9d6323f6b1c38043ae5931c6049b56 のように実装しました。

アプリ選択画面をスキップさせる

公式情報
https://developer.android.com/training/app-links/verify-site-associations

ここが今回の本題です。

まずは、Android側のintent-filterに android:autoVerify="true" を追加します。

            <intent-filter android:autoVerify="true">
                <action android:name="android.intent.action.VIEW"/>

                <category android:name="android.intent.category.DEFAULT"/>
                <category android:name="android.intent.category.BROWSABLE"/>

                <data
                    android:host="my-android-server.appspot.com"
                    android:pathPrefix="/html/list.html"
                    android:scheme="http"/>
            </intent-filter>

次に、サーバ側。
公式情報
https://developer.android.com/training/app-links/verify-site-associations#web-assoc
https://www.google.co.jp/.well-known/assetlinks.json のように、他の有名ドメインのものは参考にできそうです。)

.well-known/assetlinks.json というファイルを作成し、内部を以下のようにしました。

[
    {
        "relation": ["delegate_permission/common.handle_all_urls"],
        "target": {
            "namespace": "android_app",
            "package_name": "hm.orz.chaos114.android.tumekyouen.debug",
            "sha256_cert_fingerprints":
            ["C0:D7:F9:34:D8:F7:15:06:FA:21:FA:0D:CF:09:E5:C4:E2:66:D4:11:5D:72:E0:D7:B8:38:F9:49:AB:C7:A4:F0"]
        }
    },
    {
        "relation": ["delegate_permission/common.handle_all_urls"],
        "target": {
            "namespace": "android_app",
            "package_name": "hm.orz.chaos114.android.tumekyouen",
            "sha256_cert_fingerprints":
            ["6E:5A:DB:69:B4:C3:28:AC:DA:7F:00:A7:4D:5D:CD:F9:ED:87:0B:5D:D2:71:C5:89:64:DF:13:38:5A:5B:B8:A2"]
        }
    }
]

まず、公式情報にあるサンプルをコピーし、debug用のpackage名と本番用のpackage名を適用しました。
その後、各keystoreに対して、 keytool -list -v -keystore app/cert/debug.keystore などを実行し、 SHA256 の結果を貼り付けました。

これを、 https://my-android-server.appspot.com/.well-known/assetlinks.json としてアクセスできるようにします。

今回はサーバサイドがGAE上で動いているので、 https://github.com/noboru-i/kyouen-python/pull/18/files のように設定しました。
.well-known/assetlinks.json というファイルをそのまま転送しようとしたら Directory matches ignore regex. と言われてアップロードできなかったので、物理的には well-known/assetlinks.json に変更して、app.yamlの設定でアクセス先を変えました。)

https://digitalassetlinks.googleapis.com/v1/statements:list?source.web.site=https://my-android-server.appspot.com&relation=delegate_permission/common.handle_all_urls にアクセスし、

"debugString": "********************* ERRORS *********************\nNone!...

と返却されることを確認しました。

これで、再度、

adb shell am start -W -a android.intent.action.VIEW -d "http://my-android-server.appspot.com/html/list.html?page_no=1\&open=2"

を実行すると、今まではダイアログでアプリ選択が出ていたのですが、今回は何も聞かれずに対象のアプリ画面が表示されました。

動作確認

上記の対応を行い、Play Storeにアプリを公開しました。

https://twitter.com/noboru_i/status/1028173855754346496
このツイートをTwitterアプリで開き、URLをタップすると、ダイアログが表示されずにステージ2の画面が表示されました。