Android では、アプリ内の特定のデスティネーションにユーザーを直接誘導するリンクをディープリンクと呼びます。
アプリでは、「明示的」と「暗黙的」という 2 種類のディープリンクをサポートできます。ディープリンクの実装方法は、アプリで使用するグラフの種類(XML or programmatic)によって異なります。
明示的ディープリンクを作成する
明示的ディープリンクは、PendingIntent を使用してアプリ内の特定の場所にユーザーを誘導するディープリンクの単一インスタンスです。たとえば、通知やアプリ ウィジェットの一部として明示的ディープリンクを表示できます。
ユーザーが明示的ディープリンクを通じてアプリを開くと、タスク バックスタックがクリアされ、ディープリンク デスティネーションに置き換えられます。グラフをネストしている場合は、各ネストレベルの開始デスティネーション(つまり、階層内の各 <navigation> 要素の開始デスティネーション)もスタックに追加されます。そのため、ユーザーがディープリンク デスティネーションから [戻る] ボタンを押すと、アプリにそのエントリ ポイントからアクセスしたかのようにナビゲーション スタックを戻ることができます。
プログラムによるグラフ
ナビゲーション グラフがプログラムで定義されている場合(Navigation Compose や Kotlin DSL で一般的)、TaskStackBuilder を使用してディープリンク PendingIntent を作成することをおすすめします。
val id = "exampleId"
val context = LocalContext.current
val deepLinkIntent = Intent(
Intent.ACTION_VIEW,
"https://www.example.com/profile/$id".toUri(),
context,
MyActivity::class.java
)
val pendingIntent: PendingIntent? = TaskStackBuilder.create(context).run {
addNextIntentWithParentStack(deepLinkIntent)
getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT)
}
XML グラフ
以下の例に示すように、NavDeepLinkBuilder クラスを使用して、PendingIntent を作成できます。指定されたコンテキストが Activity でない場合、コンストラクタは、起動するデフォルト アクティビティとして PackageManager.getLaunchIntentForPackage() を使用します(利用可能な場合)。
Kotlin
val pendingIntent = NavDeepLinkBuilder(context) .setGraph(R.navigation.nav_graph) .setDestination(R.id.android) .setArguments(args) .createPendingIntent()
Java
PendingIntent pendingIntent = new NavDeepLinkBuilder(context) .setGraph(R.navigation.nav_graph) .setDestination(R.id.android) .setArguments(args) .createPendingIntent();
デフォルトでは、NavDeepLinkBuilder はアプリのマニフェストに宣言されたデフォルト起動 Activity への明示的ディープリンクを起動します。NavHost が別のアクティビティにある場合は、ディープリンク ビルダーを作成する際に、次のようにしてそのコンポーネント名を指定する必要があります。
Kotlin
val pendingIntent = NavDeepLinkBuilder(context) .setGraph(R.navigation.nav_graph) .setDestination(R.id.android) .setArguments(args) .setComponentName(DestinationActivity::class.java) .createPendingIntent()
Java
PendingIntent pendingIntent = new NavDeepLinkBuilder(context) .setGraph(R.navigation.nav_graph) .setDestination(R.id.android) .setArguments(args) .setComponentName(DestinationActivity.class) .createPendingIntent();
ComponentName がある場合は、次のようにビルダーにそのまま渡すことができます。
Kotlin
val componentName = ... val pendingIntent = NavDeepLinkBuilder(context) .setGraph(R.navigation.nav_graph) .setDestination(R.id.android) .setArguments(args) .setComponentName(componentName) .createPendingIntent()
Java
ComponentName componentName = ...; PendingIntent pendingIntent = new NavDeepLinkBuilder(context) .setGraph(R.navigation.nav_graph) .setDestination(R.id.android) .setArguments(args) .setComponentName(componentName) .createPendingIntent();
既存の NavController がある場合は、NavController.createDeepLink() を使用してディープリンクを作成することもできます。
暗黙的ディープリンクを作成する
暗黙的ディープリンクは、アプリ内の特定のデスティネーションを参照します。ディープリンクが呼び出されると(たとえばユーザーがリンクをタップしたとき)、Android は対応するデスティネーションでアプリを開くことができます。
ディープリンクは、URI、インテント アクション、MIME タイプによってマッチングできます。単一のディープリンクに対して複数のマッチタイプを指定できますが、マッチングの優先順位は URI 引数、アクション、MIME タイプの順になります。
プログラムによるグラフ
ナビゲーション グラフをプログラムで定義する場合(Navigation Compose または Kotlin DSL を使用)、コードでディープリンクを定義します。
作成
Navigation Compose では、deepLinks パラメータを使用して、composable() デスティネーション ビルダーの一部としてディープリンクを定義できます。navDeepLink() 関数を使用して作成できる NavDeepLink オブジェクトのリストを受け取ります。
@Serializable
data class Profile(val id: String)
val uri = "https://www.example.com"
composable<Profile>(
deepLinks = listOf(
navDeepLink<Profile>(basePath = "$uri/profile")
)
) { backStackEntry ->
val profile: Profile = backStackEntry.toRoute()
ProfileScreen(id = profile.id)
}
Kotlin DSL
Kotlin DSL を使用する場合は、デスティネーション ブロック内の deepLink() ビルダー関数を使用してディープリンクを定義できます。
@Serializable
data class Profile(val id: String)
val uri = "https://www.example.com"
fragment<ProfileFragment, Profile> {
deepLink<Profile>(basePath = "$uri/profile")
}
プログラマティック グラフのインテント フィルタを追加する
プログラムによるナビゲーション グラフは実行時に構築されるため、Navigation コンポーネントは AndroidManifest.xml 内で一致する <intent-filter> 要素を自動的に生成できません。代わりに、適切な <intent-filter> 要素を手動で追加する必要があります。
上記の例のディープリンクを有効にするには、マニフェストの対応する <activity> 要素内に次の要素を追加します。
<activity …>
<intent-filter>
...
<data android:scheme="https" android:host="www.example.com" />
</intent-filter>
</activity>
XML グラフ
XML ベースのグラフで暗黙的ディープリンクを作成するには、XML で <deepLink> 要素を直接定義するか、Navigation Editor を使用します。
URI、アクション、MIME タイプを含むディープリンクの例を次に示します。
<fragment android:id="@+id/a"
android:name="com.example.myapplication.FragmentA"
tools:layout="@layout/a">
<deepLink app:uri="www.example.com"
app:action="android.intent.action.MY_ACTION"
app:mimeType="type/subtype"/>
</fragment>
Navigation Editor を使用して、デスティネーションへの暗黙的ディープリンクを作成することもできます。手順は次のとおりです。
- Navigation Editor の [Design] タブで、ディープリンクのデスティネーションを選択します。
- [Attributes] パネルの [Deep Links] セクションで、[+] をクリックします。
表示された [Add Deep Link] ダイアログで、ディープリンクの情報を入力します。
次の点にご注意ください。
- スキーマのない URI は、
httpまたはhttpsのいずれかと見なされます。たとえば、www.google.comはhttp://www.google.comとhttps://www.google.comの両方に一致します。 {placeholder_name}形式のパスパラメータ プレースホルダは、1 つ以上の文字に一致します。たとえば、http://www.example.com/users/{id}はhttp://www.example.com/users/4に一致します。Navigation コンポーネントは、プレースホルダ名を、ディープリンク デスティネーション用に定義された引数とマッチングすることにより、プレースホルダ値を解析して適切な型に解決しようと試みます。同じ名前を持つ引数が定義されていない場合は、デフォルトのString型が引数の値に使用されます。ワイルドカード「.*」を使用すると、0 個以上の文字に一致させることができます。- クエリ パラメータ プレースホルダは、パスパラメータの代わりに使用することも、パスパラメータと一緒に使用することもできます。たとえば、
http://www.example.com/users/{id}?myarg={myarg}はhttp://www.example.com/users/4?myarg=28に一致します。 - デフォルト値または null 許容値で定義された変数のクエリ パラメータ プレースホルダは、マッチングが不要です。たとえば、
http://www.example.com/users/{id}?arg1={arg1}&arg2={arg2}はhttp://www.example.com/users/4?arg2=28またはhttp://www.example.com/users/4?arg1=7と一致します。この点がパスパラメータと異なります。たとえば、http://www.example.com/users?arg1=7&arg2=28は、必須のパスパラメータが指定されていないため、上記のパターンに一致しません。 - 追加のクエリ パラメータは、ディープリンク URI のマッチングには影響しません。たとえば、
extraneousParamが URI パターンで定義されていなくても、http://www.example.com/users/{id}はhttp://www.example.com/users/4?extraneousParam=7に一致します。
- スキーマのない URI は、
(省略可)自分が URI のオーナーであることが必ず Google によって検証されるようにするには、[Auto Verify] チェックボックスをオンにします。詳しくは、Android アプリリンクを検証するをご覧ください。
[Add] をクリックします。選択したデスティネーションの上にリンクアイコン
が表示され、そのデスティネーションがディープリンクを持つことが示されます。[Code] タブをクリックして、XML ビューに切り替えます。ネストされた
<deepLink>要素がデスティネーションに追加されています。<deepLink app:uri="https://www.google.com" />
XML ベースのグラフで暗黙的ディープリンクを有効にするには、アプリの manifest.xml ファイルに要素を追加する必要もあります。既存のナビゲーション グラフをポイントするアクティビティに対して、単一の <nav-graph> 要素を追加します。次の例をご覧ください。
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.myapplication"> <application ... > <activity name=".MainActivity" ...> ... <nav-graph android:value="@navigation/nav_graph" /> ... </activity> </application> </manifest>
プロジェクトをビルドする際、Navigation コンポーネントは、<nav-graph> 要素を生成された <intent-filter> 要素に置き換えて、ナビゲーション グラフ内のすべてのディープリンクに一致するようにします。
暗黙的ディープリンクとバックスタック
暗黙的ディープリンクをトリガーする場合、暗黙的 Intent を Intent.FLAG_ACTIVITY_NEW_TASK フラグ付きで起動したかどうかによって、バックスタックの状態が変わります。
- フラグがセットされている場合、タスク バックスタックはクリアされ、ディープリンク デスティネーションに置き換えられます。明示的ディープリンクと同様、グラフをネストしている場合は、各ネストレベルの開始デスティネーション(つまり、階層内の各
<navigation>要素の開始デスティネーション)もスタックに追加されます。そのため、ユーザーがディープリンク デスティネーションから [戻る] ボタンを押すと、アプリにそのエントリ ポイントからアクセスしたかのようにナビゲーション スタックを戻ることができます。 - フラグがセットされていない場合、ユーザーは、暗黙的ディープリンクをトリガーした元のアプリのタスクスタック上にとどまります。この場合、[戻る] ボタンを押すと前のアプリに戻り、[上へ] ボタンを押すと、ナビゲーション グラフ階層内の親デスティネーション上にあるアプリのタスクが開始されます。
ディープリンクを処理する
Navigation を使用する際は、常にデフォルトの standard launchMode を使用することを強くおすすめします。standard 起動モードを使用すると、Navigation は Intent 内の明示的・暗黙的ディープリンクを処理する handleDeepLink() を呼び出して、ディープリンクを自動的に処理します。しかし、singleTop など別の launchMode を使用すると、Activity が再使用された際に自動的に処理されません。その場合は、次の例に示すように、onNewIntent() で handleDeepLink() を手動で呼び出す必要があります。
Kotlin
override fun onNewIntent(intent: Intent?) { super.onNewIntent(intent) navController.handleDeepLink(intent) }
Java
@Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); navController.handleDeepLink(intent); }