App Linksの基本を理解したところで
モバイルアプリで、以下の流れ、経験したことありませんか?
アプリをインストール
↓
アプリを起動して、フォームからメールアドレスを入力して送信
↓
メールが届く
↓
メール本文のリンクをタップしたら、アプリが起動
↓
登録情報の入力画面が表示される
太字で記載した部分がApp Linksに関係するものです。
あるサイトの画像をお借りしますが、以下の通りです。
URLをタップ時、
対応アプリがインストール済であれば、アプリが起動し、
未インストールであれば、以下の通りアプリインストールに進むか、ブラウザが開くか、そのどちらかになるかと思います。

※App Linksより
App Links機能の構築
Android アプリリンクは、Android 6 以降の特別なディープリンク機能です。これにより、確認済みのウェブサイト URL から直接 Android アプリ内の対応コンテンツを開けるようになります。ユーザーがアプリの選択ダイアログからアプリを選択する必要はありません。
1.アプリのマニフェストで、android:autoVerify="true を使用してインテント フィルタ内の URL を宣言し、ウェブサイトのホストを指定します。
2.アプリがインストールされると、Android システムはウェブサーバー上の既知の場所から assetlinks.json ファイルを取得します。
3.システムは、assetlinks.json ファイルが有効で、sha256_cert_fingerprints がアプリの署名証明書と一致することを確認します。
4.ユーザーが一致するリンクをクリックすると、システムは確認ダイアログを表示せずに、ユーザーをアプリに直接誘導します。
必要な作業がいくつかあります。
-
android/app/src/main/AndroidManifest.xmlの修正 -
assetlinks.jsonの作成とデプロイ アプリコード修正
以前以下の2本の記事を公開して、App Linksを自分のアプリへの組み込みに挑戦しました。
これらを確認いただければ、概要は掴んでいただけるかと思いますので、ご覧ください。
App Links構築自体は実施してきましたが、以降が今回の本題です。
Dynamic App Links
上記のページでDynamic App Links(動的アプリリンク)について記載されています。
Android 15 以降では、動的アプリリンクが導入され、アプリリンクがさらに強力になります。
動的アプリリンクを使用すると、アプリの新しいバージョンを公開することなく、サーバーサイドの assetlinks.json ファイルでディープリンク ルールを更新できます。
「動的アプリリンクを使用すると」以降が、この機能のメリットの一部であり、まさにDynamicです。
今回はこのDynamic App Linksにまとめています。
まずはドキュメントの内容を確認して内容を理解します。その後、実際に動作させて体感していきたいと思います。
概念フロー
1~3番は冒頭の引用と同じApp Linksに関する記載と同じで、4番、5番がDynamic App Linksに関する話です。
1.アプリのマニフェストで、android:autoVerify="true を使用してインテント フィルタ内の URL を宣言し、ウェブサイトのホストを指定します。
2.アプリがインストールされると、Android システムはウェブサーバー上の既知の場所から assetlinks.json ファイルを取得します。
3.システムは、ファイルが有効で、sha256_cert_fingerprints がアプリの署名証明書と一致していることを検証します。
4.システムは、Digital Asset Links ステートメントの dynamic_app_deep_link_components フィールド内で定義したディープリンク ルールを解析し、マニフェストで宣言されたルールと統合します。
5.システムは assetlinks.json ファイルを定期的に再取得して最新のルールを取得するため、アプリをアップデートしなくてもリンクを更新できます。定期的な再取得は、Google サービスがインストールされている Android 15(API レベル 35)以降を搭載したデバイスでサポートされています。
5番について2点補足します。
「定期的な再取得」とはどれくらいの間隔なの?
システムは assetlinks.json ファイルを定期的に再取得
以下のサポートサイトに載っていました。「だいたい週1回」とのことです。
https://support.google.com/google-ads/answer/16604674?hl=en
the system periodically re-fetches the assetlinks.json file (roughly once a week) to get the latest rules.
テスト時、即座に反映させたい場合、コマンドで強制的に再検証できます。
https://support.google.com/google-ads/answer/16604164?hl=ja
# デバイスのアプリリンクの状態をリセット
adb shell pm set-app-links --package com.example.app 0 all
# システムに再検証を強制する
adb shell pm verify-app-links --re-verify com.example.app
# 検証結果を確認
adb shell pm get-app-links com.example.app
Android 15(API レベル 35)
Play Storeでアプリをリリースされている方々にとっては、普通の話かと思いますが、android\app\build.gradleで設定するtargetSdkの話です。
android {
// 中略
defaultConfig {
applicationId = "com.exmaple.app"
minSdk 29
targetSdk flutter.targetSdkVersion
}
}
以下ページで要件について記載されています。
https://developer.android.com/google/play/requirements/target-sdk?hl=ja
一部ユースケース
このDynamic App Linksの役立つ場面が記載されています。(一部抜粋)
1.ユーザ利用におけるメリット
以下のように、一定期間だけのコンテンツというものがあります。その期間終了後に、アプリの更新をするのは使う側からすれば面倒なケースもありますよね。
季節限定のマーケティング キャンペーン: 小売アプリは、assetlinks.json ファイルに「/promo/summer-sale」のルールを追加して、ユーザーを特定のセール画面に誘導できます。セールが終了したら、ユーザーがアプリを更新しなくてもルールを削除できます。
2.開発工程におけるメリット
開発者にとってもありがたい話はリリースよりも前工程にもあります。テスト時に都度デプロイは大変ですよね、手間もかかりますし、都度デプロイとなれば、時間もかかります。そこも改善可能です。
URL パスの A/B テスト: デベロッパーは、特定の URL パスで新機能を公開し、assetlinks.json ファイルにそのルールを追加できます。これにより、一部のユーザーで機能をテストし、アプリを完全にデプロイすることなくルーティングを変更できます。
構成方法
assetlinks.jsonへの組み込み方が記載されています。dynamic_app_link_componentsが本記事で扱う箇所です。
[
{
"relation": [
"delegate_permission/common.handle_all_urls"
],
"target": {
"namespace": "android_app",
"package_name": "com.example.app",
"sha256_cert_fingerprints": []
},
"relation_extensions": {
"delegate_permission/common.handle_all_urls": {
"dynamic_app_link_components": [
{"?": {"dl": "*"}},
{"#": "app"},
{"/": "/products/*"},
{"/": "/shoes", "?": {"in_app": "true"}},
{"/": "*", "exclude": true}
]
}
}
}
]
記法理解が必要ですが、ドキュメントに丁寧に記載されています。
#はFlutter Webで登場する話ですが、それ以外の/と?はWeb開発経験者にとってなじみ深いパスとクエリパラメータです。
{"#": "app"}は省いて、それ以外を図で整理すると、以下の形になります。
まずAndroidManifest.xmlによる判定をします。
その後、assetlinks.jsonのdynamic_app_link_componentsに沿って表示コンテンツの判定をします。

スコープを適切に設定
ドキュメントに細かく記載されている通りですが、AndroidManifest.xmlとassetlinks.jsonでバランスよく設定します。
動的ルールと静的ルール全体でこのアプローチを使用することをおすすめします。
assetlinks.json ファイルで宣言された動的ルールでは、アプリの AndroidManifest.xml ファイルで宣言したホストのルールのみを指定できます。動的ルールでは、アプリ マニフェストで静的に宣言した URL ルールのスコープを拡大することはできません。
ルール定義の方針
-
AndroidManifest.xml:必ず守るべき土台部分のルールの設定 -
assetlinks.json:状況に応じて可変的にしたいルールの設定
上記の話を受けて、AndroidManifest.xmlを修正します。以下のようにschemeとhostの設定のみを残して、pathに関する情報を削除します。
pathはassetlinks.jsonで管理するようにします。
<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" />
<data android:host="${FIREBASE_HOSTING_DOMAIN}" />
- <data android:path="/register" />
</intent-filter>
定義順の重要性
ルールの宣言順序は重要です。Android は、一致するルールが見つかるまで各ルールを順番に評価します。
dynamic_app_link_componentsの配列について、一致したタイミングで以降の判定は実施しません。記載順を間違えてしまうと、想定した形でアプリが起動しなくなってしまいます。
「限定的なルールは前に、広域的なルールは後に定義」と頭に入れておく必要があります。
ワイルドカードを用いた定義、
上記の例でいえば、{"/": "*", "exclude": true}を使った定義をする場合には注意が必要そうですね。
動作確認してみよう
以下2パターンで試してみました。
1.想定した挙動となるパターン
見出し通りですが、想定した挙動になることを確認します。
"dynamic_app_link_components": [
{
"/": "/register",
"?": {"token": "*"}
},
{
"/": "*",
"exclude": true
}
]
それぞれのパターンに関するスクリーンショットです。想定した通りに制御できていることが確認できました。
| 1.正規パス | 2.パラメータ誤り | 3.パス誤り | 4.ドメイン誤り |
|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
2.全部のパスが除外されるパターン
{"/": "*", "exclude": true}を先頭に定義するパターンです。
ドキュメント内で記載した通り、アプリ起動することを想定しているパスでも、アプリ起動しなくなってしまうことを試します。
実際のアプリの場合はもっと複雑だと思いますので、より慎重に定義するかと思いますが、今回は1つ目の想定通りのパターンから、配列の中身の順番を入れ替えるだけです。
"dynamic_app_link_components": [
{
"/": "*",
"exclude": true
},
{
"/": "/register",
"?": {"token": "*"}
}
]
どんなパスであろうと、アプリで起動しないという確認ができました。
| 1.正規パス | 2.パラメータ誤り | 3.パス誤り | 4.ドメイン誤り |
|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
workflowを用意
本題と関係はしますが、ワークフロー作成、というオマケのような内容です。
Dynamic App Linksと直接は関係しませんので、スキップいただいても構いません。
assetlinks.jsonを更新後、assetlinks.jsonの更新を反映するために、デプロイコマンドを実行します。都度手作業で行うのは、手間な上に間違える可能性もあります。仕組み化しておきたいです。
firebase deploy --only hosting
サービスアカウント作成(Google Cloud)
権限はroles/firebasehosting.adminだけあればOKです。

「鍵を管理」をクリックし、「新しい鍵」を作成して、jsonファイルをダウンロードします。

Workflow用のyamlファイル作成
先ほどダウンロードしたjsonファイルの中身を、GithubのSettingからSecretとして設定します。私はFIREBASE_HOSTING_DEPLOY_SERVICE_ACCOUNT_JSONとしましたが、ここは任意の名前でOKです。
ワークフローのyamlファイル
name: Deploy Firebase Hosting
on:
push:
branches:
- main
paths:
- 'public/.well-known/assetlinks.json'
- 'firebase.json'
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '24'
- name: Install Firebase CLI
run: npm install -g firebase-tools
- name: Setup Firebase Service Account
run: |
echo '${{ secrets.FIREBASE_HOSTING_DEPLOY_SERVICE_ACCOUNT_JSON }}' > $HOME/only-firebasehosting-admin.json
echo "GOOGLE_APPLICATION_CREDENTIALS=$HOME/only-firebasehosting-admin.json" >> $GITHUB_ENV
- name: Deploy to Firebase Hosting
run: firebase deploy --only hosting --non-interactive
まとめ
今回は、Android 15(API レベル 35)からサポートされている、Dynamic App Linksについて学習しました。
以下まとめになります。
改めてDynamic App Linksとは
従来のApp Linksでは、ディープリンクのルールを変更する際にアプリの新しいバージョンをリリースする必要がありましたが、Dynamic App Linksを使用することで、assetlinks.jsonファイル更新だけでルールが変更できるようになりました。
主なメリット
ユーザー視点
- 季節限定キャンペーンなどの一時的なコンテンツに対応する際、アプリの更新が不要
- キャンペーン終了後もアプリの更新不要
開発者視点
- A/Bテストが容易に実施可能
- アプリの完全なデプロイなしに新機能のテストやルーティング変更ができる
導入時の確認事項
-
役割分担を明確に
-
AndroidManifest.xml:変更の少ない基本的なルール(scheme、hostなど) -
assetlinks.json:柔軟に変更したいルール(path、クエリパラメータなど)
-
-
ルールの定義順序に注意
- 配列内のルールは上から順に評価
- 限定的なルールを先に、広域的なルールを後に記載
-
定期的な自動更新
- システムが約週1回
assetlinks.jsonを自動的に再取得 - テスト時は
adbコマンドで強制的に再検証可能
- システムが約週1回
注意点
- Google サービスがインストールされているAndroid 15以降のデバイスでのみサポート
-
targetSdkの設定がAPI レベル 35以上であること - 動的ルールでは、マニフェストで宣言したホストのスコープを拡大できない
参考





