获取我们在 Firebase 峰会上发布的所有信息,了解 Firebase 可如何帮助您加快应用开发速度并满怀信心地运行应用。了解详情

在 Android 上设置 Firebase 云消息传递客户端应用

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请求此权限的运行时版本。在用户授予此权限之前,您的应用将无法显示通知。

请求新的运行时权限:

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);
        }
    }
}

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)
        }
    }
}

通常,您应该显示一个 UI,向用户解释如果他们授予应用程序发布通知的权限将启用的功能。此 UI 应为用户提供同意或拒绝的选项,例如OKNo Thanks按钮。如果用户选择OK ,直接请求权限。如果用户选择No Thanks ,则允许用户在没有通知的情况下继续。

有关您的应用何时应向用户请求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()

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();
        }
    });

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()
})

监控令牌生成

每当生成新令牌时都会触发onNewToken回调。

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);
}

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)
}

获取令牌后,您可以将其发送到您的应用服务器并使用您喜欢的方法进行存储。

检查 Google Play 服务

依赖 Play 服务 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 自动初始化,请进行运行时调用:

Java

FirebaseMessaging.getInstance().setAutoInitEnabled(true);

Kotlin+KTX

Firebase.messaging.isAutoInitEnabled = true

要重新启用 Analytics 收集,请调用FirebaseAnalytics类的setAnalyticsCollectionEnabled()方法。例如:

setAnalyticsCollectionEnabled(true);

设置后,这些值会在应用重新启动后持续存在。

下一步

设置客户端应用程序后,您就可以开始使用Notifications composer发送下游消息了。快速入门示例中演示了此功能,您可以下载、运行和查看该示例。

要向您的应用程序添加其他更高级的行为,您可以声明一个意图过滤器并实现一个活动来响应传入的消息。详情请参见从应用服务器发送消息的指南:

请记住,要利用这些功能,您需要一个服务器实现和服务器协议(HTTP 或 XMPP),或者Admin SDK的实现。