[Android]AppLinksを使ってディープリンク（アプリを開く）方法について

## はじめに

今までアプリでディープリンクというとFirebase Dynamic Linskがお馴染みでしたが正式にサービス終了(2025/8/25終了)をアナウンスしました。代替のものも独自で新たにリリースする予定は今のところなさそうです。
https://qiita.com/y-matsumoto/items/c244d6749f85165d8741

そのため、今まで使っていたアプリは何かに移行する必要があります。個人的にはAdjustが使い勝手よく、シェアも大きいため良いと思います。

今回はネイティブのAndroidが用意しているAppLinksについて実装を確認していきます。
iOSの場合はApple公式でUniversal linkが同等な機能にあたります。

```引用
ユーザーがデバイスでリンクをたどる目的は、見たいコンテンツにたどり着くこと。デベロッパーは Android アプリリンクを設定して、アプリ選択ダイアログ（確認ダイアログとも呼ばれます）をバイパスして、アプリ内でリンクの特定のコンテンツに直接ユーザーを誘導できます。Android アプリリンクは HTTP URL とウェブサイトとの関連付けを利用するため、アプリをインストールしていないユーザーは、サイトのコンテンツに直接移動します。

リンクの種類を理解する
Android アプリリンクを実装する前に、Android アプリで作成できるさまざまな種類のリンク（ディープリンク、ウェブリンク、Android アプリリンク）を理解することが重要です。図 1 に、これらの種類のリンクの関係を示します。以降のセクションでは、各種類のリンクについて詳しく説明します。

ディープリンク
ディープリンクは、ユーザーをアプリの特定の部分に直接誘導する、あらゆるスキームの URI です。ディープリンクを作成するには、アプリ内の適切なアクティビティにユーザーを誘導するインテント フィルタを追加します。
```

引用元：https://developer.android.com/training/app-links?hl=ja

## 具体的にAppLinksを使うと何ができるのか
基本的にはリンクからアプリを呼び出すことが可能です。
それだけであれば既存のURLスキームを使うと同じことが可能ですが、セキュアではありません。そのため推奨されていません。（これは他の悪意あるアプリがある場合にうまく動作しない場合があります。）
それに比べるとAppLinksはセキュアな設計になっており、アプリとサーバ間で検証が行われ、アプリ制作した側とサーバ用意した側が一致していることを証明する仕組みが組み込まれています。
URLスキームではオリジナルのスキーム（myapp://やtest://など）が使えていましたが、 AppLinksはhttps(またはhttp)のみとなります。

## 実装方法

1.assetlinks.jsonファイルをサーバに設置
2.アプリのマニフェストにintet-filterを設置

## 1.assetlinks.jsonファイルのサーバ設定
まずこれがアプリとサーバの紐付けに関連するファイルとなります。

### フォーマット
```
[
	{
		"relation": [
			"delegate_permission/common.handle_all_urls"
		],
		"target": {
			"namespace": "android_app",
			"package_name": [パッケージ名],
			"sha256_cert_fingerprints": [sha256署名フィンガープリント]
			]
		}
	}
]
```

### 実際に下記を例に埋めるとこんな形です。
パッケージ名：com.example.testapp
sha256_cert_fingerprints：XX:XX:17:56:72:55:51:F0:0B:64:83:7E:CB:2A:90:86:BE:58:64:27:05:CC:EA:D8:59:17:42:66:0D:A4:XX:XX

```
[
	{
		"relation": [
			"delegate_permission/common.handle_all_urls"
		],
		"target": {
			"namespace": "android_app",
			"package_name": "com.example.testapp",
			"sha256_cert_fingerprints": [
				"XX:XX:17:56:72:55:51:F0:0B:64:83:7E:CB:2A:90:86:BE:58:64:27:05:CC:EA:D8:59:17:42:66:0D:A4:XX:XX"
			]
		}
	}
]
```

### 次にassetlinks.jsonをサーバに設置

サーバの直下に.well-known/assetlinks.jsonを設置する必要があります。
注意事項として直下でないと動作がうまくいきませんでした。（ここ気が付かず苦戦しました）

### assetlinks.jsonファイルの検証

下記のサイトにサーバドメイン、アプリパッケージ、フィンガープリントを入れてTestステートメントでSuccessになれば問題ないということです。ここで、自動でステートメントを作成しassetlinks.jsonを作成することもできるので、便利です。
https://developers.google.com/digital-asset-links/tools/generator?hl=ja

成功パターン
![スクリーンショット 2024-08-04 16.44.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109862/225eae5d-5d2a-4201-9dc1-a95b51eaf45e.png)

失敗パターン
![スクリーンショット 2024-08-04 16.44.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109862/7dcdfeb7-3c31-d6ae-e217-72acffe17791.png)

## 2.アプリのマニフェストにintet-filterを設置

### 実際に下記を例にマニフェストを埋めるとこんな形です。
url：https://example.test.com
```
            <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="example.test.com"
                    android:scheme="https" />
            </intent-filter>
```
autoVerify="true"を入れることで手動で設定画面からユーザに任意で設定を行なってもらう必要なく自動で対処可能です。もしこれを入れない場合は手動設定をユーザに促す必要があります。（カメラ権限をユーザにOKもらうのと同じ形）

下記のような形となります。
![スクリーンショット 2024-08-02 13.58.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109862/9e8ec0bd-8669-9102-a7ef-10ee92db0112.png)

AppLinksは6以降から対応してますが、全てautoVerify="true"で対処できるのかまでは検証してません。必要に応じて端末依存でautoVerify="true"が聞いてない場合は、手動設定を検討する必要もありそうです。

## 動作確認
上記の設定の場合は、urlで
```
https://example.test.com
https://example.test.com/test
```
などを叩けば処理されます。処理されたものを受け取りたい場合はMainActivityより下記のようにonNewIntentで受け取ることが可能です。

```kotlin
    override fun onNewIntent(intent: Intent) {
        super.onNewIntent(intent)
        // 何かしらの処理(urlは取得できるため、urlにより処理を変える)
    }
```

これにより例えば、受け取ったurlのパスによっては画面を切り替えるや処理を変更するなどが容易にできます。
これらは端末標準「のブラウザからurlを叩いても」、「アプリ内のChrome Custom Tabsから叩いても」、「アプリからIntentで該当アプリを起動しても」、onNewIntentでハンドリング可能です。
しかしアプリ内のWebviewで同じ挙動にしたい場合は、onNewIntentでは取得できないため、フックして同じ挙動になるようにWebviewのコードで対処することが必要になります。

## AppLinksでディファードディープリンクは実現できるのかどうか
結論難しいです。
しかし同じような挙動にすることはバックエンド側のディープリンクをはるサイトが自分側のサーバの場合は対処が可能です。この辺りは細かくは割愛します。

一つのアイデアとして簡単にまとめると、まずはアプリ起動をサーバ側で強制的に行わせ、アプリ起動の履歴がサーバに来ない場合は数秒後にマーケットに誘導するなどが一つのアイデアです

## さいごに
AppLinks以外と考慮することが多いためよく理解して、サービスのパターンとしてWebviewも同様の挙動にしたいのか、またはブラウザでurlによりどういう挙動を求めるのか設計を考えた上で実装する必要があります。