Advanced Android in Kotlin 01.2: Android Firebase Cloud Messaging

Questo codelab fa parte del corso Advanced Android in Kotlin. Per ottenere il massimo valore da questo corso, ti consigliamo di seguire i codelab in sequenza, ma non è obbligatorio. Tutti i codelab del corso sono elencati nella pagina di destinazione dei codelab Advanced Android in Kotlin.

Introduzione

Nel codelab precedente, hai aggiunto notifiche al tuo timer per uova che vengono create e attivate all'interno dell'app. Un altro caso d'uso importante delle notifiche è l'invio remoto di notifiche push che possono essere ricevute anche quando l'app non è in esecuzione.

Che cos'è una notifica push?

Le notifiche push sono notifiche che il server "invia" ai dispositivi mobili. Possono essere inviati a un dispositivo indipendentemente dal fatto che la tua app sia in esecuzione o meno.

Le notifiche push sono un ottimo modo per informare gli utenti di un aggiornamento o ricordare loro un'attività o una funzionalità. Immagina di aspettare che un prodotto torni disponibile. Con una notifica push, un'app di shopping può informarti sugli aggiornamenti delle scorte, così non dovrai controllare lo stato delle scorte ogni giorno.

Le notifiche push utilizzano il pattern pubblica/sottoscrivi, che consente alle app di backend di inviare contenuti pertinenti ai client interessati. Senza un modello di pubblicazione/sottoscrizione, gli utenti della tua app dovrebbero controllare periodicamente gli aggiornamenti nell'app. Questo processo è noioso e inaffidabile per gli utenti. Inoltre, man mano che il numero di client aumenta, questi controlli periodici eserciterebbero un carico eccessivo sulle risorse di rete e di elaborazione, sia per il server dell'app sia per il dispositivo di un utente.

Come per tutti gli altri tipi di notifiche, assicurati di rispettare i tuoi utenti con le notifiche push. Se i contenuti della notifica non sono interessanti o tempestivi per l'utente, quest'ultimo può disattivare facilmente tutte le notifiche della tua app.

Che cos'è Firebase Cloud Messaging?

Firebase Cloud Messaging fa parte della piattaforma Firebase per lo sviluppo mobile. In genere, devi configurare un server da zero in grado di comunicare con i dispositivi mobili per attivare le notifiche. Con Firebase Cloud Messaging, puoi inviare notifiche a tutti gli utenti della tua app installata o a un sottoinsieme di questi, senza configurare un server. Ad esempio, puoi inviare agli utenti un promemoria o offrire loro una promozione speciale, ad esempio un regalo gratuito.Puoi inviare una notifica da remoto a un singolo dispositivo o a più dispositivi.

Puoi anche utilizzare Firebase Cloud Messaging per trasferire dati dalla tua app di backend o da un progetto Firebase ai tuoi utenti.

In questo codelab imparerai a utilizzare Firebase Cloud Messaging per inviare notifiche push per la tua app per Android, nonché a inviare dati.

Se riscontri problemi (bug del codice, errori grammaticali, formulazione poco chiara e così via) mentre segui questo codelab, segnalali tramite il link Segnala un errore nell'angolo in basso a sinistra del codelab.

Cosa devi già sapere

Devi avere familiarità con:

  • Come creare app per Android in Kotlin. In particolare, lavora con l'SDK Android.
  • Come progettare l'app utilizzando i componenti dell'architettura e il data binding.
  • Una conoscenza di base dei broadcast receiver.
  • Conoscenza di base di AlarmManager.
  • Come creare e inviare notifiche utilizzando NotificationManager.

Obiettivi didattici

  • Come inviare messaggi all'utente tramite Firebase Cloud Messaging.
  • Come inviare dati da un backend alla tua app utilizzando i messaggi di dati, che fanno parte di Firebase Cloud Messaging.

In questo lab proverai a:

  • Aggiungi notifiche push all'app iniziale.
  • Gestisci Firebase Cloud Messaging mentre l'app è in esecuzione.
  • Trasferisci i dati con Firebase Cloud Messaging.

In questo codelab lavorerai sul codice del precedente codelab Utilizzo delle notifiche nelle app per Android. Nel codelab precedente, hai creato un'app timer per uova che invia notifiche quando il timer di cottura è scaduto. In questo codelab, aggiungerai Firebase Cloud Messaging per inviare notifiche push agli utenti della tua app per ricordare loro di mangiare uova.

Per ottenere l'app di esempio, puoi:

Clona il repository da GitHub e passa al ramo starter:

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


In alternativa, puoi scaricare il repository come file ZIP, decomprimerlo e aprirlo in Android Studio.

Scarica zip

Passaggio 1: crea un progetto Firebase

Prima di poter aggiungere Firebase alla tua app per Android, devi creare un progetto Firebase a cui connetterti.

  1. Accedi alla console Firebase.
  2. Fai clic su Aggiungi progetto, poi seleziona o inserisci un nome del progetto. Assegna al progetto il nome fcm-codelab.
  3. Fai clic su Continua.
  4. Puoi saltare la configurazione di Google Analytics disattivando il pulsante Abilita Google Analytics per questo progetto .
  5. Fai clic su Crea progetto per completare la configurazione del progetto Firebase.

Passaggio 2: registra la tua app con Firebase

Ora che hai un progetto Firebase, puoi aggiungervi la tua app per Android.

  1. Al centro della pagina di riepilogo del progetto della console Firebase, fai clic sull'icona Android per avviare il flusso di lavoro di configurazione.

  1. Nel campo Nome pacchetto Android, inserisci com.example.android.eggtimernotifications.
  2. Fai clic su Registra app.

Importante : assicurati di inserire l'ID corretto per la tua app, perché non potrai aggiungere o modificare questo valore dopo aver registrato l'app con il tuo progetto Firebase.

Passaggio 3: aggiungi il file di configurazione Firebase al progetto

Aggiungi il file di configurazione Firebase Android alla tua app.

  1. Fai clic su Scarica google-services.json per ottenere il file di configurazione Firebase Android (google-services.json). Assicurati che al file di configurazione non vengano aggiunti caratteri aggiuntivi e che il nome sia esattamente google-services.json.
  2. Sposta il file di configurazione nella directory del modulo (a livello di app) della tua app.

Passaggio 4: configura il tuo progetto Android per attivare i prodotti Firebase

Per attivare i prodotti Firebase nella tua app, devi aggiungere il plug-in google-services ai file Gradle.

  1. Nel file Gradle a livello di directory principale (a livello di progetto) (build.gradle), verifica di avere il repository Maven di Google.
  2. Quindi, aggiungi regole per includere il plug-in Google Services.

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. Nel file Gradle del modulo (a livello di app, di solito app/build.gradle), aggiungi una riga per applicare il plug-in in fondo al file.

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

In questa attività, aggiungerai Firebase Cloud Messaging (FCM) al tuo progetto per utilizzare le notifiche push.

Il codice di servizio Android per FCM di questo codelab è riportato in MyFirebaseMessagingService.kt. Nei passaggi successivi aggiungerai il codice alla tua app per Android.

Utilizzerai lo strumento di composizione delle notifiche per testare l'implementazione. Il compositore di notifiche è uno strumento che ti aiuta a comporre e inviare messaggi dal sito web della console Firebase.

  1. Apri MyFirebaseMessagingService.kt
  2. Ispeziona il file e in particolare le seguenti funzioni:
  • onNewToken(): chiamato automaticamente se il servizio è registrato nel file manifest di Android. Questa funzione viene chiamata la prima volta che esegui l'app e ogni volta che Firebase rilascia un nuovo token per la tua app. Un token è una chiave di accesso al progetto backend Firebase. Viene generato per il tuo dispositivo client specifico. Con questo token, Firebase sa a quale client deve inviare i messaggi il backend. Firebase sa anche se questo client è valido e ha accesso a questo progetto Firebase.
  • onMessageReceived: viene chiamata quando l'app è in esecuzione e Firebase invia un messaggio all'app. Questa funzione riceve un oggetto RemoteMessage che può contenere un payload di notifica o di messaggio di dati. Scoprirai di più sulle differenze tra notifiche e payload dei messaggi di dati più avanti in questo codelab.

Passaggio 1: invio di notifiche FCM a un singolo dispositivo

La console delle notifiche ti consente di testare l'invio di una notifica. Per inviare un messaggio a un dispositivo specifico utilizzando la console, devi conoscere il token di registrazione del dispositivo.

Quando il backend Firebase genera un token nuovo o aggiornato, viene chiamata la funzione onNewToken(), con il nuovo token passato come argomento. Se vuoi scegliere come target un singolo dispositivo o creare un gruppo di dispositivi a cui inviare un messaggio di trasmissione, dovrai accedere a questo token estendendo FirebaseMessagingService e sostituendo onNewToken().

  1. Apri AndroidManifest.xml e rimuovi il commento dal seguente codice per attivare MyFirebaseMessagingService per l'app timer per uova. I metadati del servizio nel manifest Android registrano MyFirebaseMessagingService come servizio e aggiungono un filtro per intent in modo che questo servizio riceva i messaggi inviati da FCM. L'ultima parte dei metadati dichiara breakfast_notification_channel_id come default_notification_channel_id per Firebase. Utilizzerai questo ID nel passaggio successivo.
<!-- 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] -->

È consigliabile creare un nuovo canale di notifica per FCM, in quanto gli utenti potrebbero voler attivare/disattivare separatamente le notifiche push di FCM o del timer per uova.

  1. Apri ui/EggTimerFragment.kt . In onCreateView(), aggiungi il seguente codice di creazione del canale.
// 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. Apri MyFirebaseMessagingService.kt e rimuovi il commento dalla funzione onNewToken(). Questa funzione viene chiamata quando viene generato un nuovo token.
// 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. Esegui l'app Timer per uova.
  2. Osserva logcat (Visualizza > Finestre degli strumenti > Logcat). Dovresti visualizzare una riga di log che mostra il token simile a quella riportata di seguito. Questo è il token necessario per inviare un messaggio a questo dispositivo. Questa funzione viene chiamata solo quando viene creato un nuovo token.
2019-07-23 13:09:15.243 2312-2459/com.example.android.eggtimernotifications D/MyFirebaseMsgService: Refreshed token: f2esflBoQbI:APA91bFMzNNFaIskjr6KIV4zKjnPA4hxekmrtbrtba2aDbh593WQnm11ed54Mv6MZ9Yeerver7pzgwfKx7R9BHFffLBItLEgPvrtF0TtX9ToCrXZ5y7Hd-m

Nota: se non vedi il token nei messaggi logcat, è possibile che la tua app lo abbia già ricevuto in precedenza. In questo caso, la disinstallazione dell'app ti aiuterà a ricevere un nuovo token.

Ora puoi eseguire il test inviando una notifica. Per inviare una notifica, utilizzerai il composer delle notifiche.

  1. Apri la console Firebase e seleziona il tuo progetto.
  2. Quindi, seleziona Cloud Messaging dal menu di navigazione a sinistra.
  3. Fai clic su Invia il tuo primo messaggio.

  1. Inserisci Time for Breakfast! come titolo della notifica e Don't forget to eat eggs! come testo della notifica, quindi seleziona Invia messaggio di test. Viene visualizzata la finestra di dialogo popup Test sul dispositivo, che ti chiede di fornire un token di registrazione FCM.

  1. Copia il token dell'app da logcat.

  1. Incolla questo token nel campo Aggiungi un token di registrazione FCM all'interno della finestra popup, quindi fai clic sul pulsante Aggiungi accanto al token.
  2. Seleziona il token nell'elenco di caselle di controllo visualizzato. Il pulsante Testa dovrebbe essere abilitato.

  1. Sul tuo dispositivo, metti l'app Timer per uova in background .
  2. Nel popup, fai clic su Test.
  1. Dopo aver fatto clic su Test, il dispositivo client di destinazione con la tua app in esecuzione in background dovrebbe ricevere la notifica nella barra delle notifiche di sistema. Vedrai più avanti come gestire i messaggi FCM quando l'app è in primo piano.

Attività: invio di notifiche FCM a un argomento

La messaggistica basata su argomenti FCM si basa sul modello di pubblicazione/sottoscrizione.

Un'app di messaggistica può essere un buon esempio per il modello Pubblica/Sottoscrivi. Immagina che un'app controlli la presenza di nuovi messaggi ogni 10 secondi. In questo modo, non solo la batteria dello smartphone si scaricherà più rapidamente, ma verranno anche utilizzate risorse di rete non necessarie e verrà creato un carico inutile sul server dell'app. Un dispositivo client può invece iscriversi e ricevere una notifica quando vengono inviati nuovi messaggi tramite la tua app.

Gli argomenti ti consentono di inviare un messaggio a più dispositivi che hanno attivato la ricezione di messaggi per quell'argomento specifico. Per i clienti, gli argomenti sono origini dati specifiche a cui sono interessati. Per il server, gli argomenti sono gruppi di dispositivi che hanno attivato la ricezione di aggiornamenti su un'origine dati specifica. Gli argomenti possono essere utilizzati per presentare categorie di notifiche, come notizie, previsioni meteo e risultati sportivi. Per questa parte del codelab, creerai un argomento "colazione" per ricordare agli utenti dell'app interessati di mangiare uova a colazione.

Per iscriversi a un argomento, l'app client chiama la funzione Firebase Cloud Messaging subscribeToTopic() con il nome dell'argomento breakfast. Questa chiamata può avere due esiti. Se il chiamante ha esito positivo, il callback OnCompleteListener verrà chiamato con il messaggio a cui è stato eseguito l'abbonamento. Se il client non riesce a eseguire la sottoscrizione, il callback riceverà invece un messaggio di errore.

Nella tua app, gli utenti verranno iscritti automaticamente all'argomento Colazione. Nella maggior parte delle app di produzione, tuttavia, è meglio lasciare agli utenti il controllo degli argomenti a cui iscriversi.

  1. Apri EggTimerFragment.kt e trova la funzione vuota subscribeTopic().
  2. Ottieni un'istanza di FirebaseMessaging e chiama la funzione subscibeToTopic() con il nome dell'argomento.
  3. Aggiungi un addOnCompleteListener per ricevere una notifica da FCM che ti informa se l'abbonamento è andato a buon fine o meno.
// 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. Chiama la funzione subscribeTopic() per abbonarti a un argomento all'avvio dell'app. Scorri fino a onCreateView() e aggiungi una chiamata a subscribeTopic().
// EggTimerFragment.kt

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

    return binding.root
  1. Per iscriverti all'argomento Colazione, esegui di nuovo l'app. Dovresti visualizzare un messaggio di notifica che indica "Iscrizione all'argomento effettuata".

Ora puoi testare l'invio di messaggi a un argomento:

  1. Apri lo strumento di composizione delle notifiche e seleziona Componi notifica.
  2. Imposta il titolo della notifica e il testo della notifica come prima.
  3. Questa volta, anziché inviare il messaggio a un singolo dispositivo, fai clic su Argomento in Destinazione e inserisci breakfast come argomento del messaggio.

  1. Seleziona Ora per la programmazione.

  1. Assicurati che l'app sia in esecuzione in background sul dispositivo di test.
  1. Fai clic su Rivedi e poi su Pubblica. Se puoi eseguire l'app su più dispositivi, puoi testare e osservare che la notifica viene ricevuta su tutti i dispositivi iscritti a questo argomento.

L'app ora dispone dei seguenti canali per le notifiche: Uovo e Colazione. Su un dispositivo client, fai clic a lungo sull'icona dell'app, seleziona Informazioni e poi Notifiche. Dovresti visualizzare i canali di notifica Uovo e Colazione, come mostrato nello screenshot seguente. Se deselezioni il canale Colazione, la tua app non riceverà alcuna notifica inviata tramite questo canale.

Quando utilizzi le notifiche, tieni sempre presente che gli utenti possono disattivare qualsiasi canale di notifica in qualsiasi momento.

Passaggio 1: messaggi di dati

I messaggi FCM possono contenere anche un payload di dati che elabora i messaggi nell'app client. Utilizza i messaggi di dati anziché i messaggi di notifica.

Per gestire i messaggi di dati, devi gestire il payload di dati nella funzione onMessageReceived() di MyFirebaseMessagingService. Il payload è archiviato nella proprietà data dell'oggetto remoteMessage. Sia l'oggetto remoteMessage che la proprietà data possono essere null.

  1. Apri MyFirebaseMessagingService.
  2. Controlla se la proprietà data dell'oggetto remoteMessage ha un valore e stampa i dati nel 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]

Per testare il codice, puoi utilizzare di nuovo lo strumento di composizione delle notifiche.

  1. Apri il compositore di notifiche, crea un nuovo messaggio e imposta Target sull'argomento "colazione".
  2. Questa volta, quando arrivi al passaggio 4, Opzioni aggiuntive, imposta le proprietà chiave e valore di Dati personalizzati come segue:
  1. Chiave: eggs
  2. Valore: 3

  1. Assicurati che l'app sia in esecuzione in primo piano. Se l'app è in background, il messaggio FCM attiverà una notifica automatica e la funzione onMessageReceived() riceverà solo l'oggetto remoteMessage quando l'utente fa clic sulla notifica.
  2. Invia il messaggio dal compositore di notifiche e osserva il log dei messaggi di dati visualizzato in logcat.

Passaggio 2: gestione dei messaggi in primo piano e in background

Quando un dispositivo client che esegue la tua app riceve un messaggio che include sia il payload di notifica sia quello di dati, il comportamento dell'app dipende dal fatto che sia in background o in primo piano sul dispositivo:

  • Se l'app è in esecuzione in background, se il messaggio ha un payload di notifica, la notifica viene visualizzata automaticamente nella barra delle notifiche. Se il messaggio contiene anche un payload di dati, questo verrà gestito dall'app quando l'utente tocca la notifica.
  • Se l'app è in esecuzione in primo piano, se la notifica del messaggio ha un payload di notifica, la notifica non verrà visualizzata automaticamente. L'app deve decidere come gestire la notifica nella funzione onMessageReceived(). Se il messaggio contiene anche un payload di dati, entrambi i payload verranno gestiti dall'app.

Ai fini di questo codelab, vuoi ricordare all'utente dell'app di mangiare delle uova per colazione. Non hai intenzione di inviare dati, ma vuoi anche assicurarti che la notifica di promemoria venga sempre visualizzata, indipendentemente dal fatto che l'app sia in primo piano o in background.

Quando invii un messaggio FCM ai dispositivi su cui è installata l'app timer, il messaggio di notifica viene visualizzato automaticamente se l'app non è in esecuzione o è in background. Tuttavia, se l'app è in esecuzione in primo piano, la notifica non viene mostrata automaticamente. Il codice dell'app decide cosa fare con il messaggio. Se l'app è in primo piano quando riceve un messaggio FCM, la funzione onMessageReceived() viene attivata automaticamente con il messaggio FCM. È qui che la tua app può gestire in modo silenzioso le notifiche e i payload di dati o attivare una notifica.

Per la tua app, vuoi assicurarti che l'utente riceva il promemoria quando l'app è in primo piano, quindi implementiamo del codice per attivare una notifica:

  1. Apri di nuovo la funzione onMessageReceived() in MyFirebaseMessagingService.
  2. Subito dopo il codice che hai aggiunto di recente per controllare il messaggio di dati, aggiungi il seguente codice che invia una notifica utilizzando il framework delle notifiche.
// 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 esegui di nuovo l'app e invii una notifica utilizzando il compositore di notifiche, dovresti visualizzare una notifica come quella che vedevi nella prima parte del codelab, indipendentemente dal fatto che l'app sia in primo piano o in background.

Il codice della soluzione si trova nel ramo master del codice scaricato.

Corso Udacity:

Documentazione di Firebase:

Per i link ad altri codelab di questo corso, consulta la pagina di destinazione dei codelab Advanced Android in Kotlin.