设置 Firebase Cloud Messaging 客户端应用 (Android)

FCM 客户端需要在搭载 Android 4.4 或更高版本且安装了 Google Play 商店应用的设备上运行,或者在搭载 Android 4.4 版本且支持 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);
        }
    }
}

通常,您应向用户显示一个界面,说明如果用户授予应用发布通知的权限,会启用哪些功能。此界面应向用户提供同意或拒绝的选项,例如确定不用了按钮。如果用户选择确定,则直接请求该权限。如果用户选择不用了,则允许用户在不接收通知的情况下继续操作。

如需详细了解有关您的应用应在何时向用户请求 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 会为客户端应用实例生成一个注册令牌 (registration token)。如果您希望指定单一目标设备或者创建设备组,需要扩展 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。我们建议您在以下两个位置进行检查:主 Activity 的 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);

这些值一经设置,即使应用重启也将持续生效。

后续步骤

客户端应用设置完成后,您就可以使用 Notifications Composer 开始发送下行消息。您可以下载、运行和查看此功能的快速入门示例

如需向您的应用添加其他更高级的行为,您可以声明 intent 过滤器,并实现一个 Activity 来响应传入的消息。如需了解详情,请参阅有关从应用服务器发送消息的指南:

请注意,如需使用这些功能,您需要完成服务器实现和使用服务器协议(HTTP 或 XMPP),或者实现 Admin SDK