Iniciar uma atividade a partir de uma notificação

Ao iniciar uma atividade em uma notificação, você precisa preservar a experiência de navegação esperada do usuário. Ao tocar no botão "Voltar", o usuário precisa voltar pelo fluxo de trabalho normal do app até a tela inicial, e ao abrir a tela "Recentes", a atividade precisa aparecer como uma tarefa separada. Para preservar essa experiência de navegação, inicie a atividade em uma nova tarefa.

A abordagem básica para definir o comportamento de toque da sua notificação é descrita em Criar uma notificação básica. Nesta página, descrevemos como configurar um PendingIntent para a ação da notificação, de modo que ela crie uma tarefa e um backstack. A maneira de fazer isso depende do tipo de atividade que você está iniciando:

  • Atividade regular: é uma atividade que existe como parte do fluxo normal de UX do seu app. Quando o usuário chega à atividade pela notificação, a nova tarefa precisa incluir uma backstack completa, permitindo que o usuário toque no botão "Voltar" para navegar na hierarquia do app.
  • Atividade especial: o usuário só vê essa atividade se ela for iniciada por uma notificação. De certa forma, essa atividade estende a interface de notificação ao fornecer informações difíceis de mostrar na própria notificação. Essa atividade não precisa de uma backstack.

Configurar uma atividade comum PendingIntent

Para iniciar uma atividade regular na notificação, configure o PendingIntent usando TaskStackBuilder para criar uma nova backstack da seguinte maneira.

Definir a hierarquia de atividades do app

Defina a hierarquia natural das atividades adicionando o atributo android:parentActivityName a cada elemento <activity> no arquivo de manifesto do app. Confira este exemplo:

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

Criar um PendingIntent com uma pilha de retorno

Para iniciar uma Activity que inclui um backstack de Activities, crie uma instância de TaskStackBuilder e chame addNextIntentWithParentStack(), transmitindo o Intent da Activity que você quer iniciar.

Desde que você defina a atividade principal para cada atividade conforme descrito anteriormente, é possível chamar getPendingIntent() para receber um PendingIntent que inclui toda a backstack.

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

Se necessário, adicione argumentos aos objetos Intent na pilha chamando TaskStackBuilder.editIntentAt(). Isso às vezes é necessário para garantir que uma atividade na backstack mostre dados significativos quando o usuário navega até ela.

Em seguida, transmita o PendingIntent para a notificação normalmente:

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

Configurar uma atividade especial PendingIntent

Como uma atividade especial iniciada por uma notificação não precisa de uma pilha de retorno, é possível criar o PendingIntent chamando getActivity(). No entanto, defina as opções de tarefa adequadas no manifesto.

  1. No manifesto, adicione os seguintes atributos ao elemento <activity>.

    android:taskAffinity=""
    Combinado com a flag FLAG_ACTIVITY_NEW_TASK usada no código, defina esse atributo como em branco para garantir que a atividade não entre na tarefa padrão do app. As tarefas atuais que têm a afinidade padrão do app não serão afetadas.
    android:excludeFromRecents="true"
    Exclui a nova tarefa da tela "Recentes" para que o usuário não volte a ela por acidente.

    Isso é mostrado neste exemplo:

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

  2. Compilar e emitir a notificação:

    1. Crie um Intent que inicie o Activity.
    2. Defina o Activity para iniciar em uma nova tarefa vazia chamando setFlags() com as flags FLAG_ACTIVITY_NEW_TASK e FLAG_ACTIVITY_CLEAR_TASK.
    3. Crie um PendingIntent chamando getActivity().

    Isso é mostrado neste exemplo:

    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. Transmita o PendingIntent à notificação normalmente:

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

Para mais informações sobre as várias opções de tarefas e como a backstack funciona, consulte Tarefas e a backstack.