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

一、简介

最后更新: 2022-04-04

此 Codelab 将引导您完成使用 Flutter 通过 Firebase Cloud Messaging (FCM) 开发多平台应用的过程。您将编写应用程序的一部分实现,然后在三个平台上构建并无缝运行它:Android、iOS 和 Web。您还将学习如何将 FCM 集成到 Flutter 中以及如何编写代码来接收和发送消息。最后,Codelab 介绍了 FCM HTTP v1 API 的平台特定块功能,该功能允许您发送一条在不同平台上具有不同行为的消息。

先决条件

对 Flutter 的基本了解。

你将学到什么

  • 如何设置和创建 Flutter 应用程序。
  • 如何添加 FCM 依赖项。
  • 如何将单个 FCM 消息发送到您的应用程序。
  • 如何将主题 FCM 消息发送到您的应用程序。

你需要什么

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

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

(可选)要使用 iOS 平台运行 Codelab,您需要 iOS 设备、Apple 开发者帐户和安装了 XCode 的 macOS 设备。

2. 颤振设置

如果您已经设置了 Flutter 开发环境,请跳过本节。

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

  1. 下载并安装适合您操作系统的 Flutter:安装 |扑
  2. 确保 Flutter 工具已添加到您的路径中。
  3. 为 Flutter 设置编辑器,如设置编辑器 |中所示。 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 -> Open ,找到 Flutter 应用的路径,然后单击Open以在 Android Studio 中打开项目。应用程序代码位于文件lib/main.dart中。

在 Android Studio 工具栏上,单击向下箭头以选择 Android 设备。如果目标选择器为空,请安装虚拟 Android 设备,或者如果您希望从 Web 浏览器或 iOS 设备启动应用程序,请安装Chrome 浏览器或 iOS 模拟器。您可能需要手动启动设备并刷新列表才能找到目标设备。

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

单击运行Android Studio 中的运行按钮启动应用程序。

已启动的 Flutter 演示应用程序的 UI

恭喜!您已成功创建 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 版云消息传递

  1. 导航到 Apple开发人员页面,然后单击“密钥”选项卡上的“创建密钥”

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

  1. 输入密钥的名称并选中Apple 推送通知服务 (APN)Apple 开发者页面的裁剪屏幕截图,突出显示新密钥名称的文本框
  2. 下载密钥文件,其文件扩展名为.p8Apple 开发者页面的裁剪屏幕截图,突出显示了下载密钥的按钮
  3. Firebase 控制台中,导航到项目的“项目设置”并选择“云消息传递”选项卡。

Firebase 控制台页面的裁剪屏幕截图,突出显示用于更新项目设置的组件

Firebase 控制台页面的裁剪屏幕截图,突出显示“云消息传递”选项卡

  1. 云消息传递选项卡中上传 iOS 应用程序的 APNs 密钥文件。输入“云消息”选项卡中的 APN 密钥 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());
}

然后在 Android Studio 中运行Tools -> Flutter -> Flutter Pub Get来加载在Set up FlutterFire中添加的包,并在 Android Studio 中使用适当的 Intellisense 设置显示代码。

这会初始化当前平台的 FlutterFire DefaultFirebaseOptions.currentPlatform ,该平台是从生成的firebase_options.dart文件导入的。请注意, 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 工具栏的裁剪屏幕截图,其中包含目标选择器和“运行”按钮

然后,Chrome 选项卡启动,并弹出一个请求许可的窗口。如果单击Allow ,您将在 Android Studio 控制台中看到一条日志: Permission granted: AuthorizationStatus.authorized 。允许或阻止权限请求后,您的响应将与您的应用程序一起存储在浏览器中,并且不会再次显示弹出窗口。请注意,当您在 Android Studio 上再次运行 Web 应用程序时,系统可能会再次提示您授予权限。 Chrome 标签页的裁剪屏幕截图,其中有一个弹出窗口要求

登记

将此代码复制到注释TODO: Register with FCM下方的 main 函数中以向 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 需要将 VAPID 密钥传递给getToken才能授权向支持的 Web 推送服务发送请求。

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

Web 配置页面的 Web 推送证书组件的裁剪屏幕截图,突出显示了密钥对

接下来,将注册部分中的注册代码替换为以下代码,然后更新 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

之后,在Project Settings -> General选项卡下,向下滚动并找到Web App ,复制firebaseConfig代码部分并将其粘贴到firebase-messaging-sw.js中。 Firebase 配置页面的 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 -> Open iOS module in Xcode裁剪后的屏幕截图
  2. Xcode 启动后,在项目目标的“签名和功能”选项卡中启用推送通知后台模式。有关详细信息,请参阅配置您的应用程序
  3. 在 Android Studio 工具栏上,在目标选择器中选择 iOS 设备并运行应用程序。授予通知权限后,注册令牌将打印在 Android Studio 控制台中。

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

恭喜,您已成功向 FCM 注册您的应用程序。您已准备好接收消息,如下一节所述。

5.接收来自FCM的消息

设置消息处理程序

当应用程序处于前台模式时消息到达时,应用程序需要处理onMessage事件;当应用程序处于后台模式时,应用程序需要处理onBackgroundMessage事件。

前台消息处理程序

首先,在文件main.dart中的注释TODO: Add stream controller ,以便将消息从事件处理程序传递到 UI。

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

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

接下来,在 Android Studio 中运行Tools -> Flutter -> 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中的原始 State 小部件,这会将订阅者添加到 State 小部件中的流控制器,并在小部件上显示最后一条消息。

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处理程序处理。处理程序应该是顶级函数。当应用程序进入前台时,可以通过处理消息(请参阅处理交互)或与应用程序服务器同步来更新 UI。

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

Web 后台消息处理程序

从 FlutterFire firebase_messaging版本 11.2.8 开始,在基于 Web 的平台上处理后台消息需要不同的流程。因此,您需要在服务工作线程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 管理 SDK 授权对 FCM API 的调用。在 Firebase 控制台中打开“项目设置” ,然后选择“服务帐户”选项卡。选择“Java”并单击Generate new private key以下载配置片段。 裁剪后的屏幕截图,突出显示项目设置页面的服务帐户组件的管理 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. 单击运行Android Studio 中的运行按钮运行 main 函数并通过 FCM 向用户发送消息。 Android Studio 中 FcmSender.java 主函数旁边显示的运行图标的裁剪屏幕截图

当 Android 应用程序在后台运行时,该消息将显示在通知托盘中。

Android 通知托盘中显示的消息的裁剪屏幕截图

当 Android 应用程序位于前台时,您将在 Android Studio 控制台中看到一条日志:“处理前台消息”。消息内容也会显示在 UI 中,因为 UI 订阅了流控制器以获取新消息。

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

如果您粘贴注册令牌并从应用程序服务器或其他受信任的服务器环境发送消息,您将看到类似的行为:

  • 当网络应用程序在后台时(即,当它被另一个窗口隐藏或另一个选项卡处于活动状态时),您将看到网络通知。

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

  • 当 Web 应用程序位于前台时,您可以通过右键单击 Web 并选择Inspect在 Chrome 控制台中查看日志。消息内容也会显示在 UI 中。 带有调试日志的 Chrome 控制台的裁剪屏幕截图

6.发送主题消息

FCM HTTP v1 API 的平台覆盖功能使消息发送请求在不同平台上具有不同的行为。此功能的一个用例是根据平台显示不同的通知消息内容。当主题消息传递针对多个设备(可能跨越多个平台)时,该功能得到最充分的利用。本部分将引导您完成使您的应用程序接收为每个平台定制的主题消息的步骤。

订阅客户端的主题

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

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

[可选] 从 Web 服务器订阅主题

如果您不是在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());
 }

打开应用程序服务器并单击运行Android Studio 中的运行按钮运行FcmSubscriptionManager.java文件中的 main 函数:

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

向主题发送带有平台覆盖的消息

现在您已准备好发送主题平台覆盖消息。在下面的代码片段中:

  • 您使用基本消息和标题“ A new app is available ”构建发送请求。
  • 该消息会在 iOS 和 Web 平台上生成标题为“ A new app is available ”的显示通知。
  • 该消息会在 Android 设备上生成标题为“ 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文件的main函数中,取消注释sendMessageToFcmTopic(); 。单击运行Android Studio 中的运行按钮发送主题消息。

7. 总结和下一步

总而言之,您已经了解了如何使用 Flutter 和 FCM 进行多平台应用程序开发,其中包括环境设置、依赖项集成以及消息接收和发送。要深入了解,请参阅以下材料:

代码实验室

参考