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

FCM 用戶端需要搭載 Android 5.0 以上版本,且已安裝 Google Play 商店應用程式的裝置,或是搭載 Android 5.0 並使用 Google API 的模擬器。請注意,你不限於透過 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 服務功能前,應一律檢查裝置是否有相容的 Google Play 服務 APK。建議您在兩個地方執行此操作:在主要活動的 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 的導入作業。