在 Android 上設定 Firebase 雲端通訊用戶端應用程式

FCM 用戶端要求的裝置必須搭載 Android 4.4 以上版本,且已安裝 Google Play 商店應用程式,或是模擬器搭配 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 應為使用者提供同意或拒絕的選項,例如「OK」和「No 這個選項」按鈕。如果使用者選取「確定」,請直接要求權限。如果使用者選取「不用了,謝謝」,請允許使用者在不接收通知的情況下繼續操作。

如要進一步瞭解應用程式何時應要求使用者提供 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 服務 SDK 的應用程式應一律先檢查裝置是否含有相容的 Google Play 服務 APK,再存取 Google Play 服務功能。建議您在兩個地方執行此操作:在主要活動的 onCreate() 方法和其 onResume() 方法中執行這項操作。onCreate() 中的檢查可確保在未成功檢查的情況下才能使用應用程式。onResume() 中的檢查功能可確保如果使用者透過其他方式 (例如透過返回按鈕) 返回執行中的應用程式,系統仍會執行檢查。

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

避免自動初始化

產生 FCM 註冊權杖時,程式庫會將 ID 和設定資料上傳至 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 的實作。