Android avanzato in Kotlin 01.2: Android Firebase Cloud Messaging

Questo codelab fa parte del corso Advanced Android in Kotlin. Otterrai il massimo valore da questo corso se lavori in sequenza nei codelab, ma non è obbligatorio. Tutti i codelab del corso sono elencati nella pagina di destinazione avanzata per i codelab di Android in Kotlin.

Introduzione

Nel codelab precedente, hai aggiunto notifiche al timer che hai creato e attivato all'interno dell'app. Un altro caso d'uso importante delle notifiche consiste nell'inviare da remoto 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. Queste app possono essere pubblicate su un dispositivo indipendentemente dal fatto che la tua app sia in esecuzione o meno.

Le notifiche push sono un ottimo modo per far conoscere agli utenti un aggiornamento o ricordare loro un'attività o una funzionalità. Immagina di aspettare che un prodotto sia di nuovo disponibile. Con una notifica push, un'app di shopping può informarti sugli aggiornamenti delle azioni invece di dover controllare lo stato delle azioni ogni giorno.

Le notifiche push utilizzano il pattern publish/subscribe, che consente alle app di backend di inviare contenuti pertinenti ai client interessati. Senza un modello di pubblicazione/iscrizione, gli utenti della tua app dovrebbero verificare periodicamente la presenza di aggiornamenti nella tua app. Questa procedura è noiosa e inaffidabile per gli utenti. Inoltre, con l'aumento del numero di client, questi controlli periodici aumenterebbero il carico di lavoro sul networking e sulle risorse 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, possono facilmente disattivare tutte le notifiche dalla tua app.

Cos'è Firebase Cloud Messaging?

Firebase Cloud Messaging fa parte della piattaforma Firebase per lo sviluppo di app per dispositivi mobili. Solitamente è necessario 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 delle app installate o a un loro sottoinsieme, senza configurare un server. Ad esempio, puoi inviare un promemoria agli utenti o offrire loro una promozione speciale, come un regalo.Puoi inviare una notifica da remoto a un singolo dispositivo o a più dispositivi.

Puoi anche utilizzare Firebase Cloud Messaggi per trasferire i 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 Android e come inviare dati.

Se riscontri problemi (bug di codice, errori grammaticali, parole non chiare e così via) via email con questo codelab, segnala il problema tramite il link Segnala un errore nell'angolo in basso a sinistra del codelab.

Informazioni importanti

Dovresti acquisire familiarità con:

  • Come creare app Android in Kotlin. In particolare, puoi usare l'SDK Android.
  • Come progettare l'app utilizzando componenti di architettura e associazioni di dati.
  • Conoscenza di base dei ricevitori di trasmissioni.
  • Conoscenza di base di AlarmManager.
  • Come creare e inviare notifiche usando NotificationsManager.

Obiettivi didattici

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

In questo lab proverai a:

  • Aggiungere 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 al codice del codelab sull'utilizzo precedente delle notifiche in Android Apps. Nel codelab precedente, hai creato un'app timer per le uova che invia notifiche quando il timer di cottura è attivo. In questo codelab, aggiungerai Firebase Cloud Messaging per inviare notifiche push agli utenti della tua app per ricordare loro di mangiare le uova.

Per scaricare 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 Android, devi creare un progetto Firebase per connetterti all'app.

  1. Accedi alla Console Firebase.
  2. Fai clic su Aggiungi progetto, quindi seleziona o inserisci un Nome progetto. Assegna al progetto il nome fcm-codelab.
  3. Fai clic su Continua.
  4. Puoi evitare di configurare 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 creato un progetto Firebase, puoi aggiungervi l'app per Android.

  1. Al centro della pagina Panoramica 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 l'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 di Firebase Android alla tua app.

  1. Fai clic su Scarica google-services.json per ottenere il file di configurazione di Firebase Android (google-services.json). Assicurati che il file di configurazione non venga aggiunto con caratteri aggiuntivi e che abbia il nome google-services.json esatto.
  2. Sposta il file di configurazione nella directory del modulo (a livello di app) dell'app.

Passaggio 4: configura il 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 tuo file Gradle a livello di progetto (build.gradle) a livello di progetto, verifica di disporre del repository Maven di Google.
  2. quindi aggiungi le regole per includere il plug-in Servizi 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. Nel file Gradle del tuo modulo (a livello di app, in genere app/build.gradle), aggiungi una riga per applicare il plug-in alla fine del 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 progetto per utilizzare le notifiche push.

Il codice di servizio Android per FCM di questo codelab è fornito in MyFirebaseMessagingService.kt. Nei passaggi seguenti, aggiungerai codice alla tua app Android.

Per verificare l'implementazione, utilizzerai il compositore delle notifiche. Composer è uno strumento che ti consente di scrivere e inviare messaggi dal sito web della Console Firebase.

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

Passaggio 1: invio delle notifiche FCM a un singolo dispositivo

La console 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 di Firebase genera un token nuovo o aggiornato, viene chiamata la funzione onNewToken(), che viene trasferito come argomento. Se vuoi scegliere come target un singolo dispositivo o creare un gruppo di dispositivi a cui vuoi inviare un messaggio di trasmissione, dovrai accedere al token estendendo FirebaseMessagingService e eseguendo l'override di onNewToken().

  1. Apri AndroidManifest.xml e annulla il commento del seguente codice per abilitare MyFirebaseMessagingService per l'app Timer timer. I metadati del servizio nel manifest di Android registrano MyFirebaseMessagingService come servizio e aggiungono un filtro per intent, che riceverà 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, poiché gli utenti potrebbero voler attivare/disattivare separatamente il timer per le uova o le notifiche push FCM.

  1. Apri ui/EggTimerFragment.kt . In onCreateView(), aggiungi il seguente codice per la 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 annulla il commento per la funzione onNewToken(). Questa funzione viene richiamata 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 il timer delle uova.
  2. Osserva logcat (View > Tool Windows > Logcat). Dovresti vedere una riga di log in cui è mostrato il tuo token, simile a quello riportato di seguito. Questo è il token che ti serve 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 di logcat, è possibile che l'app lo abbia già ricevuto in precedenza. In tal caso, la disinstallazione dell'app ti consentirà di ricevere un nuovo token.

Ora puoi testarla inviando una notifica. Per inviare una notifica, dovrai utilizzare il compositore delle notifiche.

  1. Apri la Console Firebase e seleziona il tuo progetto.
  2. Seleziona quindi Cloud Messaging nella barra 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 e seleziona Invia messaggio di prova. Viene visualizzata la finestra di dialogo popup Testa sul dispositivo, in cui ti viene chiesto 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 nella casella di controllo visualizzata. Il pulsante Test dovrebbe diventare attivo.

  1. Sul tuo dispositivo, inserisci l'app Timer uova in sfondo.
  2. Nella finestra popup, fai clic su Testa.
  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ù informazioni su come gestire i messaggi FCM quando la tua app è in primo piano in un secondo momento.

Attività: invio di notifiche FCM a un argomento

I messaggi per argomento di FCM si basano sul modello di pubblicazione/abbonamento.

Un'app di messaggistica può essere un buon esempio per il modello Publish/Abbonati. Immagina che un'app verifichi la presenza di nuovi messaggi ogni 10 secondi. In questo modo, la batteria del telefono non solo si esaurirà, ma verrà utilizzata anche le risorse di rete non necessarie, creando un carico non necessario sul server dell'app. Invece, un dispositivo client può iscriversi e ricevere una notifica quando vengono recapitati nuovi messaggi tramite la tua app.

Argomenti: ti consente di inviare un messaggio a più dispositivi che hanno attivato quell'argomento. Per gli utenti, gli argomenti sono origini dati specifiche a cui il cliente è interessato. 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, ad esempio notizie, previsioni meteo e risultati sportivi. Per questa parte del codelab, creerai un argomento " colazione" per ricordare agli utenti dell'app interessati di mangiare le uova con la loro colazione.

Per iscriversi a un argomento, l'app client chiama la funzione Firebase Cloud Messaging subscribeToTopic() con il nome argomento breakfast. Questa chiamata può avere due risultati. Se il chiamante ha esito positivo, il callback OnCompleteListener verrà chiamato con il messaggio a cui hai effettuato l'iscrizione. Se il cliente non riesce a iscriversi, il callback riceverà un messaggio di errore.

Nell'app, abbonerai automaticamente gli utenti all'argomento della colazione. Nella maggior parte delle app di produzione, tuttavia, è meglio offrire agli utenti il controllo sugli argomenti a cui iscriversi.

  1. Apri EggTimerFragment.kt e trova la funzione subscribeTopic() vuota.
  2. Recupera un'istanza di FirebaseMessaging e chiama la funzione subscibeToTopic() con il nome dell'argomento.
  3. Aggiungi un addOnCompleteListener per ricevere una notifica da FCM in caso di esito positivo o negativo dell'abbonamento.
// 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. Richiama la funzione subscribeTopic() per iscriverti a un argomento all'avvio dell'app. Scorri verso l'alto 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 abbonarti all'argomento della colazione, esegui di nuovo l'app. Dovrebbe essere visualizzato un messaggio toast "Iscritto a argomento".

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

  1. Apri il compositore delle notifichee seleziona Scrivi 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 Target e inserisci breakfast come argomento del messaggio.

  1. Seleziona Adesso per 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 riesci a eseguire l'app su più dispositivi, puoi testare e osservare che la notifica viene ricevuta su tutti i dispositivi iscritti a questo argomento.

Ora l'app ha i seguenti canali per le notifiche: Uovo e Colazione. Sul dispositivo client, fai clic sull'icona dell'app, seleziona Informazioni e fai clic su Notifiche. Dovresti vedere i canali di notifica Uovo e Colazione, come mostrato nel seguente screenshot. Se deselezioni il canale Colazione, l'app non riceverà alcuna notifica inviata su questo canale.

Quando utilizzi le notifiche, ricorda che gli utenti possono disattivare i canali di notifica in qualsiasi momento.

Passaggio 1: messaggi relativi ai dati

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

Per gestire i messaggi di dati, devi gestire il payload dei dati nella funzione onMessageReceived() di MyFirebaseMessagingService. Il payload viene memorizzato nella proprietà data dell'oggetto remoteMessage. Sia l'oggetto remoteMessage sia 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 verificare il codice, puoi utilizzare di nuovo il servizio Notifiche.

  1. Apri il compositore di notifica, crea un nuovo messaggio e imposta il relativo target sull'argomento "Colazione".
  2. Questa volta, quando vai al passaggio 4, in Opzioni aggiuntive, imposta le proprietà chiave e valore personalizzate come segue:
  1. Chiave: eggs
  2. Valore: 3

  1. Assicurati che la tua app sia in esecuzione in primo piano. Se la tua 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 che viene visualizzato in logcat.

Passaggio 2: gestisci i messaggi in primo piano e in background

Quando un dispositivo client che esegue l'app riceve un messaggio che include sia il payload delle notifiche sia i payload di dati, il comportamento dell'app dipende dal fatto che l'app 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 automaticamente visualizzata nella barra delle notifiche. Se il messaggio ha anche un payload dati, quest'ultimo 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, questa non verrà visualizzata automaticamente. L'app deve decidere come gestire la notifica nella funzione onMessageReceived(). Se il messaggio contiene anche payload, entrambi verranno gestiti dall'app.

Ai fini di questo codelab, vuoi ricordare all'utente dell'app di bere delle uova per la colazione. Non hai intenzione di inviare dati, ma vuoi anche che venga sempre visualizzata la notifica di promemoria, 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 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, ma deciderà che 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 automaticamente i payload di notifiche e 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. Riapri la funzione onMessageReceived() in MyFirebaseMessagingService.
  2. Subito dopo il codice aggiunto di recente per controllare il messaggio dei 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 vedere una notifica esattamente come hai visto 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 Firebase:

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