Как начать сеанс из уведомления

Когда пользователь запускает действие из уведомления, вы должны сохранить ожидаемый им порядок навигации. При нажатии кнопки "Назад" пользователь должен возвращаться к предыдущим экранам приложения, пока не попадет на главный экран. При открытии экрана недавних приложений действие должно отображаться как отдельная задача. Чтобы сохранить этот принцип навигации, запускайте действие в новой задаче.

Основные сведения о том, как задать поведение при нажатии на уведомление, приведены в разделе Создание простого уведомления. На этой странице рассказывается, как настроить PendingIntent для действия уведомления, чтобы создать новую задачу и стек возврата. Способ зависит от типа действия:

  • Обычное действие. Это действие, которое является частью обычного процесса взаимодействия с приложением. Когда пользователь переходит к действию из уведомления, новая задача должна включать полную цепочку возврата, чтобы пользователь мог нажимать кнопку "Назад" и перемещаться по иерархии приложения.
  • Специальное действие. Пользователь видит это действие, только если оно запущено из уведомления. По сути, это действие расширяет интерфейс уведомлений, предоставляя информацию, которую сложно отобразить в самом уведомлении. Для этого действия не нужна история переходов назад.

Как настроить регулярное намерение PendingIntent для действия

Чтобы запустить обычное действие из уведомления, настройте PendingIntent с помощью TaskStackBuilder так, чтобы создавался новый стек возврата, как показано ниже.

Как определить иерархию Activity в приложении

Определите естественную иерархию для объектов activity, добавив атрибут android:parentActivityName в каждый элемент <activity> в файле манифеста приложения. Вот пример:

<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
    )
}

При необходимости вы можете добавить аргументы в объекты Intent в стеке, вызвав метод TaskStackBuilder.editIntentAt(). Иногда это необходимо, чтобы при переходе пользователя к действию в стеке возврата отображались значимые данные.

Затем вы можете передать PendingIntent в уведомление обычным способом:

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

Как настроить специальное намерение PendingIntent для действия

Поскольку специальному действию, запускаемому из уведомления, не нужен стек возврата, вы можете создать PendingIntent, вызвав getActivity(). Однако в манифесте необходимо указать подходящие параметры задачи.

  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. Создайте Intent, который запускает Activity.
    2. Установите Activity, чтобы начать новую пустую задачу, вызвав setFlags() с флагами FLAG_ACTIVITY_NEW_TASK и FLAG_ACTIVITY_CLEAR_TASK.
    3. Создайте PendingIntent, позвонив на номер getActivity().

    Пример:

    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())
    }

Подробнее о различных вариантах задач и о том, как работает обратный стек, можно узнать в статье Задачи и обратный стек.