ブラウザやメールなどからURLをタップしたときに自分のアプリを開かせるには、IntentFilter でディープリンクを設定する。URLのパラメータをアプリ内に渡せる。

IntentFilter を設定する

AndroidManifest.xml の対象 ActivityIntentFilter を追加する。Android 12(API 31)以降は android:exported の明示的な設定が必須だ。外部アプリ(ブラウザやメールクライアント)からActivityを起動できるよう、true を設定する。

<activity
    android:name=".MainActivity"
    android:exported="true">
    <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:scheme="https"
            android:host="example.com"
            android:pathPrefix="/items" />
    </intent-filter>
</activity>

各要素の説明は以下のとおり。

要素説明
action: VIEWURLを表示するアクション。ディープリンクに必須
category: DEFAULT暗黙的インテントに対応するために必須
category: BROWSABLEブラウザからのリンクを受け取るために必須
dataマッチさせるURLのパターンを指定

pathPrefix="/items" の設定で https://example.com/items 以下のURLがアプリで開ける。

Activity でURLを受け取る

アプリが起動したら Intent から data を取得してURLを解析する。

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        handleDeepLink(intent)
    }

    override fun onNewIntent(intent: Intent) {
        super.onNewIntent(intent)
        setIntent(intent)
        handleDeepLink(intent)
    }

    private fun handleDeepLink(intent: Intent) {
        val uri = intent.data ?: return

        // URLのパスを取得する
        val path = uri.path
        // URLのクエリパラメータを取得する
        val itemId = uri.getQueryParameter("id")
    }
}

intent.data はディープリンクで起動した場合のみ非nullになる。通常起動では null になるため ?: return でガードする。

launchModesingleTopsingleTask の場合、アクティビティが起動済みだと onCreate() ではなく onNewIntent() が呼ばれる。両方でディープリンクを処理するために handleDeepLink() として共通化する。

URLパラメータを渡す

クエリパラメータを使うとURLからアプリへデータを渡せる。

https://example.com/items?id=42&category=books を受け取った場合:

val uri = intent.data ?: return

val itemId = uri.getQueryParameter("id")       // "42"
val category = uri.getQueryParameter("category") // "books"

パスのセグメントからデータを取得するには pathSegments を使う。

https://example.com/items/42 の場合:

val uri = intent.data ?: return

// ["items", "42"] のリストが得られる
val segments = uri.pathSegments
val itemId = segments.getOrNull(1) // "42"

複数のURLパターンに対応する

複数の IntentFilter を設定すると、異なるURLパターンに対応できる。

<activity
    android:name=".MainActivity"
    android:exported="true">
    <!-- https://example.com/items に対応 -->
    <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:scheme="https"
            android:host="example.com"
            android:pathPrefix="/items" />
    </intent-filter>

    <!-- https://example.com/users に対応 -->
    <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:scheme="https"
            android:host="example.com"
            android:pathPrefix="/users" />
    </intent-filter>
</activity>

カスタムスキームを使う

https の代わりにアプリ独自のスキームも使える。

<data
    android:scheme="myapp"
    android:host="open"
    android:pathPrefix="/items" />

scheme="myapp" の設定で myapp://open/items?id=42 でアプリを開ける。ただしカスタムスキームは他のアプリと衝突する可能性があるため、https スキームを使う方が安全だ。

https スキームでディープリンクを設定しただけでは、URLをタップしたときにブラウザとアプリのどちらで開くかを選ぶダイアログが表示される。アプリが自動的に開くようにするにはAndroid App Linksの設定が必要だ。

android:autoVerify="true"IntentFilter に追加する。

<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:scheme="https"
        android:host="example.com"
        android:pathPrefix="/items" />
</intent-filter>

さらに対象ドメインの https://example.com/.well-known/assetlinks.json にDigital Asset Linksファイルを配置し、ドメインとアプリの紐付けをOSが検証できるようにする。ファイルにはアプリのパッケージ名とSHA-256フィンガープリントを記述する。

[{
  "relation": ["delegate_permission/common.handle_all_urls"],
  "target": {
    "namespace": "android_app",
    "package_name": "com.example.myapp",
    "sha256_cert_fingerprints": ["AA:BB:CC:..."]
  }
}]

SHA-256フィンガープリントはリリース用キーストアから以下のコマンドで取得できる。

keytool -list -v -keystore release.jks -alias [key alias]

adb でディープリンクをテストする

adb shell am start \
  -W -a android.intent.action.VIEW \
  -d "https://example.com/items?id=42" \
  com.example.myapp

com.example.myapp は自分のアプリのパッケージ名に置き換える。

参考