使用 Firebase Cloud Messaging 发送和接收 Flutter 应用的通知

1.简介

上次更新时间:2022 年 4 月 4 日

此 Codelab 将引导您完成使用 Flutter 通过 Firebase Cloud Messaging (FCM) 开发多平台应用的流程。您将编写一个应用实现代码,然后在三个平台(Android、iOS 和 Web)上无缝构建和运行该应用。您还将学习如何在 Flutter 中集成 FCM,以及如何编写代码以接收和发送消息。最后,此 Codelab 介绍了 FCM HTTP v1 API 针对具体平台的屏蔽功能,可让您发送一条在不同平台上具有不同行为的消息。

前提条件

对 Flutter 有基本的了解。

学习内容

  • 如何设置和创建 Flutter 应用。
  • 如何添加 FCM 依赖项。
  • 如何向您的应用发送单条 FCM 消息。
  • 如何向您的应用发送主题 FCM 消息。

所需条件

  • 配置了 Dart 和 Flutter 插件的 Android Studio 最新稳定版。

您可以使用以下任一设备运行此 Codelab:

(可选)若要使用 iOS 平台运行此 Codelab,您需要一台 iOS 设备、一个 Apple 开发者账号,以及一台安装了 XCode 的 macOS 设备。

2. Flutter 设置

如果您已设置 Flutter 开发环境,请跳过此部分。

如需设置 Flutter 开发环境,请按以下步骤操作:

  1. 下载并安装适用于您的操作系统的 Flutter:安装 |Flutter
  2. 确保已将 Flutter 工具添加到您的路径中。
  3. 按照设置编辑器 |Flutter 请确保为您的编辑器安装 Flutter 和 Dart 插件。对于此 Codelab 的其余部分,您将使用 Android Studio。
  4. 从命令行运行 flutter doctor,它会扫描您的设置并列出所有需要修复的缺失依赖项。请按照说明修复任何重要的依赖项缺失问题。请注意,某些依赖项可能不是必要的。例如,如果您不打算针对 iOS 进行开发,那么缺少 CocoaPods 依赖项就不会成为阻塞问题。
  5. 运行以下命令,在 fcmflutter 目录 flutter create --org com.flutter.fcm --project-name fcmflutter fcmflutter 中创建您的 Flutter 应用,然后将目录更改为 fcmflutter
  1. 在 Android Studio 中,前往 File ->打开,找到 Flutter 应用的路径,然后点击 Open,在 Android Studio 中打开项目。应用代码位于 lib/main.dart 文件中。

在 Android Studio 工具栏中,点击向下箭头以选择 Android 设备。如果目标选择器为空,请安装虚拟 Android 设备Chrome 浏览器或 iOS 模拟器(如果您希望通过网络浏览器或 iOS 设备启动应用)。您可能需要手动启动该设备并刷新列表,才能找到目标设备。

一个 Android Studio 工具栏,其中突出显示了 build 目标菜单下拉箭头。

点击 Run 图标 Android Studio 中的“Run”按钮 以启动应用。

已启动 Flutter 演示版应用的界面

恭喜!您已成功创建了一个 Flutter 应用。

3. Firebase 和 FlutterFire 设置

要使用 Flutter 开发与 Firebase Cloud Messaging 集成的应用,您需要:

  • Firebase 项目。
  • 具有正常运行的 Firebase CLI。
  • 安装 FlutterFire。
  • 使用 flutterfire configure 配置和生成的应用。

创建 Firebase 项目

如果您已有 Firebase 项目,可以跳过此步骤。

  1. 如果您有 Google 账号,请打开 Firebase 并使用您的 Google 账号登录,然后点击转到控制台
  2. 在 Firebase 控制台中,点击添加项目。按照说明创建项目。请勿选中为此项目启用 Google Analytics ,因为您不会在此项目中使用它。
  3. 创建项目后,点击项目概览旁边的齿轮图标,进入该项目的项目设置

Firebase 控制台的剪裁屏幕截图,其中突出显示了项目设置菜单的图标和

项目 ID 用于唯一标识项目,可能与项目名称不同。项目 ID 稍后将用于设置 FlutterFire。

Firebase 控制台的剪裁屏幕截图,其中突出显示了项目 ID

恭喜!您已成功创建 Firebase 项目。

设置 Firebase CLI

如果您已设置 Firebase CLI,可以跳过此步骤。

转到 Firebase CLI 参考,下载并安装 Firebase CLI。使用以下命令,使用您的 Google 账号登录 Firebase:

firebase login

设置 FlutterFire

  1. 使用以下命令安装 FlutterFire 插件:flutter pub add firebase_core
  2. 安装 FCM 插件:flutter pub add firebase_messaging
  3. 设置 FlutterFire CLI:dart pub global activate flutterfire_cli
  4. 在 Flutter 上配置 Firebase 项目:flutterfire configure --project=fcm4flutter. 使用箭头键和空格键可选择平台,或按 Enter 键使用默认平台。

此 Codelab 使用默认平台(Android、iOS 和 Web),但您只能选择一个或两个平台。如果系统提示您输入 iOS 软件包 ID,请输入 com.flutter.fcm.fcmflutter 或您自己的 iOS 软件包 ID,格式为 [company domain name].[project name]。命令完成后,刷新 Firebase 控制台页面。您将看到它已经在 Firebase 项目下为所选平台创建了应用。

Firebase 控制台的剪裁屏幕截图,显示了为所选平台创建的应用

此命令会在 lib 目录下生成一个 firebase_options.dart 文件,其中包含初始化所需的所有选项。

设置 iOS 版 Cloud Messaging

  1. 前往 Apple 开发者页面,然后点击密钥标签页上的创建密钥

Apple 开发者页面的剪裁屏幕截图,其中突出显示了用于创建密钥的页面组件

  1. 输入密钥的名称,并选中 Apple 推送通知服务 (APNs)Apple 开发者页面的剪裁屏幕截图,其中突出显示了新密钥名称的文本框
  2. 下载文件扩展名为 .p8 的密钥文件。Apple 开发者页面的剪裁屏幕截图,其中突出显示了用于下载密钥的按钮
  3. Firebase 控制台中,前往项目的项目设置,然后选择 Cloud Messaging 标签页。

Firebase 控制台页面的剪裁屏幕截图,其中突出显示了更新项目设置的各个组件

Firebase 控制台页面的剪裁屏幕截图,其中突出显示了“Cloud Messaging”标签页

  1. 云消息传递标签页中上传 iOS 应用的 APNs 密钥文件。输入 Cloud Messaging 标签页中的 APNs 密钥 ID 以及团队 ID(可在 Apple 会员中心找到)。Firebase 控制台页面的剪裁屏幕截图,其中突出显示了用于上传 APNs 身份验证密钥的按钮

4. FCM 准备

应用必须先执行以下操作,然后才能接收来自 FCM 的消息:

  • 初始化 FlutterFire。
  • 请求通知权限。
  • 向 FCM 注册以获取注册令牌。

初始化

如需初始化该服务,请将 main 函数 (lib/main.dart) 替换为以下代码:

// core Flutter primitives
import 'package:flutter/foundation.dart';
// core FlutterFire dependency
import 'package:firebase_core/firebase_core.dart';
// generated by 
flutterfire configure
import 'firebase_options.dart';
// FlutterFire's Firebase Cloud Messaging plugin
import 'package:firebase_messaging/firebase_messaging.dart';

// TODO: Add stream controller
// TODO: Define the background message handler

Future<void> main() async {
 WidgetsFlutterBinding.ensureInitialized();
 await Firebase.initializeApp(
   options: DefaultFirebaseOptions.currentPlatform,
 );

 // TODO: Request permission
 // TODO: Register with FCM
 // TODO: Set up foreground message handler
 // TODO: Set up background message handler

 runApp(MyApp());
}

然后运行工具 ->Flutter ->Android Studio 中的 Flutter Pub Get 以加载在设置 FlutterFire 中添加的软件包,并在 Android Studio 中使用适当的 Intellisense 设置显示代码。

这会针对当前平台 DefaultFirebaseOptions.currentPlatform(从生成的 firebase_options.dart 文件导入)初始化 FlutterFire。请注意,initializeApp 是一个异步函数,await 关键字可确保在运行应用之前完成初始化。

请求权限

应用需要请求用户授权才能接收通知。firebase_messaging 提供的 requestPermission 方法会显示一个对话框或弹出式窗口,提示用户允许或拒绝权限。

首先,将此代码复制到 TODO: Request permission 注释下的 main 函数中。返回的 settings 会告知您用户是否已授予权限。我们建议仅在用户需要使用需要访问权限的功能时才请求权限(例如,当用户在应用设置中启用通知时)。在此 Codelab 中,为简单起见,我们将在应用启动时请求权限。

final messaging = FirebaseMessaging.instance;

final settings = await messaging.requestPermission(
 alert: true,
 announcement: false,
 badge: true,
 carPlay: false,
 criticalAlert: false,
 provisional: false,
 sound: true,
);

 if (kDebugMode) {
   print('Permission granted: ${settings.authorizationStatus}');
 }

接下来,在 Android Studio 工具栏中,从目标选择器中选择 Chrome (web),然后再次运行应用。

Android Studio 工具栏的剪裁屏幕截图,其中显示了目标选择器和“Run”按钮

然后,系统会打开 Chrome 标签页,并显示一个请求权限的弹出式窗口。如果您点击 Allow,便会在 Android Studio 控制台中看到一条日志:Permission granted: AuthorizationStatus.authorized。在您允许或屏蔽权限请求后,您的响应会随应用一起存储在浏览器中,并且不会再显示弹出式窗口。请注意,当您在 Android Studio 中再次运行 Web 应用时,可能会再次提示您授予权限。Chrome 标签页的剪裁屏幕截图,其中包含一个要求输入以下内容的弹出式窗口

注册

将此代码复制到 TODO: Register with FCM 注释下方的主函数中,以便向 FCM 注册。getToken 调用会返回一个注册令牌,应用服务器或可信服务器环境可以使用该令牌向用户发送消息。

// It requests a registration token for sending messages to users from your App server or other trusted server environment.
String? token = await messaging.getToken();

if (kDebugMode) {
  print('Registration Token=$token');
}

在 Android Studio 工具栏中,选择一个 Android 设备并运行应用。在 Android Studio 控制台中,系统输出的注册令牌如下所示:

I/flutter ( 3717): Permission granted: AuthorizationStatus.authorized
I/flutter ( 3717): Registration Token=dch. . . D2P:APA9. . .kbb4

请将其复制到文本编辑器中,因为稍后您将使用它发送消息。

uses-sdk:minSdkVersion 16 cannot be smaller than version 19 declared in library [:firebase_messaging]

在网上接收邮件所需采取的额外措施

Web 应用需要执行两个额外步骤才能获取注册令牌并监听传入消息。Web 需要向 getToken 传递 VAPID 密钥,才能授权向受支持的 Web 推送服务发送请求。

首先,在 Firebase 控制台中打开 Firebase 项目的 Cloud Messaging 标签页,向下滚动到 Web 配置部分以找到现有的密钥对,或者生成新的密钥对。点击突出显示的按钮以复制密钥,以便将其用作 vapidKey。

Web 配置页面中 Web Push Certificates 组件的剪裁屏幕截图,其中突出显示了密钥对

接下来,使用以下代码替换“Registration”(注册)部分中的注册代码,然后更新 vapidKey:

// TODO: replace with your own VAPID key
 const vapidKey = "<YOUR_PUBLIC_VAPID_KEY_HERE>";

 // use the registration token to send messages to users from your trusted server environment
 String? token;

 if (DefaultFirebaseOptions.currentPlatform == DefaultFirebaseOptions.web) {
   token = await messaging.getToken(
     vapidKey: vapidKey,
   );
 } else {
   token = await messaging.getToken();
 }

 if (kDebugMode) {
   print('Registration Token=$token');
 }

然后,在项目根目录中的 web/ 目录下创建一个 firebase-messaging-sw.js 文件。将以下内容复制到 firebase-messaging-sw.js 以允许 Web 应用接收 onMessage 事件。如需了解详情,请参阅在 Service Worker 中设置通知选项

importScripts("https://www.gstatic.com/firebasejs/9.6.10/firebase-app-compat.js");
importScripts("https://www.gstatic.com/firebasejs/9.6.10/firebase-messaging-compat.js");

// todo Copy/paste firebaseConfig from Firebase Console
const firebaseConfig = {
 apiKey: "...",
 authDomain: "...",
 databaseURL: "...",
 projectId: "...",
 storageBucket: "...",
 messagingSenderId: "...",
 appId: "...",
};

firebase.initializeApp(firebaseConfig);
const messaging = firebase.messaging();

// todo Set up background message handler

之后,在项目设置 ->General 标签页,向下滚动并找到 Web App,复制 firebaseConfig 代码部分并将其粘贴到 firebase-messaging-sw.jsFirebase 配置页面中 Web 应用组件的剪裁屏幕截图

最后,在 Android Studio 工具栏中,在目标选择器中选择 Chrome (web) 并运行应用。在 Android Studio 控制台中,系统输出的注册令牌如下所示:

Debug service listening on ws://127.0.0.1:61538/BLQQ3Fg-h7I=/ws
Permission granted: AuthorizationStatus.authorized
Registration Token=fH. . .ue:APA91. . .qwt3chpv

将注册令牌复制到文本编辑器中,以便您稍后使用它发送消息。

在 iOS 上接收消息的额外步骤

要从 FCM 接收消息,iOS 设备需要在 Xcode 上启用推送通知后台模式

  1. 在 Android Studio 中,右键点击项目名称,然后选择 Flutter ->在 Xcode 中打开 iOS 模块经过剪裁的屏幕截图
  2. Xcode 启动后,在签名和项目目标的“Capabilities”标签页。如需了解详情,请参阅配置应用
  3. 在 Android Studio 工具栏中,在目标选择器中选择一个 iOS 设备,然后运行应用。授予通知权限后,系统会在 Android Studio 控制台中输出注册令牌。

iOS 应用请求权限发送通知的剪裁屏幕截图

恭喜,您已成功向 FCM 注册应用。如下一部分所述,您已经准备好接收邮件了。

5. 接收来自 FCM 的消息

设置消息处理程序

应用处于前台模式时,应用需要处理 onMessage 事件(当应用收到消息时),以及 onBackgroundMessage 事件(应用在后台运行时)。

前台消息处理程序

首先,在文件 main.dart 中的注释 TODO: Add stream controller 后面添加一个流控制器,以便将消息从事件处理脚本传递到界面。

import 'package:rxdart/rxdart.dart';
// used to pass messages from event handler to the UI
final _messageStreamController = BehaviorSubject<RemoteMessage>();

如需添加依赖项 rxdart,请从项目目录下运行以下命令:flutter pub add rxdart

接下来,运行工具 ->Flutter ->Android Studio 中的 Flutter Pub Get,以加载 rxdart.dart 软件包,并在 Android Studio 中使用适当的 Intellisense 设置显示代码。

然后,添加一个事件处理脚本,以监听 TODO: Set up foreground message handler 注释后面的前台消息。它会输出日志并将消息发布到流控制器。

 FirebaseMessaging.onMessage.listen((RemoteMessage message) {
   if (kDebugMode) {
     print('Handling a foreground message: ${message.messageId}');
     print('Message data: ${message.data}');
     print('Message notification: ${message.notification?.title}');
     print('Message notification: ${message.notification?.body}');
   }

   _messageStreamController.sink.add(message);
 });

然后,使用以下代码替换文件 main.dart 中的原始状态 widget,这会在状态 widget 中向数据流控制器添加一个订阅者,并在 widget 上显示最后一条消息。

class _MyHomePageState extends State<MyHomePage> {
 String _lastMessage = "";

 _MyHomePageState() {
   _messageStreamController.listen((message) {
     setState(() {
       if (message.notification != null) {
         _lastMessage = 'Received a notification message:'
             '\nTitle=${message.notification?.title},'
             '\nBody=${message.notification?.body},'
             '\nData=${message.data}';
       } else {
         _lastMessage = 'Received a data message: ${message.data}';
       }
     });
   });
 }

 @override
 Widget build(BuildContext context) {
   return Scaffold(
     appBar: AppBar(
       title: Text(widget.title),
     ),
     body: Center(
       child: Column(
         mainAxisAlignment: MainAxisAlignment.center,
         children: <Widget>[
           Text('Last message from Firebase Messaging:',
               style: Theme.of(context).textTheme.titleLarge),
           Text(_lastMessage, style: Theme.of(context).textTheme.bodyLarge),
         ],
       ),
     ),
   );
 }
}

适用于 Android/iOS 的后台消息处理程序

当应用在后台运行时,消息由 onBackgroundMessage 处理程序处理。处理程序应该是顶级函数。通过处理消息(请参阅处理互动)或与应用服务器同步,可以在应用进入前台时更新界面。

在主函数外的 TODO: Define the background message handler 注释后面创建处理程序函数,并在主函数中的注释 TODO: Set up background message handler 后调用它。

// TODO: Define the background message handler
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
 await Firebase.initializeApp();

 if (kDebugMode) {
   print("Handling a background message: ${message.messageId}");
   print('Message data: ${message.data}');
   print('Message notification: ${message.notification?.title}');
   print('Message notification: ${message.notification?.body}');
 }
}

void main() {
 ...

 // TODO: Set up background message handler
 FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);

 runApp(MyApp());
}

适用于网页的后台消息处理程序

从 FlutterFire firebase_messaging 11.2.8 版开始,在基于网络的平台上处理后台消息需要不同的流程。因此,您需要在 Service Worker web/firebase-messaging-sw.js 中添加单独的消息处理程序。

messaging.onBackgroundMessage((message) => {
 console.log("onBackgroundMessage", message);
});

设置应用服务器

  1. 在 Android Studio 中打开 https://github.com/FirebaseExtended/firebase_fcm_flutter/tree/main/server 项目,导入起始服务器代码。服务器是一个基于 Gradle 的 Java 项目,依赖于 firebase-admin SDK,后者提供 FCM 消息发送功能。
  2. 设置 Firebase 服务账号,让 Firebase Admin SDK 能够授权对 FCM API 的调用。在 Firebase 控制台中打开项目设置,然后选择服务账号标签页。选择“Java”点击 Generate new private key 即可下载配置代码段。剪裁的屏幕截图,其中突出显示了“项目设置”页面中“服务账号”组件的 Admin SDK 配置代码段
  3. 将该文件重命名为 service-account.json,并将其复制到服务器项目的 src/main/resources 路径下。

发送测试消息

FcmSender.java 文件中,sendMessageToFcmRegistrationToken 撰写带有数据载荷的通知消息。注册令牌将定位消息发送到的应用实例。

private static void sendMessageToFcmRegistrationToken() throws Exception {
   String registrationToken = "REPLACE_WITH_FCM_REGISTRATION_TOKEN";
   Message message =
       Message.builder()
           .putData("FCM", "https://firebase.google.com/docs/cloud-messaging")
           .putData("flutter", "https://flutter.dev/")
           .setNotification(
               Notification.builder()
                   .setTitle("Try this new app")
                   .setBody("Learn how FCM works with Flutter")
                   .build())
           .setToken(registrationToken)
           .build();

   FirebaseMessaging.getInstance().send(message);

   System.out.println("Message to FCM Registration Token sent successfully!!");
 }
  1. 复制从“注册”部分复制的 Android 注册令牌,并将其粘贴到变量 registrationToken 的值中。
  2. 点击 Run 图标 Android Studio 中的“Run”按钮 以运行主函数,并通过 FCM 将消息发送给用户。Android Studio 中 FcmSender.java 主函数旁边显示的“Run”图标的剪裁屏幕截图

当 Android 应用在后台运行时,消息会显示在通知栏中。

Android 通知栏中消息的剪裁屏幕截图

当 Android 应用在前台运行时,您会在 Android Studio 控制台中看到以下日志:“处理前台消息”。消息内容还会显示在界面中,因为界面订阅了新消息的流控制器。

Android 应用中显示的消息内容的剪裁屏幕截图

如果您粘贴注册令牌,并从应用服务器或其他可信服务器环境发送消息,则会看到类似行为:

  • 当 Web 应用在后台运行时(即,当它被另一个窗口隐藏或有其他标签页处于活动状态时),您会看到 Web 通知。

Chrome 浏览器中显示的网络通知的剪裁屏幕截图

  • 当该 Web 应用位于前台时,您可以在 Chrome 控制台中查看日志,方法是右键点击该 Web 应用,然后选择 Inspect。消息内容也会显示在界面中。包含调试日志的 Chrome 控制台的剪裁屏幕截图

6. 发送主题消息

FCM HTTP v1 API 的平台替换功能可让消息发送请求在不同平台上具有不同的行为。此功能的一个用例是根据平台显示不同的通知消息内容。使用主题消息传递针对多种设备(可能跨多个平台)时,此功能的使用最多。本部分将逐步介绍如何让应用接收针对每个平台自定义的主题消息。

从客户端订阅主题

如需订阅主题,请在 Flutter 应用的 main.dart 文件中的主函数末尾调用 messaging.subscribeToTopic 方法。

// subscribe to a topic.
const topic = 'app_promotion';
await messaging.subscribeToTopic(topic);

[可选] 通过网页版服务器订阅主题

如果您不在 Web 平台上进行开发,可以跳过本部分。

FCM JS SDK 目前不支持客户端主题订阅。您可以改为使用 Admin SDK 的服务器端主题管理 API 进行订阅。此代码展示了使用 Java Admin SDK 的服务器端主题订阅。

 private static void subscribeFcmRegistrationTokensToTopic() throws Exception {
   List<String> registrationTokens =
       Arrays.asList(
           "REPLACE_WITH_FCM_REGISTRATION_TOKEN"); // TODO: add FCM Registration Tokens to
   // subscribe
   String topicName = "app_promotion";

   TopicManagementResponse response =     FirebaseMessaging.getInstance().subscribeToTopic(registrationTokens, topicName);
   System.out.printf("Num tokens successfully subscribed %d", response.getSuccessCount());
 }

打开应用服务器,然后点击 Run 图标 Android Studio 中的“Run”按钮 以运行 FcmSubscriptionManager.java 文件中的主函数:

Android Studio 中 FcmSubscriptionManager.java 主函数旁边显示的“Run”图标的剪裁屏幕截图

向主题发送包含平台替换值的消息

现在,您可以发送主题平台替换消息了。在以下代码段中:

  • 您将使用基本消息和标题“A new app is available”构建一个发送请求。
  • 消息生成标题为“A new app is available”的显示通知和网络平台
  • 消息生成标题为“A new Android app is available”的显示通知。
private static void sendMessageToFcmTopic() throws Exception {
   String topicName = "app_promotion";

   Message message =
       Message.builder()
           .setNotification(
               Notification.builder()
                   .setTitle("A new app is available")
                   .setBody("Check out our latest app in the app store.")
                   .build())
           .setAndroidConfig(
               AndroidConfig.builder()
                   .setNotification(
                       AndroidNotification.builder()
                           .setTitle("A new Android app is available")
                           .setBody("Our latest app is available on Google Play store")
                           .build())
                   .build())
           .setTopic("app_promotion")
           .build();

   FirebaseMessaging.getInstance().send(message);

   System.out.println("Message to topic sent successfully!!");
 }

FcmSender.java 文件的主函数中,取消注释 sendMessageToFcmTopic();。点击 Run 图标 Android Studio 中的“Run”按钮 以发送主题消息。

7. 总结和后续步骤

总而言之,您已经学习了如何使用 Flutter 和 FCM 参与多平台应用开发,包括环境设置、依赖项集成以及消息接收和发送。如需深入了解,请参阅以下资料:

Codelab

References