在 Android 上設定 Firebase Cloud Messaging 用戶端應用

FCM 用戶端需要運行 Android 4.4 或更高版本並安裝了 Google Play Store 應用程式的設備,或運行帶有 Google API 的 Android 4.4 的模擬器。請注意,您不僅限於透過 Google Play 商店部署 Android 應用程式。

設定SDK

如果您已經為您的應用程式啟用了其他 Firebase 功能,本部分將介紹您可能已完成的任務。如果您尚未將 Firebase 新增至您的 Android 專案中

編輯您的應用程式清單

將以下內容新增至應用程式的清單:

  • 擴充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+KTX

// 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"/>

訪問設備註冊令牌

在應用程式首次啟動時,FCM SDK 會為客戶端應用程式實例產生註冊令牌。如果您想要定位單一裝置或建立裝置群組,則需要透過擴充FirebaseMessagingService並覆蓋onNewToken來存取此令牌。

本節介紹如何檢索令牌以及如何監視令牌的變更。由於令牌在首次啟動後可能會輪換,因此強烈建議您檢索最新更新的註冊令牌。

註冊令牌可能會在以下情況下變更:

  • 該應用程式已在新設備上恢復
  • 用戶卸載/重新安裝應用程式
  • 用戶清除應用程式資料。

檢索目前註冊令牌

當您需要檢索目前令牌時,請呼叫FirebaseMessaging.getInstance().getToken()

Kotlin+KTX

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+KTX

/**
 * 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 Services SDK 的應用程式應始終在存取 Google Play 服務功能之前檢查裝置是否有相容的 Google Play 服務 APK。建議在兩個地方執行此操作:在主活動的onCreate()方法中和在其onResume()方法中。 onCreate()中的檢查可確保在檢查成功的情況下無法使用應用程式。 onResume()中的檢查確保如果使用者透過其他方式(例如透過後退按鈕)返回到正在運行的應用程序,仍然會執行檢查。

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

防止自動初始化

產生 FCM 註冊令牌後,程式庫會將識別碼和設定資料上傳到 Firebase。如果您希望阻止令牌自動生成,請透過將這些元資料值新增至AndroidManifest.xml來停用 Analytics 收集和 FCM 自動初始化(您必須停用兩者):

<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+KTX

Firebase.messaging.isAutoInitEnabled = true

Java

FirebaseMessaging.getInstance().setAutoInitEnabled(true);

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

setAnalyticsCollectionEnabled(true);

設定後,這些值將在應用程式重新啟動後持續存在。

下一步

設定客戶端應用程式後,您就可以開始使用通知編輯器發送下游訊息了。快速入門範例中演示了此功能,您可以下載、運行和查看該範例。

若要為應用程式新增其他更進階的行為,您可以聲明意圖過濾器並實作一個活動來回應傳入訊息。有關詳細信息,請參閱從應用程式伺服器發送訊息的指南:

請記住,要利用這些功能,您需要伺服器實作和伺服器協定(HTTP 或 XMPP),或Admin SDK的實作。