Kotlin 01.2 中的進階 Android:Android Firebase 通信

本程式碼研究室是 Kotlin 進階課程的一部分。只要您按部就班完成程式碼研究室,就能發揮本課程的最大效益。不過,您不一定要這麼做。所有課程程式碼研究室清單均列於進階 Android 版的 Kotlin 程式碼研究室到達網頁中。

引言

先前的程式碼研究室中,您已在應用程式裡建立並啟動的 Doodle 計時器通知。另一個重要的通知用途,就是在應用程式未運作的情況下,從遠端傳送推播通知。

什麼是推播通知?

推播通知則是伺服器「推送」至行動裝置的通知。無論應用程式是否正在執行,都可發送至裝置。

推播通知是通知使用者更新或提醒使用者完成工作或功能的絕佳方式。假設您已經等候產品有現貨。有了購物通知,購物應用程式就能顯示股票最新資訊,您不用每天查看庫存狀態。

推播通知會使用發布/訂閱模式,讓後端應用程式能夠將相關內容推送給感興趣的客戶。如果沒有發布/訂閱模式,應用程式的使用者就必須定期檢查您的應用程式是否有更新內容。這項程序相當繁瑣且不可靠。此外,隨著客戶人數增加,這些定期檢查會對網路和伺服器資源的負載和資源資源造成太大的負擔。

如同其他類型的通知,請務必透過推播通知告知使用者。如果通知內容不有趣或及時對使用者顯示,使用者可以輕鬆關閉應用程式中的所有通知。

什麼是 Firebase 雲端通訊?

Firebase 雲端通訊是 Firebase 行動裝置開發的一部分。一般而言,您需要從頭設定伺服器,以便與行動裝置進行通訊以觸發通知。有了 Firebase 雲端通訊功能,您不必設定伺服器,就能將通知傳送給所有已安裝的應用程式使用者,或是部分使用者。舉例來說,您可以向使用者傳送提醒或提供特別促銷活動,例如免費贈禮。您可以從遠端將通知傳送到單一裝置或多部裝置。

您也可以使用 Firebase Cloud Messages 將資料從後端應用程式或 Firebase 專案傳輸給使用者。

在本程式碼研究室中,您將瞭解如何使用 Firebase 雲端通訊來傳送 Android 應用程式的推播通知以及傳送資料。

使用本程式碼研究室時,如果遇到任何問題 (程式碼錯誤、文法錯誤、措辭不明確等),請透過程式碼研究室左下角的 [回報錯誤] 連結回報問題。

須知事項

您應該很熟悉:

  • 如何在 Kotlin 中建立 Android 應用程式。(尤其是 Android SDK) 的運作方式。
  • 如何使用架構元件和資料繫結設計應用程式。
  • 瞭解廣播接收者的基本知識。
  • 瞭解 AlarmManager 的基本知識。
  • 如何使用 NotificationManager 建立和傳送通知。

課程內容

  • 如何透過 Firebase 雲端通訊推送訊息給使用者。
  • 如何使用資料訊息從後端傳送資料至應用程式,這是 Firebase 雲端通訊的一部分。

執行步驟

  • 在啟動應用程式中加入推播通知。
  • 在應用程式執行期間處理 Firebase 雲端通訊。
  • 使用 Firebase 雲端通訊來轉移資料。

在本程式碼研究室中,您將參考先前的 Android Android 應用程式通知程式程式碼的程式碼。在先前的程式碼研究室中,您建構了一個蛋計時器計時器應用程式,會在烹飪計時器響起時傳送通知。在這個程式碼研究室中,您將加入 Firebase 雲端通訊功能來傳送推播通知給應用程式使用者,提醒他們吃雞蛋。

如要取得範例應用程式,您可以採取下列其中一種做法:

從 GitHub 複製存放區並切換至 starter 分支版本:

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


或者,您也可以將存放區下載為 ZIP 檔案,然後解壓縮,然後在 Android Studio 中開啟該檔案。

下載 Zip

步驟 1:建立 Firebase 專案

您必須建立 Firebase 專案才能連結至您的 Android 應用程式,才能將 Firebase 新增至 Android 應用程式。

  1. 登入 Firebase 主控台
  2. 按一下 [新增專案],然後選取或輸入專案名稱。將專案命名為 fcm-codelab
  3. 按一下 [繼續]
  4. 您可以關閉 [為這項專案啟用 Google Analytics (分析)] 按鈕,略過 Google Analytics (分析) 的設定程序。
  5. 按一下 [建立專案] 即可完成 Firebase 專案設定程序。

步驟 2:使用 Firebase 註冊應用程式

現在,您已經有 Firebase 專案了,可以將 Android 應用程式加進該專案了。

  1. Firebase 主控台的「專案總覽」頁面中央,按一下 Android 圖示即可啟動設定工作流程。

  1. 在 [Android 套件名稱] 欄位中輸入 com.example.android.eggtimernotifications
  2. 按一下 [Register app] (註冊應用程式)

重要事項:在您透過 Firebase 專案註冊應用程式後,無法新增或修改這個值,請務必輸入正確的應用程式 ID。

步驟 3:將 Firebase 設定檔新增至專案

將 Firebase Android 設定檔新增至您的應用程式。

  1. 點選 [下載 google-services.json] 即可取得 Firebase Android 設定檔 (google-services.json)。請確定您的設定檔沒有附加其他字元,且名稱是 google-services.json
  2. 將設定檔移至應用程式的模組 (應用程式層級) 目錄中。

步驟 4:設定 Android 專案以啟用 Firebase 產品

如要在應用程式中啟用 Firebase 產品,您必須在 Gradle 檔案中加入 google-services 外掛程式

  1. 在您的根層級 (專案層級) Gradle 檔案 (build.gradle) 中,檢查您是否擁有 Google 的 Maven 存放區。
  2. 然後新增規則來加入 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. 在您的模組 (應用程式層級) Gradle 檔案 (通常是 app/build.gradle) 中新增一行,將外掛程式套用至檔案底部。

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

在這項工作中,您將將 Firebase 雲端通訊 (FCM) 新增到專案中,以使用推播通知。

這個程式碼研究室的 FCM Android 版服務代碼位於 MyFirebaseMessagingService.kt。請按照下列步驟在 Android 應用程式中加入程式碼。

您將使用通知撰寫器來測試實作結果。通知撰寫工具可協助您從 Firebase 主控台網站撰寫及傳送訊息。

  1. 開啟 MyFirebaseMessagingService.kt
  2. 檢查檔案,尤其是下列函式:
  • onNewToken():如果您的服務已在 Android 資訊清單中完成註冊,系統會自動呼叫服務。您第一次執行應用程式時,每當 Firebase 為您的應用程式發出新「憑證」,系統就會呼叫此函式。「憑證」是 Firebase 後端專案的存取金鑰。是系統為特定用戶端裝置產生的 ID。透過這個符記,Firebase 會知道後端應向哪個用戶端傳送訊息。Firebase 也會知道這個用戶端是否有效,而且可以存取這個 Firebase 專案。
  • onMessageReceived:當應用程式執行,且 Firebase 傳送訊息給您的應用程式時,就會呼叫此函式。此函式可接收 RemoteMessage 物件,其中包含可發出通知或資料訊息酬載。本程式碼研究室將進一步說明通知和資料訊息酬載之間的差異。

步驟 1:傳送 FCM 通知至單一裝置

通知主控台可讓您測試傳送通知。如要透過主控台傳送訊息到特定裝置,您必須先知道裝置的註冊憑證。

當 Firebase 後端產生新符記或更新符記時,系統會呼叫 onNewToken() 函式,並將新符記做為引數傳入。如要指定單一裝置,或建立要傳送廣播訊息的裝置群組,則必須延伸 FirebaseMessagingService 並覆寫 onNewToken(),以存取這個權杖。

  1. 開啟 AndroidManifest.xml 並取消註解下列程式碼,即可為雞蛋計時器應用程式啟用 MyFirebaseMessagingService。Android 資訊清單中的服務中繼資料會註冊 MyFirebaseMessagingService 做為服務並新增意圖篩選器,以便這項服務接收 FCM 傳送的訊息。中繼資料的最後部分將 breakfast_notification_channel_id 宣告為 Firebase for default_notification_channel_id。您會在下一個步驟中使用這個編號。
<!-- 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] -->

建議您為 FCM 建立新的通知管道,因為使用者可能想個別啟用/停用雞蛋計時器或 FCM 推播通知。

  1. 開啟 ui/EggTimerFragment.kt。在 onCreateView() 中,新增下列管道建立程式碼。
// 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. 開啟 MyFirebaseMessagingService.kt 並取消對 onNewToken() 函式的註解。產生新的憑證時,系統就會呼叫此函式。
// 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. 執行雞蛋計時器應用程式。
  2. 觀察 logcat (View > Tool Windows > Logcat)。系統應該會顯示與下方憑證類似的記錄行。這是傳送訊息到這個裝置所需的憑證。只有在建立新符記時,才會呼叫此函式。
2019-07-23 13:09:15.243 2312-2459/com.example.android.eggtimernotifications D/MyFirebaseMsgService: Refreshed token: f2esflBoQbI:APA91bFMzNNFaIskjr6KIV4zKjnPA4hxekmrtbrtba2aDbh593WQnm11ed54Mv6MZ9Yeerver7pzgwfKx7R9BHFffLBItLEgPvrtF0TtX9ToCrXZ5y7Hd-m

注意:如果 Logcat 訊息未顯示憑證,表示應用程式可能先前曾收到該權杖。在這種情況下,解除安裝該應用程式有助於您接收新的憑證。

現在您可以傳送通知來進行測試。如要傳送通知,請使用通知撰寫工具

  1. 開啟 Firebase 主控台並選取您的專案。
  2. 然後選取左側導覽列中的 [雲端通訊]
  3. 按一下 [傳送您的第一則訊息]

  1. 輸入 Time for Breakfast! 做為通知標題,並輸入 Don't forget to eat eggs! 做為通知文字,然後選取 [傳送測試郵件]。「測試裝置」彈出式視窗隨即顯示,要求您提供 FCM 註冊憑證。

  1. 從 logcat 複製您的應用程式權杖。

  1. 請將這個憑證貼到彈出式視窗的 [新增 FCM 註冊憑證] 欄位中,然後按一下憑證旁邊的 [新增] 按鈕。
  2. 在隨即顯示的核取方塊清單中,選取憑證。「Test」(測試) 按鈕應會啟用。

  1. 在裝置上將 Egg Timer 應用程式設為背景
  2. 在彈出式視窗中按一下 [測試]
  1. 按下 [測試] 後,指定在背景執行應用程式的用戶端裝置應會在系統通知匣中收到通知。(您將在應用程式於前景執行時,會更瞭解 FCM 訊息的處理方式)。

工作:將 FCM 通知傳送至主題

FCM 主題訊息是以發布/訂閱模式為基礎。

訊息應用程式是發布/訂閱模型的良好範例。假設應用程式每 10 秒會檢查有無新訊息。這樣不僅會耗盡手機電池電力,還會耗用不必要的網路資源,並造成應用程式伺服器負載不必要的負載。用戶端裝置則可訂閱通知,並在您的應用程式收到新訊息時通知您。

主題可讓您將訊息傳送到已選擇該主題的多部裝置上。對客戶而言,主題是客戶感興趣的特定資料來源。對伺服器來說,主題是一組裝置,其已選擇接收特定資料來源的更新。主題可用來顯示通知類別,例如新聞、天氣預報和運動賽事結果。在這個程式碼研究室的這個環節中,您將建立「突破」主題,提醒感興趣的應用程式使用者,在吃早餐的同時吃雞蛋。

如要「訂閱」主題,用戶端應用程式會呼叫 Firebase 雲端通訊 subscribeToTopic() 函式,並將主題名稱設為「breakfast」。這場通話有兩項結果。如果呼叫成功,系統會透過已訂閱的訊息呼叫 OnCompleteListener 回呼。如果用戶端無法訂閱,回呼將會收到錯誤訊息。

在應用程式中,使用者會自動訂閱早餐主題。然而,在大多數的正式版應用程式中,最好讓使用者自行決定要訂閱的主題。

  1. 開啟 EggTimerFragment.kt 並找到空白的 subscribeTopic() 函式。
  2. 取得 FirebaseMessaging 的執行個體,並呼叫主題名稱的 subscibeToTopic() 函式。
  3. 新增 addOnCompleteListener 來接收 FCM 通知訂閱成功或失敗的通知。
// 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. 啟動應用程式後,呼叫 subscribeTopic() 函式即可訂閱主題。向上捲動至 onCreateView(),然後為 subscribeTopic() 加入通話。
// EggTimerFragment.kt

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

    return binding.root
  1. 如要訂閱早餐主題,請再次執行應用程式。你應該看見吐司烤訊息,說「已訂閱主題」。

您現在可以測試傳送郵件至某個主題:

  1. 開啟通知撰寫器並選取 [撰寫通知]
  2. 將通知的「通知標題」和「通知文字」設為以往狀態。
  3. 此時,請不要傳送郵件到單一裝置,而是按一下「Target」(目標) 下方的 [Topic] (主題),然後輸入 breakfast 做為訊息主題。

  1. 在「排程」部分選取 [現在]

  1. 在測試裝置上,確認應用程式在背景執行。
  1. 依序點選 [檢閱] 和 [發布]。如果應用程式可以在多部裝置上執行,您可以測試並觀察訂閱此主題的所有裝置是否都會收到通知。

這個應用程式現在已針對下列管道提供通知管道:早餐。在用戶端裝置上,長按應用程式圖示並選取 [資訊],然後點選 [通知]。您應該會看到「Egg」和「Breakfast」通知管道,如以下螢幕截圖所示。如果您取消選取 [Breakfast] 頻道,您的應用程式將不會收到透過這個頻道傳送的任何通知。

使用通知時,請記住使用者可以隨時關閉任何通知管道。

步驟 1:資料訊息

FCM 訊息也可以包含處理用戶端應用程式訊息的資料酬載,並且使用資料訊息而非通知訊息。

您必須處理 MyFirebaseMessagingServiceonMessageReceived() 函式中的資料酬載,才能處理資料訊息。酬載儲存在 remoteMessage 物件的 data 屬性中。remoteMessage 物件和 data 屬性可以是 null

  1. 開啟「MyFirebaseMessagingService.
  2. 請檢查 remoteMessage 物件的 data 屬性是否有一些值,並將資料列印至記錄中。
// 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]

如要測試程式碼,您可以再次使用通知撰寫器

  1. 開啟通知撰寫器,建立新訊息,將其「目標」設為「休息時間」主題。
  2. 此時,當您進入步驟 4 的「其他選項」時,請設定自訂資料鍵和值屬性,如下所示:
  1. 鍵:eggs
  2. 值:3

  1. 確認應用程式是在前景執行。如果您的應用程式在背景執行,FCM 訊息將觸發自動通知,且 onMessageReceived() 函式只會在使用者點擊通知時收到 remoteMessage 物件。
  2. 透過通知撰寫工具傳送訊息,並觀察 Logcat 中顯示的資料訊息記錄。

步驟 2:處理前景和背景中的郵件

當執行應用程式的用戶端裝置收到包含通知和資料酬載的訊息時,應用程式的行為將取決於應用程式是否在背景運作或於前景運作:

  • 如果應用程式正在背景執行,當訊息有通知酬載時,通知就會自動顯示在通知匣中。如果訊息也包含資料酬載,應用程式會在使用者輕觸通知時處理資料酬載。
  • 如果應用程式是在前景執行,如果訊息通知含有通知酬載,則通知將自動不顯示。應用程式必須決定如何處理 onMessageReceived() 函式中的通知。如果訊息也包含資料酬載,應用程式將同時處理這兩項酬載。

以這個程式碼研究室為例,你想提醒應用程式使用者想吃早餐。您沒有要傳送任何資料,但也想要確保隨時會顯示提醒通知,無論應用程式是位於前景或背景中都一樣。

您將 FCM 訊息傳送至已安裝「雞蛋計時器」應用程式的裝置時,若裝置未運作或在背景中執行,系統將自動顯示通知訊息。不過,如果應用程式在前景執行,系統就不會顯示通知;而是透過應用程式的程式碼決定要如何處理訊息。如果應用程式在接收 FCM 訊息時於前景執行,系統會使用 FCM 訊息自動觸發 onMessageReceived() 函式。您的應用程式可以在無訊息的情況下處理通知和資料酬載,或觸發通知。

以應用程式來說,您希望確保應用程式在前景執行提醒時能收到提醒,因此請導入一些程式碼來觸發通知:

  1. MyFirebaseMessagingService 中再次開啟 onMessageReceived() 函式。
  2. 針對您最近新增的程式碼檢查資料訊息後,立即加入下列程式碼,透過通知架構傳送通知。
// 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. 如果您再次執行應用程式,並使用「通知」撰寫器傳送通知,則無論應用程式是在前景或背景中運作,系統一律會在程式碼研究室的第一部分顯示通知。

此解決方案程式碼位於您下載的程式碼的主要分支版本中。

Udacity 課程:

Firebase 說明文件:

如要瞭解本課程中其他程式碼研究室的連結,請參閱進階 Android 版 Kotlin 程式碼研究室到達網頁