通知からアクティビティを起動する

通知からアクティビティを開始する場合は、ユーザーが期待するナビゲーション エクスペリエンスを維持する必要があります。戻るボタンをタップすると、アプリの通常のワークフローをたどってホーム画面に戻り、履歴画面を開くと、アクティビティが別のタスクとして表示される必要があります。このナビゲーション エクスペリエンスを維持するには、新しいタスクでアクティビティを開始します。

通知のタップ動作を設定する基本的なアプローチについては、基本的な通知を作成するをご覧ください。このページでは、通知のアクションに PendingIntent を設定して、新しいタスクとバックスタックを作成する方法について説明します。その方法は、開始するアクティビティの種類によって異なります。

  • 通常のアクティビティ: アプリの通常の UX フローの一部として存在するアクティビティです。ユーザーが通知からアクティビティに移動した場合、新しいタスクには完全なバックスタックが含まれている必要があります。これにより、ユーザーは [戻る] ボタンをタップしてアプリの階層を上に移動できます。
  • 特別なアクティビティ: 通知から開始された場合にのみ表示されます。このアクティビティは、通知自体に表示するのが難しい情報を提供することで、通知 UI を拡張します。このアクティビティにはバックスタックは必要ありません。

標準アクティビティの PendingIntent をセットアップする

通知から通常のアクティビティを開始するには、TaskStackBuilder を使用して PendingIntent を設定し、次のように新しいバックスタックを作成します。

アプリのアクティビティ階層を定義する

アプリ マニフェスト ファイル内の各 <activity> 要素に android:parentActivityName 属性を追加して、アクティビティの自然な階層を定義します。次の例をご覧ください。

<activity
    android:name=".MainActivity"
    android:label="@string/app_name" >
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>
<!-- MainActivity is the parent for ResultActivity. -->
<activity
    android:name=".ResultActivity"
    android:parentActivityName=".MainActivity" />
    ...
</activity>

バックスタックを備えた PendingIntent を作成する

アクティビティのバックスタックを含むアクティビティを開始するには、TaskStackBuilder のインスタンスを作成し、addNextIntentWithParentStack() を呼び出して、開始するアクティビティの Intent を渡します。

前述のように各アクティビティの親アクティビティを定義している限り、getPendingIntent() を呼び出して、バックスタック全体を含む PendingIntent を受け取ることができます。

// Create an Intent for the activity you want to start.
val resultIntent = Intent(this, ResultActivity::class.java)
// Create the TaskStackBuilder.
val resultPendingIntent: PendingIntent? = TaskStackBuilder.create(this).run {
    // Add the intent, which inflates the back stack.
    addNextIntentWithParentStack(resultIntent)
    // Get the PendingIntent containing the entire back stack.
    getPendingIntent(
        0,
        PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
    )
}

必要に応じて、TaskStackBuilder.editIntentAt() を呼び出して、スタック内の Intent オブジェクトに引数を追加できます。これは、ユーザーがバックスタック内のアクティビティに移動したときに、意味のあるデータが表示されるようにするために必要な場合があります。

その後、通常どおり PendingIntent を通知に渡すことができます。

val builder = NotificationCompat.Builder(this, CHANNEL_ID).apply {
    setContentIntent(resultPendingIntent)
    // ...
}
with(NotificationManagerCompat.from(this)) {
    notify(NOTIFICATION_ID, builder.build())
}

特殊アクティビティの PendingIntent をセットアップする

通知から開始される特別なアクティビティにはバックスタックが必要ないため、getActivity() を呼び出して PendingIntent を作成できます。ただし、マニフェストで適切なタスク オプションを定義します。

  1. マニフェストで、<activity> 要素に次の属性を追加します。

    android:taskAffinity=""
    コードで使用する FLAG_ACTIVITY_NEW_TASK フラグと組み合わせて、この属性を空白に設定し、このアクティビティがアプリのデフォルト タスクに入らないようにします。アプリのデフォルトのアフィニティを持つ既存のタスクは影響を受けません。
    android:excludeFromRecents="true"
    新しいタスクを履歴画面から除外して、ユーザーが誤って戻らないようにします。

    これを次の例に示します。

    <activity
    android:name=".ResultActivity"
    android:launchMode="singleTask"
    android:taskAffinity=""
    android:excludeFromRecents="true">
    </activity>

  2. 通知をビルドして発行します。

    1. Activity を開始する Intent を作成します。
    2. FLAG_ACTIVITY_NEW_TASK フラグと FLAG_ACTIVITY_CLEAR_TASK フラグを指定して setFlags() を呼び出し、新しい空のタスクで開始するように Activity を設定します。
    3. getActivity() を呼び出して PendingIntent を作成します。

    これを次の例に示します。

    val notifyIntent = Intent(this, ResultActivity::class.java).apply {
        flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
    }
    val notifyPendingIntent = PendingIntent.getActivity(
        this, 0, notifyIntent,
        PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
    )

  3. 通常どおり PendingIntent を通知に渡します。

    val builder = NotificationCompat.Builder(this, CHANNEL_ID).apply {
        setContentIntent(notifyPendingIntent)
        // ...
    }
    with(NotificationManagerCompat.from(this)) {
        notify(NOTIFICATION_ID, builder.build())
    }

さまざまなタスク オプションとバックスタックの仕組みの詳細については、タスクとバックスタックをご覧ください。