開始在 Android 應用程式中使用 Firebase 雲端通訊

選取平台: iOS+ Android 網頁 Flutter Unity C++


本指南說明如何在 Android 用戶端應用程式中開始使用 Firebase Cloud Messaging,以便穩定傳送訊息。

FCM 用戶端必須使用搭載 Android 6.0 以上版本的裝置,且裝置已安裝 Google Play 商店應用程式,或是使用搭載 Android 6.0 和 Google API 的模擬器。請注意,您不一定要透過 Google Play 商店部署 Android 應用程式。

設定 SDK

如果您尚未將 Firebase 新增至 Android 專案,請先新增。

為獲得最佳 FCM 體驗,強烈建議您在專案中啟用 Google AnalyticsGoogle AnalyticsFCM訊息傳送 報表必要條件。

編輯應用程式資訊清單

在應用程式的資訊清單中新增下列內容:

  • 擴充 FirebaseMessagingService 的服務。如果您想在應用程式於背景執行時,處理通知以外的訊息,就必須這麼做。如要在前景應用程式中接收通知、接收資料酬載等,您必須擴充這項服務。
  • <service
        android:name=".java.MyFirebaseMessagingService"
        android:exported="false">
        <intent-filter>
            <action android:name="com.google.firebase.MESSAGING_EVENT" />
        </intent-filter>
    </service>
  • (選用) 在應用程式元件中,中繼資料元素可設定預設通知圖示和顏色。如果傳入的訊息未明確設定圖示或顏色,Android 就會使用這些值。
  • <!-- 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/ic_stat_ic_notification" />
    <!-- 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" />
  • (選用) 從 Android 8.0 (API 級別 26) 以上版本開始,系統支援並建議使用 通知管道FCM 提供具有基本設定的預設通知管道。如要 建立及使用自己的預設管道,請將 default_notification_channel_id 設為通知管道物件的 ID,如圖所示;每當傳入訊息未明確設定通知管道時,FCM 就會使用這個值。詳情請參閱「 管理通知管道」。
  • <meta-data
        android:name="com.google.firebase.messaging.default_notification_channel_id"
        android:value="@string/default_notification_channel_id" />

在 Android 13 以上版本要求執行階段通知權限

Android 13 導入了新的執行階段權限,可顯示通知。這項異動會影響在 Android 13 以上版本上執行的所有應用程式,這些應用程式都會使用FCM通知。

根據預設,FCM SDK (23.0.6 以上版本) 包含資訊清單中定義的 POST_NOTIFICATIONS 權限。不過,您的應用程式也需要使用常數 android.permission.POST_NOTIFICATIONS,要求這個權限的執行階段版本。使用者授予這項權限後,應用程式才能顯示通知。

如要要求新的執行階段權限,請按照下列步驟操作:

Kotlin

// Declare the launcher at the top of your Activity/Fragment:
private val requestPermissionLauncher = registerForActivityResult(
    ActivityResultContracts.RequestPermission(),
) { isGranted: Boolean ->
    if (isGranted) {
        // FCM SDK (and your app) can post notifications.
    } else {
        // TODO: Inform user that that your app will not show notifications.
    }
}

private fun askNotificationPermission() {
    // This is only necessary for API level >= 33 (TIRAMISU)
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) ==
            PackageManager.PERMISSION_GRANTED
        ) {
            // FCM SDK (and your app) can post notifications.
        } else if (shouldShowRequestPermissionRationale(Manifest.permission.POST_NOTIFICATIONS)) {
            // TODO: display an educational UI explaining to the user the features that will be enabled
            //       by them granting the POST_NOTIFICATION permission. This UI should provide the user
            //       "OK" and "No thanks" buttons. If the user selects "OK," directly request the permission.
            //       If the user selects "No thanks," allow the user to continue without notifications.
        } else {
            // Directly ask for the permission
            requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)
        }
    }
}

Java

// Declare the launcher at the top of your Activity/Fragment:
private final ActivityResultLauncher<String> requestPermissionLauncher =
        registerForActivityResult(new ActivityResultContracts.RequestPermission(), isGranted -> {
            if (isGranted) {
                // FCM SDK (and your app) can post notifications.
            } else {
                // TODO: Inform user that that your app will not show notifications.
            }
        });

private void askNotificationPermission() {
    // This is only necessary for API level >= 33 (TIRAMISU)
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) ==
                PackageManager.PERMISSION_GRANTED) {
            // FCM SDK (and your app) can post notifications.
        } else if (shouldShowRequestPermissionRationale(Manifest.permission.POST_NOTIFICATIONS)) {
            // TODO: display an educational UI explaining to the user the features that will be enabled
            //       by them granting the POST_NOTIFICATION permission. This UI should provide the user
            //       "OK" and "No thanks" buttons. If the user selects "OK," directly request the permission.
            //       If the user selects "No thanks," allow the user to continue without notifications.
        } else {
            // Directly ask for the permission
            requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS);
        }
    }
}

一般來說,您應顯示 UI,向使用者說明授予應用程式發布通知的權限後,會啟用哪些功能。這個 UI 應提供同意或拒絕選項,例如「確定」和「謝謝,不必了」按鈕。如果使用者選取「確定」,請直接要求權限。 如果使用者選取「不用了,謝謝」,請允許使用者在不接收通知的情況下繼續。

如要進一步瞭解應用程式何時應向使用者要求 POST_NOTIFICATIONS 權限,請參閱「通知執行階段權限」一文中的最佳做法。

目標為 Android 12L (API 級別 32) 以下版本的應用程式通知權限

只要應用程式在前台運作,Android 就會在應用程式首次建立通知管道時,自動要求使用者授予權限。不過,關於頻道建立時間和權限要求,有幾項重要注意事項:

  • 如果應用程式在背景執行時建立第一個通知管道 (FCM SDK 收到 FCM 通知時會這麼做),Android 不會允許顯示通知,也不會提示使用者授予通知權限,直到下次開啟應用程式時才會提示。也就是說,如果使用者未開啟應用程式並接受權限,就無法收到任何通知。
  • 強烈建議您更新應用程式,以 Android 13 以上版本為目標,充分運用平台 API 要求權限。如果無法這麼做,應用程式應先建立通知管道,再傳送任何通知給應用程式,以便觸發通知權限對話方塊,確保不會遺失任何通知。詳情請參閱通知權限最佳做法

選用步驟:移除 POST_NOTIFICATIONS 權限

根據預設,FCM SDK 包含 POST_NOTIFICATIONS 權限。如果您的應用程式未使用通知訊息 (無論是透過 FCM 通知、其他 SDK,還是直接由應用程式發布),且您不希望應用程式包含這項權限,可以使用資訊清單合併工具remove 標記移除權限。請注意,移除這項權限後,系統會禁止顯示所有通知,而不只是 FCM 通知。在應用程式的資訊清單檔案中新增下列內容:

<uses-permission android:name="android.permission.POST_NOTIFICATIONS" tools:node="remove"/>

存取 Firebase 安裝 ID

應用程式首次啟動時,FCM SDK 會向 FCM 註冊應用程式執行個體,並傳回應用程式執行個體的 ID。如要指定個別應用程式例項,您需要擴充 FirebaseMessagingService 並覆寫 onRegistered(),才能存取這個 ID。 最佳做法是擷取最新更新的 ID,因為 ID 可能會在初始啟動後輪替。

透過 Firebase 安裝 ID 啟用註冊

如要使用 Firebase 安裝 ID (FID)FCM 註冊應用程式例項,請在 AndroidManifest.xml 檔案中新增下列中繼資料標記:
<meta-data
    android:name="firebase_messaging_installation_id_enabled"
    android:value="true" />

實作 onRegistered() 回呼

應用程式執行個體向 FCM 註冊後,系統就會使用 Firebase 安裝 ID (FID) 指定目標。如要在註冊時擷取 FID,請實作 onRegistered() 回呼。 註冊應用程式例項後,FCM SDK 會自動監控 FID 變更,並在偵測到變更時叫用回呼。 啟用自動初始化後,FCM SDK 會自動與 FCM 後端同步,確保註冊資訊為最新狀態,並叫用回呼,確保應用程式伺服器擁有目前的 ID。為避免 FID 遺失或過時,每當觸發這個回呼時,您都應將 FID 傳送至應用程式伺服器。

Kotlin

  /**
   * There are three scenarios when `onRegistered` is called:
   * 1) Every time a manual `register()` call finishes successfully
   * 2) Whenever the FID is changed and the app is re-registered with FCM via the new FID.
   * 3) Automatically on app startup or routine sync when auto-initialization is enabled.
   * Under #2, there are three scenarios when the existing FID is changed:
   * A) App is restored to a new device
   * B) User uninstalls/reinstalls the app
   * C) User clears app data
   */
  override fun onRegistered(installationId: String) {
      Log.d(TAG, "Registered installation ID: $installationId")

      // Send the Firebase Installation ID to your app server.
      sendRegistrationToServer(installationId)
  }
    

Java

  /**
   * There are three scenarios when `onRegistered` is called:
   * 1) Every time a manual `register()` call finishes successfully
   * 2) Whenever the FID is changed and the app is re-registered with FCM via the new FID
   * 3) Automatically on app startup or routine sync when auto-initialization is enabled.
   * Under #2, there are three scenarios when the existing FID is changed:
   * A) App is restored to a new device
   * B) User uninstalls/reinstalls the app
   * C) User clears app data
   */
  @Override
  public void onRegistered(@NonNull String installationId) {
      Log.d(TAG, "Registered installation ID: " + installationId);

      // Send the Firebase Installation ID to your app server.
      sendRegistrationToServer(installationId);
  }
    

停用自動初始化時,請手動註冊

如果必須停用自動初始化,FCM SDK 就不會在啟動時自動同步或觸發 onRegistered() 回呼。強烈建議授予通知權限後,重新啟用自動初始化。詳情請參閱「 重新啟用自動初始化」。

如果必須停用自動初始化,請在應用程式啟動時呼叫 FirebaseMessaging.getInstance().register(),透過 onRegistered() 回呼觸發註冊程序並傳送 FID。您可以在主要 Activity onCreate() 方法中執行這項呼叫。

Kotlin

  // Trigger manual registration if auto-initialization is turned off.
  // Consider calling this every time the app starts to guarantee sync status.
  FirebaseMessaging.getInstance().register()
      .addOnCompleteListener(this) { task ->
        if (!task.isSuccessful()) {
          // Registration failed. Consider retrying the registration with exponential backoff.
          Log.w(TAG, "Failed to register with Firebase Cloud Messaging", task.exception)
        }
        // Success! The Firebase Installation ID can be used to target messages to this app
        // instance and will be delivered asynchronously to your `onRegistered()` callback.
      }
    

Java

  // Trigger manual registration if auto-initialization is turned off.
  // Consider calling this every time the app starts to guarantee sync status.
  FirebaseMessaging.getInstance().register()
      .addOnCompleteListener(task -> {
        if (!task.isSuccessful()) {
          // Registration failed. Consider retrying the registration with exponential backoff.
          Log.w(TAG, "Failed to register with Firebase Cloud Messaging", task.exception)
        }
        // Success! The Firebase Installation ID can be used to target messages to this app
        // instance and will be delivered asynchronously to your `onRegistered()` callback.
      });
    

存取 FCM 註冊權杖 (已淘汰)

應用程式首次啟動時,FCM SDK 會為用戶端應用程式執行個體產生註冊權杖。如要指定單一應用程式例項或建立裝置群組,您需要透過擴充 FirebaseMessagingService 並覆寫 onNewToken,存取這個權杖。因為權杖可能會在初始啟動後輪替,強烈建議您擷取最新的更新註冊權杖。

在下列情況下,註冊權杖可能會變更:

  • 應用程式已在新裝置上還原
  • 使用者解除安裝/重新安裝應用程式
  • 使用者清除應用程式資料。

擷取目前的註冊權杖

如要擷取目前權杖,請呼叫 FirebaseMessaging.getInstance().getToken()

Kotlin

FirebaseMessaging.getInstance().token.addOnCompleteListener(OnCompleteListener { task ->
    if (!task.isSuccessful) {
        Log.w(TAG, "Fetching FCM registration token failed", task.exception)
        return@OnCompleteListener
    }

    // Get new FCM registration token
    val token = task.result

    // Log and toast
    val msg = getString(R.string.msg_token_fmt, token)
    Log.d(TAG, msg)
    Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show()
})

Java

FirebaseMessaging.getInstance().getToken()
    .addOnCompleteListener(new OnCompleteListener<String>() {
        @Override
        public void onComplete(@NonNull Task<String> task) {
          if (!task.isSuccessful()) {
            Log.w(TAG, "Fetching FCM registration token failed", task.getException());
            return;
          }

          // Get new FCM registration token
          String token = task.getResult();

          // Log and toast
          String msg = getString(R.string.msg_token_fmt, token);
          Log.d(TAG, msg);
          Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show();
        }
    });

監控權杖生成作業

每當產生新權杖時,系統就會觸發 onNewToken 回呼。

Kotlin

/**
 * Called if the FCM registration token is updated. This may occur if the security of
 * the previous token had been compromised. Note that this is called when the
 * FCM registration 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
    // FCM registration token to your app server.
    sendRegistrationToServer(token)
}

Java

/**
 * There are two scenarios when onNewToken is called:
 * 1) When a new token is generated on initial app startup
 * 2) Whenever an existing token is changed
 * Under #2, there are three scenarios when the existing token is changed:
 * A) App is restored to a new device
 * B) User uninstalls/reinstalls the app
 * C) User clears app data
 */
@Override
public void onNewToken(@NonNull String token) {
    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
    // FCM registration token to your app server.
    sendRegistrationToServer(token);
}

取得權杖後,您可以將權杖傳送至應用程式伺服器,並使用偏好的方法儲存權杖。

檢查 Google Play 服務

如果應用程式使用 Play 服務 SDK,存取 Google Play 服務功能前,請務必先檢查裝置是否安裝相容的 Google Play 服務 APK。詳情請參閱「設定 Google Play 服務」一文。建議在兩個位置執行這項操作:主要活動的 onCreate() 方法,以及其 onResume() 方法。onCreate() 中的檢查可確保應用程式必須通過檢查才能使用。onResume() 中的檢查可確保使用者透過其他方式返回執行中的應用程式 (例如透過返回按鈕) 時,系統仍會執行檢查。

如果裝置沒有相容版本的 Google Play 服務,應用程式可以呼叫 GoogleApiAvailability.makeGooglePlayServicesAvailable(),讓使用者從 Play 商店下載 Google Play 服務。

防止自動初始化

產生 FCM 註冊時,程式庫會將 ID 和設定資料上傳至 Firebase。如要避免自動註冊,請停用 Analytics 收集功能和 FCM 自動初始化功能 (必須同時停用這兩項功能),方法是在 AndroidManifest.xml 中加入下列中繼資料值:

<meta-data
    android:name="firebase_messaging_auto_init_enabled"
    android:value="false" />
<meta-data
    android:name="firebase_analytics_collection_enabled"
    android:value="false" />

重新啟用自動初始化

如要重新啟用 FCM 自動初始化功能,請進行執行階段呼叫:

Kotlin

Firebase.messaging.isAutoInitEnabled = true

Java

FirebaseMessaging.getInstance().setAutoInitEnabled(true);

如要重新啟用 Analytics 收集功能,請呼叫 FirebaseAnalytics 類別的 setAnalyticsCollectionEnabled() 方法。例如:

setAnalyticsCollectionEnabled(true);

設定完成後,這些值會在應用程式重新啟動時保留。

傳送通知訊息

如要確認 Android 用戶端設定是否正確,請按照下列操作說明傳送測試通知訊息:

  1. 在目標裝置上安裝並執行應用程式。

  2. 確認裝置上的應用程式在背景執行。

  3. Firebase 控制台中,依序前往「DevOps & Engagement」(開發運作與參與度) >「Messaging」(訊息)

  4. 建立廣告活動。

    • 如果這是您的第一則訊息:

      1. 選取「建立第一個廣告活動」

      2. 選取「Firebase 通知訊息」,然後選取「建立」

    • 如果您先前已建立廣告活動:

      1. 在「廣告活動」分頁中,選取「新增廣告活動」

      2. 按一下「通知」

  5. 輸入訊息文字。其他欄位則為選填。

  6. 在右側窗格中選取「傳送測試訊息」

  7. 在標示為「新增 FCM 註冊權杖」的欄位中,輸入您在本指南先前章節中取得的註冊權杖。

  8. 選取「測試」

目標用戶端裝置應會收到通知,且應用程式必須在背景執行。

如要深入瞭解訊息傳送至應用程式的情形,請前往 Firebase 控制台的「DevOps 和參與度」&gt;「訊息」&gt;「報告」資訊主頁。這個資訊主頁會記錄在 Apple 和 Android 裝置上傳送及開啟的訊息數量,以及 Android 應用程式的「曝光次數」(使用者看到的通知) 資料。

後續步驟

完成設定步驟後,您可以選擇以下幾種方式繼續使用 Android 版 FCM