Este tutorial faz parte do curso Android avançado em Kotlin. Você obterá o máximo valor deste curso se trabalhar com os tutoriais em sequência, mas isso não é obrigatório. Todos os tutoriais do curso estão listados na página de destino Android avançado em Kotlin.

Introdução

No tutorial anterior, você adicionou notificações ao cronômetro de ovo que são criadas e acionadas dentro do seu aplicativo. Outro caso de uso importante de notificações é enviar notificações push remotamente que podem ser recebidas mesmo quando seu aplicativo não está em execução.

O que é uma notificação push?

Notificações push são notificações que o servidor "envia" para dispositivos móveis. Eles podem ser entregues a um dispositivo, independentemente de seu aplicativo estar em execução ou não.

Notificações push são uma ótima maneira de informar aos usuários sobre uma atualização ou lembrá-los de uma tarefa ou recurso. Imagine esperar que um produto esteja em estoque novamente. Com uma notificação push, um aplicativo de compras pode informá-lo sobre as atualizações do estoque, em vez de você ter que verificar o status do estoque todos os dias.

As notificações push usam o padrão publicar / assinar, que permite que aplicativos de back-end enviem conteúdo relevante para clientes interessados. Sem um modelo publicar / assinar, os usuários de seu aplicativo precisariam verificar periodicamente se há atualizações em seu aplicativo. Esse processo é tedioso e não confiável para os usuários. Além disso, conforme o número de clientes aumenta, essas verificações periódicas sobrecarregariam demais os recursos de rede e processamento, tanto para o servidor do seu aplicativo quanto para o dispositivo do usuário.

Assim como todos os outros tipos de notificações, certifique-se de respeitar seus usuários com notificações push. Se o conteúdo da notificação não for interessante ou oportuno para o usuário, ele pode facilmente desligar todas as notificações de seu aplicativo.

O que é Firebase Cloud Messaging?

Firebase Cloud Messaging faz parte da plataforma Firebase para desenvolvimento móvel. Normalmente você precisa configurar um servidor do zero que pode se comunicar com dispositivos móveis para acionar notificações. Com o Firebase Cloud Messaging, você pode enviar notificações para todos os usuários do seu aplicativo instalado, ou um subconjunto deles, sem configurar um servidor. Por exemplo, você pode enviar aos usuários um lembrete ou dar a eles uma promoção especial, como um presente grátis. Você pode enviar uma notificação remotamente para um ou vários dispositivos.

Você também pode usar o Firebase Cloud Messages para transferir dados do seu aplicativo de back-end ou de um projeto do Firebase para seus usuários.

Neste tutorial, você aprenderá a usar o Firebase Cloud Messaging para enviar notificações push para seu aplicativo Android, bem como enviar dados.

Se você encontrar algum problema (bugs de código, erros gramaticais, palavras pouco claras etc.) ao trabalhar neste tutorial, relate o problema por meio do link Report a mistake no canto inferior esquerdo do tutorial.

O que você já deveria saber

Você deve estar familiarizado com:

O que você aprenderá

O que você vai fazer

Neste tutorial, você trabalhará no código do tutorial anterior, Usando Notificações em Aplicativos Android. No tutorial anterior, você construiu um aplicativo de cronômetro de ovo que envia notificações quando o cronômetro de cozimento está ligado. Neste tutorial, você adicionará Firebase Cloud Messaging para enviar notificações push aos usuários do seu aplicativo para lembrá-los de comer ovos.

Para obter o aplicativo de amostra, você pode:

Clone o repositório do GitHub e mude para o branch starter:

$ git clone https://github.com/googletutoriais/android-kotlin-notifications-fcm


Alternativamente, você pode baixar o repositório como um arquivo Zip, descompactá-lo e abri-lo no Android Studio.

Baixe o Zip

Etapa 1: criar um projeto Firebase

Antes de adicionar o Firebase ao seu aplicativo Android, você precisa criar um projeto do Firebase para se conectar ao seu aplicativo Android.

  1. Faça login no Firebase console.
  2. Clique em Add project e selecione ou insira um Project name. Nomeie seu projeto como fcm-tutorial.
  3. Clique em Continue.
  4. Você pode pular a configuração do Google Analytics desativando o botão Enable Google Analytics for this project.
  5. Clique em Create Project para concluir a configuração do projeto Firebase.

Etapa 2: registre seu aplicativo no Firebase

Agora que você tem um projeto Firebase, pode adicionar seu aplicativo Android a ele.

  1. No centro da página de visão geral do projeto do console do Firebase, clique no ícone Android para iniciar o fluxo de trabalho de configuração.

  1. No campo Android package name, digite com.example.android.eggtimernotifications.
  2. Clique em Register app.

Importante: certifique-se de inserir o ID correto para seu aplicativo, porque você não pode adicionar ou modificar este valor depois de registrar seu aplicativo com seu projeto Firebase.

Etapa 3: adicione o arquivo de configuração do Firebase ao seu projeto

Adicione o arquivo de configuração do Firebase Android ao seu aplicativo.

  1. Clique em Download google-services.json para obter seu arquivo de configuração do Firebase Android (google-services.json). Certifique-se de que o arquivo de configuração não contenha caracteres adicionais e tenha o nome google-services.json exatamente.
  2. Mova seu arquivo de configuração para o diretório do módulo (nível de aplicativo) do seu aplicativo.

Etapa 4: configure seu projeto Android para habilitar produtos Firebase

Para habilitar produtos Firebase em seu aplicativo, você deve adicionar o plug-in google-services aos seus arquivos Gradle.

  1. No arquivo Gradle de nível raiz (nível de projeto) (build.gradle), verifique se você tem o repositório Maven do Google.
  2. Em seguida, adicione regras para incluir o plug-in de serviços do Google.

build.gradle

buildscript {

  repositories {
    // Check that you have the following line (if not, add it):
    google()  // Google's Maven repository
  }

  dependencies {
    // ...

    // Add the following line:
    classpath 'com.google.gms:google-services:4.3.2'  // Google Services plugin
  }
}

allprojects {
  // ...

  repositories {
    // Check that you have the following line (if not, add it):
    google()  // Google's Maven repository
    // ...
  }
}
  1. No seu arquivo Gradle do módulo (nível do aplicativo) (geralmente app/build.gradle), adicione uma linha para aplicar o plug-in na parte inferior do arquivo.

app/build.gradle

apply plugin: 'com.android.application'

android {
  // ...
}

// Add the following line to the bottom of the file:
apply plugin: 'com.google.gms.google-services'  // Google Play services Gradle plugin

Nesta tarefa, você adicionará Firebase Cloud Messaging (FCM) ao seu projeto para usar notificações push.

O código de serviço Android para FCM deste tutorial é fornecido em MyFirebaseMessagingService.kt. Nas etapas a seguir, você adicionará o código ao seu aplicativo Android.

Você usará o Compositor de notificações para testar sua implementação. O compositor de notificações é uma ferramenta que ajuda a redigir e enviar mensagens do site do console do Firebase.

  1. Abra MyFirebaseMessagingService.kt
  2. Inspecione o arquivo e, em particular, as seguintes funções:

Etapa 1: enviar notificações do FCM a um único dispositivo

O Notifications console permite que você teste o envio de uma notificação. Para enviar uma mensagem a um dispositivo específico usando o console, você precisa saber o token de registro desse dispositivo.

Quando o back-end do Firebase gera um token novo ou atualizado, a função onNewToken() é chamada, com o novo token passado como argumento. Se você deseja direcionar um único dispositivo ou criar um grupo de dispositivos para o qual deseja enviar uma mensagem de broadcast, você precisará acessar este token estendendo FirebaseMessagingService e substituindo onNewToken().

  1. Abra AndroidManifest.xml e descomente o código a seguir para ativar o MyFirebaseMessagingService para o aplicativo cronômetro de ovo. Os metadados de serviço no manifesto do Android registram MyFirebaseMessagingService como um serviço e adiciona um filtro de intent para que este serviço receba mensagens enviadas do FCM. A última parte dos metadados declara breakfast_notification_channel_id como default_notification_channel_id para Firebase. Você usará esse ID na próxima etapa.
<!-- AndroidManifest.xml -->
<!-- TODO: Step 3.0 uncomment to start the service  -->

        <service
                android:name=".MyFirebaseMessagingService"
                android:exported="false">
            <intent-filter>
                <action android:name="com.google.firebase.MESSAGING_EVENT"/>
            </intent-filter>
        </service>
        <!-- [START fcm_default_icon] -->
        <!--
 Set custom default icon. This is used when no icon is set for incoming notification messages.
             See README(https://goo.gl/l4GJaQ) for more.
        -->
        <meta-data
                android:name="com.google.firebase.messaging.default_notification_icon"
                android:resource="@drawable/common_google_signin_btn_icon_dark"/>
        <!--
 Set color used with incoming notification messages. This is used when no color is set for the incoming
             notification message. See README(https://goo.gl/6BKBk7) for more.
        -->
        <meta-data
                android:name="com.google.firebase.messaging.default_notification_color"
                android:resource="@color/colorAccent"/> <!-- [END fcm_default_icon] -->
        <!-- [START fcm_default_channel] -->
        <meta-data
            android:name="com.google.firebase.messaging.default_notification_channel_id"
            android:value="@string/breakfast_notification_channel_id" />
        <!-- [END fcm_default_channel] -->

É uma boa ideia criar um novo canal de notificação para o FCM, pois seus usuários podem querer ativar / desativar o cronômetro de ovo ou as notificações push do FCM separadamente.

  1. Abra ui/EggTimerFragment.kt. Em onCreateView(), adicione o seguinte código de criação de canal.
// EggTimerFragment.kt

   // TODO: Step 3.1 create a new channel for FCM
    createChannel(
        getString(R.string.breakfast_notification_channel_id),
        getString(R.string.breakfast_notification_channel_name)
    )
  1. Abra MyFirebaseMessagingService.kt e descomente a função onNewToken(). Esta função será chamada quando um novo token for gerado.
// MyFirebaseMessagingService.kt

   // TODO: Step 3.2 log registration token
    // [START on_new_token]
    /**
     * Called if InstanceID token is updated. This may occur if the security of
     * the previous token had been compromised. Note that this is called when the     
     * InstanceID token is initially generated so this is where you would retrieve     
     * the token.
     */
    override fun onNewToken(token: String?) {
        Log.d(TAG, "Refreshed token: $token")

        // If you want to send messages to this application instance or
        // manage this apps subscriptions on the server side, send the
        // Instance ID token to your app server.
        sendRegistrationToServer(token)
    }
    // [END on_new_token]
  1. Execute o aplicativo cronômetro de ovo.
  2. Observe o logcat (View> Tool Windows> Logcat). Você deve ver uma linha de registro mostrando seu token semelhante ao mostrado abaixo. Este é o token de que você precisa para enviar uma mensagem a este dispositivo. Esta função somente é chamada quando um novo token é criado.
2019/07/23 13: 09: 15,243 2312-2459 / com.example.android.eggtimernotifications D / MyFirebaseMsgService: símbolo refrescado: f2esflBoQbI: APA91bFMzNNFaIskjr6KIV4zKjnPA4hxekmrtbrtba2aDbh593WQnm11ed54Mv6MZ9Yeerver7pzgwfKx7R9BHFffLBItLEgPvrtF0TtX9ToCrXZ5y7Hd-m

Note: Se você não vir o token nas mensagens do logcat, seu aplicativo pode já ter recebido o token antes. Nesse caso, desinstalar o aplicativo ajudará você a receber um novo token.

Agora você pode testar enviando uma notificação. Para enviar uma notificação, você usará o Notifications composer.

  1. Abra o Firebase Console e selecione seu projeto.
  2. Em seguida, selecione Cloud Messaging na navegação à esquerda.
  3. Clique em Send your first message.

  1. Insira Time for Breakfast! como o título da notificação e Don't forget to eat eggs! como o texto da notificação e selecione Send test message. A caixa de diálogo pop-up Test on device é exibida, solicitando que você forneça um token de registro FCM.

  1. Copie seu token de aplicativo do logcat.

  1. Cole este token no campo Add an FCM registration token na janela pop-up e clique no botão Add ao lado do token.
  2. Na lista de caixas de seleção que aparece, selecione o token. O botão Test deve ser ativado.

  1. Em seu dispositivo, coloque o aplicativo Egg Timer em segundo plano background.
  2. No pop-up, clique em Test.
  1. Depois de clicar em Test, o dispositivo cliente de destino que tem seu aplicativo em execução em segundo plano deve receber a notificação na bandeja de notificações do sistema. (Você verá mais sobre como tratar com as mensagens do FCM quando seu aplicativo estiver em primeiro plano posteriormente.)

Tarefa: Enviando notificações FCM para um tópico

As mensagens de tópicos do FCM são baseadas no modelo de publicação / assinatura.

Um aplicativo de mensagens pode ser um bom exemplo para o modelo Publish/Subscribe. Imagine que um aplicativo verifique se há novas mensagens a cada 10 segundos. Isso não apenas drenará a bateria do telefone, mas também usará recursos de rede desnecessários e criará uma carga desnecessária no servidor do seu aplicativo. Em vez disso, um dispositivo cliente pode se inscrever e ser notificado quando houver novas mensagens entregues por meio de seu aplicativo.

Topics permitem que você envie uma mensagem para vários dispositivos que optaram por aquele tópico específico. Para clientes, os tópicos são fontes de dados específicas nas quais o cliente está interessado. Para o servidor, os tópicos são grupos de dispositivos que optaram por receber atualizações em uma fonte de dados específica. Os tópicos podem ser usados ​​para apresentar categorias de notificações, como notícias, previsões do tempo e resultados de esportes. Para esta parte do tutorial, você criará um tópico "café da manhã" para lembrar os usuários do aplicativo interessados ​​de comer ovos com o café da manhã.

Para subscribe um tópico, o aplicativo cliente chama a função Firebase Cloud Messaging subscribeToTopic() com o nome do tópico breakfast. Essa chamada pode ter dois resultados. Se o chamador for bem-sucedido, o retorno de chamada OnCompleteListener será chamado com a mensagem assinada. Se o cliente não conseguir se inscrever, o retorno de chamada receberá uma mensagem de erro.

Em seu aplicativo, você inscreverá automaticamente seus usuários no tópico do café da manhã. Na maioria dos aplicativos de produção, no entanto, é melhor dar aos usuários controle sobre quais tópicos assinar.

  1. Abra EggTimerFragment.kt e encontre a função subscribeTopic() vazia.
  2. Obtenha uma instância de FirebaseMessaging e chame a função subscibeToTopic() com o nome do tópico.
  3. Adicione um addOnCompleteListener para ser notificado do FCM se sua assinatura foi bem-sucedida ou não.
// EggTimerFragment.kt

   // TODO: Step 3.3 subscribe to breakfast topic
    private fun subscribeTopic() {
        // [START subscribe_topics]
        FirebaseMessaging.getInstance().subscribeToTopic(TOPIC)
            .addOnCompleteListener { task ->
                var msg = getString(R.string.message_subscribed)
                if (!task.isSuccessful) {
                    msg = getString(R.string.message_subscribe_failed)
                }
                Toast.makeText(context, msg, Toast.LENGTH_SHORT).show()
            }
        // [END subscribe_topics]
    }
  1. Chame a função subscribeTopic() para se inscrever em um tópico quando o aplicativo for iniciado. Role para cima até onCreateView() e adicione uma chamada para subscribeTopic().
// EggTimerFragment.kt

   // TODO: Step 3.4 call subscribe topics on start
    subscribeTopic()

    return binding.root
  1. Para assinar o tópico do café da manhã, execute o aplicativo novamente. Você deverá ver uma mensagem de brinde dizendo "Inscrito no tópico".

Agora você pode testar o envio de mensagens para um tópico:

  1. Abra o Notifications composer e selecione Compose Notification.
  2. Defina a notificação Notification title e Notification text como antes.
  3. Desta vez, em vez de enviar a mensagem para um único dispositivo, clique em Topic em Target e insira breakfast como o tópico da mensagem.

  1. Selecione Now para Agendamento.

  1. Certifique-se de que seu aplicativo esteja sendo executado em segundo plano no dispositivo de teste.
  1. Clique em Review e, em seguida, clique em Publish. Se você pode executar o aplicativo em mais de um dispositivo, pode testar e observar se a notificação é recebida em todos os dispositivos inscritos neste tópico.

O aplicativo tem os seguintes canais para notificações agora, Egg e Breakfast. Em um dispositivo cliente, clique longamente no ícone do aplicativo, selecione Info, e clique em Notifications. Você deve ver os canais de notificação Egg e Breakfast, conforme mostrado na imagem a seguir. Se você desmarcar o canal Breakfast, seu aplicativo não receberá notificações enviadas por meio deste canal.

Ao usar notificações, sempre tenha em mente que os usuários podem desligar qualquer canal de notificação a qualquer momento.

Etapa 1: mensagens de dados

As mensagens do FCM também podem conter uma carga útil de dados que processa as mensagens no aplicativo cliente, use mensagens de dados em vez de mensagens de notificação.

Para tratar com mensagens de dados, você precisa tratar com a carga útil de dados na função onMessageReceived() de MyFirebaseMessagingService. A carga útil é armazenada na propriedade data do objeto remoteMessage. Tanto o objeto remoteMessage quanto a propriedade data podem ser null.

  1. Abra MyFirebaseMessagingService.
  2. Verifique se a propriedade data do objeto remoteMessage tem algum valor e imprima os dados no log.
// MyFirebaseMessagingService.kt

    // [START receive_message]
    override fun onMessageReceived(remoteMessage: RemoteMessage?) {
        // Not getting messages here? See why this may be: https://goo.gl/39bRNJ
        Log.d(TAG, "From: ${remoteMessage?.from}")
        
       // TODO: Step 3.5 check messages for data
        // Check if the message contains a data payload.
        remoteMessage?.data?.let {
            Log.d(TAG, "Message data payload: " + remoteMessage.data)
        }

    }
    // [END receive_message]

Para testar seu código, você pode usar o Compositor de notificações novamente.

  1. Abra o Editor de notificação, crie uma nova mensagem, definindo seu Target como o tópico "café da manhã".
  2. Desta vez, quando você chegar à Etapa 4, Additional options, defina as propriedades de chave e valor Custom data da seguinte maneira:
  1. Key: eggs
  2. Value: 3

  1. Certifique-se de que seu aplicativo esteja sendo executado em primeiro plano. Se seu aplicativo estiver em segundo plano, a mensagem do FCM acionará uma notificação automática e a função onMessageReceived() receberá apenas o objeto remoteMessage quando o usuário clicar na notificação.
  2. Envie a mensagem do compositor de Notificações e observe o registro de mensagens de dados que aparece no logcat.

Etapa 2: tratamento de mensagens em primeiro e segundo plano

Quando um dispositivo cliente executando seu aplicativo recebe uma mensagem que inclui cargas úteis de notificação e dados, o comportamento do aplicativo depende se ele está em segundo ou primeiro plano nesse dispositivo:

Para o propósito deste tutorial, você deseja lembrar o usuário do aplicativo de comer alguns ovos no café da manhã. Você não está planejando enviar nenhum dado, mas também deseja garantir que a notificação de lembrete sempre apareça, independentemente de o aplicativo estar em primeiro ou segundo plano.

Quando você envia uma mensagem do FCM para dispositivos nos quais o aplicativo cronômetro de ovo está instalado, a mensagem de notificação será exibida automaticamente se o aplicativo não estiver em execução ou em segundo plano. No entanto, se o aplicativo estiver sendo executado em primeiro plano, a notificação não será exibida automaticamente; em vez disso, o código do aplicativo decide o que fazer com a mensagem. Se o aplicativo estiver em primeiro plano ao receber uma mensagem do FCM, a função onMessageReceived() será acionada automaticamente com a mensagem do FCM. É aqui que seu aplicativo pode manipular silenciosamente cargas úteis de notificação e dados ou acionar uma notificação.

Para seu aplicativo, você deseja garantir que o usuário receba o lembrete quando o aplicativo estiver em primeiro plano, então vamos implementar algum código para acionar uma notificação:

  1. Abra a função onMessageReceived() em MyFirebaseMessagingService novamente.
  2. Imediatamente após o código que você adicionou recentemente para verificar a mensagem de dados, adicione o seguinte código que envia uma notificação usando a estrutura de notificações.
// MyFirebaseMessagingService.kt

    // TODO: Step 3.6 check messages for notification and call sendNotification
    // Check if the message contains a notification payload.
    remoteMessage.notification?.let {
        Log.d(TAG, "Message Notification Body: ${it.body}")
        sendNotification(it.body as String)
    }
  1. Se você executar o aplicativo novamente e enviar uma notificação usando o compositor de Notificações, deverá ver uma notificação exatamente como costumava ver na primeira parte do tutorial, independentemente de o aplicativo estar em primeiro ou segundo plano.

O código da solução está no branch master do seu código baixado.

Documentação do Firebase:

Para obter links para outros tutoriais neste curso, consulte a página inicial de tutoriais do Android avançado em Kotlin.