デスティネーションへのディープリンクを作成する

Android では、アプリ内の特定のデスティネーションにユーザーを直接誘導するリンクをディープリンクと呼びます。

Navigation コンポーネントを使用すると、「明示的」と「暗黙的」という 2 種類のディープリンクを作成できます。

明示的ディープリンクを作成する

明示的ディープリンクは、PendingIntent を使用してアプリ内の特定の場所にユーザーを誘導するディープリンクの単一インスタンスです。たとえば、通知やアプリ ウィジェットの一部として明示的ディープリンクを表示できます。

ユーザーが明示的ディープリンクを通じてアプリを開くと、タスク バックスタックがクリアされ、ディープリンク デスティネーションに置き換えられます。グラフをネストしている場合は、各ネストレベルの開始デスティネーション(つまり、階層内の各 <navigation> 要素の開始デスティネーション)もスタックに追加されます。そのため、ユーザーがディープリンク デスティネーションから [戻る] ボタンを押すと、アプリにそのエントリ ポイントからアクセスしたかのようにナビゲーション スタックを戻ることができます。

以下の例に示すように、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 タイプの順になります。

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 を使用して、デスティネーションへの暗黙的ディープリンクを作成することもできます。手順は次のとおりです。

  1. Navigation Editor の [Design] タブで、ディープリンクのデスティネーションを選択します。
  2. [Attributes] パネルの [Deep Links] セクションで、[+] をクリックします。
  3. 表示された [Add Deep Link] ダイアログで、ディープリンクの情報を入力します。

    次の点に注意してください。

    • スキーマのない URI は、http または https のいずれかと見なされます。たとえば、www.google.comhttp://www.google.comhttps://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 に一致します。
  4. (省略可)自分が URI のオーナーであることが必ず Google によって検証されるようにするには、[Auto Verify] チェックボックスをオンにします。詳しくは、Android アプリリンクを検証するをご覧ください。

  5. [Add] をクリックします。選択したデスティネーションの上にリンクアイコン が表示され、そのデスティネーションがディープリンクを持つことが示されます。

  6. [Code] タブをクリックして、XML ビューに切り替えます。ネストされた <deepLink> 要素がデスティネーションに追加されています。

    <deepLink app:uri="https://www.google.com" />
    

暗黙的ディープリンクを有効にするには、アプリの 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> 要素に置き換えて、ナビゲーション グラフ内のすべてのディープリンクに一致するようにします。

暗黙的ディープリンクをトリガーする場合、暗黙的 IntentIntent.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);
}

参考情報

ナビゲーションについて詳しくは、以下の参考情報をご確認ください。

Codelab

動画