ディープリンクとは、OSがブラウザの代わりにアプリに渡すURLです。アプリがインストールされているデバイスでリンクをタップすると、アプリが正しい画面で開きます。アプリがインストールされていないデバイスでタップすると、ブラウザがWebフォールバックへのリダイレクトを辿ります。1つのURL、2つの結果、JavaScriptのshimなし、ほとんどのセットアップでサードパーティのSDKも不要です。
チームはここで定期的に過剰購入しています。Branch.io、Adjust、AppsFlyer - それらのマーケティング資料は遅延ディープリンクを主力として宣伝しています:アプリをインストールする前にリンクをタップし、インストールし、タップして辿った正確なコンテンツでアプリが開きます。この機能は本当に複雑で、アプリがインストールされるまでOSのリンクルーティングが休眠状態にあるため、サーバーサイドのフィンガープリンティングまたはクリップボードマッチングのトリックが必要です。しかし、遅延ディープリンクは問題の一部です。より一般的なケース、「すでにインストールされているアプリでリンクを開く」は、AppleとGoogleがそれぞれ2015年と2015〜16年にリリースしたOS固有のプリミティブで完全に解決されており、管理するドメインと2つのJSONファイル以外は何も必要ありません。
この記事はそれら2つのJSONファイルについてです。
まとめ#
- Apple Universal Links(iOS 9以上)とAndroid App Links(Android 6.0以上)は、サードパーティSDKなしで「インストール済みならアプリで開く、未インストールならWebフォールバック」のフローを処理します。
- どちらも、管理するドメインと、
/.well-known/に検証済みのアソシエーションファイルを持つHTTPSで提供されるものが必要です。OSはすべてのタップ時ではなく、アプリのインストール時にファイルをフェッチしてキャッシュします。 go.acme.exampleのようなカスタムドメインを持つURLショートナーは両方のファイルを提供し、アプリのルーティングをトリガーするリンクになります - ショートリンクがディープリンクになります。- SDKがOS固有のプリミティブに追加するもの:遅延ディープリンク、確率的インストールアトリビューション、クロスプラットフォームのアイデンティティステッチング。それらが必要な場合、SDKはコストに見合います。必要でない場合、使用していない機能にお金を払っています。
OS固有のプリミティブ#
AppleはiOS 9(2015年)にUniversal Linksを導入しました。AndroidはAndroid 6.0 Marshmallow(2015年、2016年にわたってデバイスにリリース)でApp Linksをリリースしました。どちらも同じ概念モデルに従います:OSはドメインとアプリの間の検証済みの関係を主張し、そのドメインのURLがタップされると、OSはブラウザではなくアプリにルーティングします。
検証は双方向でオフラインファーストです。アプリのインストール時に、OSはドメインからアソシエーションファイルをフェッチしてキャッシュします。AppleのフェッチャーはAppleのdeveloper.apple.com/ios/universal-links/(2026-05-12参照)に文書化されています。GoogleのものはGoogleのdeveloper.android.com/training/app-links(2026-05-12参照)にあります。温まったデバイスでのタップ時にはどちらのフェッチも行われません - キャッシュにより、ルーティングの決定にネットワークのラウンドトリップはゼロです。
リダイレクト自体は標準的なHTTP 302です。OSはブラウザが読み込む前にそれを傍受し、ローカルキャッシュを確認し、一致が見つかった場合はアプリにURLを渡します。キャッシュが温まると、すべての決定はローカルです。ショートリンクを提供するエッジがリダイレクトを発行し、OSが引き継ぎます。
2つのファイル#
apple-app-site-association#
AASAファイルはhttps://yourdomain.example/.well-known/apple-app-site-associationで提供される必要があります(Appleは後方互換性のためにアペックスパスhttps://yourdomain.example/apple-app-site-associationも確認しますが、.well-knownパスが現在の標準です)。有効な証明書チェーンを持つHTTPSで、Content-Type: application/jsonヘッダーと共に提供される必要があります。Appleのフェッチャーは誤ったContent-Typeで提供されたファイルを拒否します - これは本番環境での最も一般的な設定ミスの1つです。
完全なフォーマットの参照はdeveloper.apple.com/documentation/xcode/supporting-associated-domainsにあります。
最小限のAASAの形式:
{
"applinks": {
"details": [
{
"appIDs": ["ABCDE12345.com.example.acme"],
"components": [
{
"/": "/spring-*",
"comment": "Match any path starting with /spring-"
},
{
"/": "/campaigns/*"
}
]
}
]
}
}
appIDsはApple Team IDとアプリのバンドル識別子をドットで区切ったものです。components配列はどのパスがアプリのルーティングをトリガーするかを制御します。コンポーネントに一致しないものはすべてブラウザにフォールスルーします。details配列に複数のアプリを登録できます - 同じドメインに同じ製品の消費者版とエンタープライズ版がある場合に便利です。
明記する価値のある詳細:/spring-*のようなワイルドカードパターンを持つ"/"はパスのプレフィックスマッチです。AppleのXcodeのドキュメントで定義されたパターン構文をサポートしています(*は任意の部分文字列、?は任意の1文字、除外オブジェクトを含む)。ドメインのすべてのパスに一致させたい場合は"/" : "/*"を使用します。特定のパスをアプリのルーティングから除外したい場合 - たとえば/account/deleteページは常にブラウザで開くべき - ワイルドカードの前に除外オブジェクトを追加します:
{
"/": "/account/delete",
"exclude": true
}
ルールは最初から最後まで評価されます。除外をワイルドカードの前に置いてください。
assetlinks.json#
AndroidのDigital Asset LinksファイルはHTTPS//.well-known/assetlinks.jsonに存在します。仕様はGoogleのdevelopers.google.com/digital-asset-links/v1/getting-startedで維持されています。
[
{
"relation": ["delegate_permission/common.handle_all_urls"],
"target": {
"namespace": "android_app",
"package_name": "com.example.acme",
"sha256_cert_fingerprints": [
"AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99"
]
}
}
]
package_nameはPlay StoreでのアプリのアプリケーションIDです。sha256_cert_fingerprintsはAPKに署名するために使用された証明書のSHA-256フィンガープリントです - SHA-1でもMD5でもありません。Play ConsoleのApp Integrityで、またはkeytool -list -v -keystore your.keystoreを実行してフィンガープリントを見つけることができます。デバッグビルドと本番ビルドの両方をリリースする場合は、両方のフィンガープリントを配列に含めてください。
AASAファイルと異なり、Androidのアソシエーションファイルはファイルレベルでのパスフィルタリングをサポートしていません。App LinksのパスマッチングはAndroidManifest.xmlでandroid:pathPrefix、android:pathPattern、または新しいandroid:pathAdvancedPattern(Android 12から利用可能)を使用した<intent-filter>で行われます。assetlinks.jsonファイルはドメインの所有権を主張します。マニフェストはアプリが処理するパスを宣言します。
URLショートナーの役割#
go.acme.example/spring-launchのようなショートリンクは、ドメイン上のただのURLです。OSの視点から、go.acme.exampleが有効なAASAまたはassetlinks.jsonファイルを持っていれば、そのドメインのリンクをタップするとアプリのルーティングの対象になります。
これはElidoのカスタムドメインでのディープリンク設定で直接サポートしている設定です。ワークスペースでgo.acme.exampleをカスタムドメインとして登録すると、ElidoはそのドメインのすべてのスラッグのHTTPSリダイレクトを提供します。2つのアソシエーションファイルを同じドメインから提供します - 自分のオリジンのパスプロキシの背後で、またはドメイン自身のHTTPSサーバー経由で。エッジのリダイレクトが起動し、OSはブラウザが読み込む前にそれを傍受し、AASA/App Linksキャッシュを参照し、一致が見つかった場合はアプリを開きます。
アーキテクチャはcustom-domains-for-short-linksの記事で詳しく説明しています - TLS発行とCNAMEのセットアップはそこで説明されているとおりに適用されます。ディープリンク層は付加的なものです:同じドメイン、同じリダイレクト、上に2つのJSONファイルがあるだけです。
モバイルオンボーディングにショートリンクを使用するプロダクトチーム - リファラルコード、招待リンク、「レシピをシェア」フロー - にとって、このパターンはアプリのバイナリにSDK依存関係を追加することなく、ほぼすべてをカバーします。
SDKが追加するもの#
OS固有のプリミティブが提供しない3つの機能:
遅延ディープリンク。 ユーザーがアプリをインストールする前にリンクをタップします。インストール後の最初の起動で、アプリはタップして辿った正確なコンテンツで開きます。iOSのUniversal LinksとAndroid App Linksは、アプリがインストールされていない場合はサイレントです - URLはブラウザに移動し、意図は失われます。それを回復するには、サーバーサイドのフィンガープリントマッチ(IP + ユーザーエージェント + タイムスタンプ、確率的)またはiOSのクリップボードトリックが必要です。Branch、Adjust、AppsFlyer はすべてこれらを実装しています。App Tracking Transparencyのプロンプトとサファリの動作に関するエッジケースがあるため、自分で実装するのは非自明です。
大規模なインストールアトリビューション。 OS固有のルートはURLパスと共にアプリのオープンを提供しますが、最初のタップ時にアプリがインストールされていなかった場合、アトリビューションチェーンが壊れます。iOSのSKANとAndroidのPlay Install Referrerを通じてクリックをインストールと照合するのは、有料SDKなしでも可能ですが、アトリビューションベンダーがすでに行っている統合作業が必要です。
クロスプラットフォームのアイデンティティステッチング。 タップをメールアドレス、CRMコンタクト、Webセッションに紐付ける。OS固有のパスはリンクサービスの視点からは匿名です。SDKベンダーは永続的なデバイスグラフを維持しています。自分で構築するのは相当なデータインフラのプロジェクトです。
これら3つのいずれも該当しない場合、OS固有のプリミティブでカバーできます。1つが重要な場合は、正確にスコープを絞ってください - 遅延ディープリンクだけが必要かもしれません。完全なSDKではなく、1つのAPIサーフェスです。
設定クックブック#
DNSとHTTPS要件#
両方のファイルはディープリンクしたいリンクのドメインのHTTPS経由で提供される必要があります。証明書はパブリックのルートCAにチェーンしている必要があります。自己署名証明書はAppleとGoogleの両方の検証フェッチャーをサイレントに失敗させます。Let's Encryptの証明書は問題なく機能します。
ドメインのTLSはファイルを提供する前に/.well-known/パスをリダイレクトしてはいけません。Appleのフェッチャーがhttps://yourdomain.example/.well-known/apple-app-site-associationに到達する前にサーバーがwww.リダイレクトを発行した場合、フェッチは失敗します。Appleのフェッチャーは最大1つのリダイレクトを辿りますが、Googleのassetlinksフェッチャーはリダイレクトをまったく辿りません - ファイルは正確なパスに存在する必要があり、リダイレクトはありません。
iOS:Associated Domainsエンタイトルメント#
Xcodeで、ターゲットの「Signing & Capabilities」の下に、値applinks:go.acme.exampleを持つAssociated Domainsエンタイトルメントを追加します。TestFlightまたはApp Store経由で配布されていない開発ビルドでテストしている場合は、エンタイトルメントの値に?mode=developerを追加します:applinks:go.acme.example?mode=developer。これにより、OSはインストール時のキャッシュを使用するのではなく、毎回起動時にAASAを再フェッチします - Storeから毎回再インストールすることなく、パスパターンを繰り返し実装する際に便利です。
AASAファイルをフェッチするAppleのCDNはデバイス自体ではなく、Appleの独自インフラです。AppleはあなたのドメインからAASAファイルを事前フェッチしてキャッシュし、アプリのインストール時にデバイスに提供します。つまり、ファイルはエンドユーザーのデバイスだけでなく、AppleのクローラーからもアクセスできるようにAPが必要です。また伝播遅延があります - AASAファイルへの変更はAppleのキャッシュ経由ですべてのデバイスに到達するまで数時間かかる場合があります。パスパターンの迅速な繰り返し実装が必要な開発者にとって、?mode=developerエンタイトルメントはAppleのCDNをバイパスしてサーバーから直接フェッチします。
Android:マニフェストのApp Links#
AndroidManifest.xmlで、ディープリンクを処理するアクティビティ内:
<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="go.acme.example"
android:pathPrefix="/campaigns/" />
</intent-filter>
android:autoVerify="true"はAndroidにassetlinks.jsonに対してドメインの検証を試みるよう指示します。これがなければ、ユーザーはすべてのタップで直接アプリに開くのではなく、あいまい解消シートが表示されます。検証はインストール時に行われます。デバイスはhttps://go.acme.example/.well-known/assetlinks.jsonに到達し、インストールされたアプリの証明書フィンガープリントがリストされているか確認します。
バリデーターと一般的なエラー#
Appleはsearch.developer.apple.com/appsearch-validation-tool/にバリデーターを提供しており、AppleのCDNがAASAファイルをフェッチして解析できるか確認します。ドメインを入力すると、有効な解析結果または特定のエラーが返ります。一般的な失敗:
- 誤ったContent-Type。 サーバーが
text/plainまたはapplication/octet-streamを返す場合、JSONが有効でもバリデーターはファイルを読み取れないとして報告します。Content-Type: application/jsonを明示的に設定してください。 - 欠落または不一致の
appIDs。appIDsのTeam IDプレフィックスはApple Developer Accountのチームアカウントとケースを含め正確に一致する必要があります。1文字のミスがタップ時にサイレントに失敗します。 - 証明書チェーンの問題。 ドメインがパブリックルートにチェーンしていない証明書を提供する場合(ローカルのCAルートを持つステージング環境でよくある)、Appleのフェッチャーはファイルを拒否します。
GoogleのバリデーターはDigital Asset Links APIです:https://digitalassetlinks.googleapis.com/v1/statements:list?source.web.site=https://go.acme.example&relation=delegate_permission/common.handle_all_urls。JSONレスポンスにはGoogleがドメインに対して検証したすべてのステートメントがリストされます。レスポンスが空またはパッケージ名が欠落している場合、Androidはインストール時にアプリを自動検証しません。一般的な失敗:
- assetlinksパスでのリダイレクト。 上記の通り:Googleのフェッチャーはリダイレクトを辿りません。
- 誤った証明書フィンガープリント。 デバッグAPKとリリースAPKは異なるキーで署名されています。リリースフィンガープリントのみをリストした場合、デバッグビルドは検証されません。両方をリストしてください。
- CORS付きで提供されているがverifiation リクエストに対するヘッダーが誤っている。 フェッチャーはCORSを気にしませんが、一部のCDN設定では、パスがキャッシュ許可リストにない場合、GoogleのIP範囲からの
GETに対して403を返します。/.well-known/assetlinks.jsonがブラウザだけでなく外部のHTTPクライアントから200を返すことを確認してください。
トレードオフを明確に述べる#
ディープリンクSDKを削除すると、圧縮バイナリサイズが約150〜250KB節約され、アトリビューションベンダーのサーバーへのインストールごとのAPIコールが排除されます。これにより、プライバシーポリシーからデータ共有関係が削除され、GDPRのデータ処理記録が簡略化できます。実際のメリットですが、控えめです。
コストはインストール時のアトリビューションが概算または不在になることです。ユーザーがアプリをインストールする前にリンクをタップした場合、App Store ConnectまたはPlay Consoleでインストールを確認できますが、特定のリンクタップに紐付けることはできません。どのキャンペーンがより多くのインストールを促すかを比較するためにスマートリンクの実験を実行することはできます - 相対的なシグナルは残ります - しかしデバイスごと、クリックごとのアトリビューションはSDKのフィンガープリント層が必要です。
チャネルごとのCPIがまだ予算の決定を動かしていない初期規模のチームにとって、OS固有のプリミティブから始めることが賢明なパスです。データが実際に実行可能になった後で、アトリビューションSDKを後から追加してください。
Elidoのディープリンク設定に関する開発者向けセットアップガイドには、ドメイン検証フローの完全なスキーマ、AASAプロキシ設定、assetlinks.jsonの提供オプションが文書化されています。プロダクトチームのソリューションページでは、スマートリンクとモバイルリンクの広いユースケースについて説明しています。
Marius VoßはElidoのDevRel + エッジインフラ担当です。edge-redirectとdomain-managerサービスを担当しています。
Elidoを試す
URLを貼り付けて短縮リンクを取得
登録不要。リンクは30日間有効。永久に保存するには登録してください。
Free、登録不要 · 1日あたり2件