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:
- 一台连接到计算机的 Android 实体设备。
- Android 模拟器(请参阅在 Android 模拟器上运行应用)。
- 您选择的浏览器(例如 Chrome)。
如需使用 iOS 平台运行此 Codelab,您还可以选择使用 iOS 设备、Apple 开发者账号和安装了 Xcode 的 macOS 设备。
2. Flutter 设置
如果您已设置 Flutter 开发环境,请跳过此部分。
如需设置 Flutter 开发环境,请按以下步骤操作:
- 下载并安装适用于您的操作系统的 Flutter:安装 | Flutter
- 确保已将 Flutter 工具添加到您的路径中。
- 按照设置编辑器 | Flutter 中的说明为 Flutter 设置编辑器。请务必为编辑器安装 Flutter 和 Dart 插件。对于此 Codelab 的其余部分,您将使用 Android Studio。
- 从命令行运行
flutter doctor
,它会扫描您的设置并列出所有需要修复的缺失依赖项。请按照说明修复任何重要的依赖项缺失问题。请注意,某些依赖项可能不是必需的。例如,如果您不打算开发 iOS 应用,那么缺少 CocoaPods 依赖项就不会成为阻碍问题。 - 运行以下命令,在
fcmflutter
目录flutter create --org com.flutter.fcm --project-name fcmflutter fcmflutter
中创建 Flutter 应用,然后更改目录为fcmflutter
。
- 在 Android Studio 中,前往 File ->打开,找到 Flutter 应用的路径,然后点击 Open,在 Android Studio 中打开项目。应用代码位于文件
lib/main.dart
中。
在 Android Studio 工具栏中,点击向下箭头以选择 Android 设备。如果目标选择器为空,请安装虚拟 Android 设备;如果您希望通过网络浏览器或 iOS 设备启动应用,请安装 Chrome 浏览器或 iOS 模拟器。您可能需要手动启动该设备并刷新列表,才能找到目标设备。
点击 Run 图标 以启动应用。
恭喜!您已成功创建 Flutter 应用。
3. Firebase 和 FlutterFire 设置
如需使用 Flutter 开发可与 Firebase Cloud Messaging 集成的应用,您需要:
- Firebase 项目。
- 可正常运行的 Firebase CLI。
- FlutterFire 的安装。
- 使用
flutterfire configure
配置和生成的应用。
创建 Firebase 项目
如果您已有 Firebase 项目,则可以跳过此步骤。
- 如果您有 Google 账号,请打开 Firebase 并使用您的 Google 账号登录,然后点击转到控制台。
- 在 Firebase 控制台中,点击添加项目。按照说明创建项目。请勿选中为此项目启用 Google Analytics ,因为您不会在此项目中使用它。
- 创建项目后,点击项目概览旁边的齿轮图标,进入该项目的项目设置。
项目 ID 用于唯一标识项目,可能与项目名称不同。项目 ID 稍后将用于设置 FlutterFire。
恭喜!您已成功创建 Firebase 项目。
设置 Firebase CLI
如果您已设置 Firebase CLI,则可以跳过此步骤。
请参阅 Firebase CLI 参考文档,下载并安装 Firebase CLI。使用以下命令,使用您的 Google 账号登录 Firebase:
firebase login
设置 FlutterFire
- 使用以下命令安装 FlutterFire 插件:
flutter pub add firebase_core
- 安装 FCM 插件:
flutter pub add firebase_messaging
- 设置 FlutterFire CLI:
dart pub global activate flutterfire_cli
- 在 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 项目下为所选平台创建了应用。
此命令会在 lib
目录下生成一个 firebase_options.dart
文件,其中包含初始化所需的所有选项。
设置 iOS 版 Cloud Messaging
- 前往 Apple 开发者页面,然后点击密钥标签页上的创建密钥。
- 输入密钥的名称,然后选中 Apple 推送通知服务 (APNs)。
- 下载文件扩展名为
.p8
的密钥文件。 - 在 Firebase 控制台中,前往项目的项目设置,然后选择 Cloud Messaging 标签页。
- 在 Cloud Messaging(云消息传递)标签页中,上传 iOS 应用的 APNs 密钥文件。输入 Cloud Messaging 标签页中的 APNs 密钥 ID 以及团队 ID(可在 Apple 会员中心找到)。
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
初始化 FlutterFire,该平台是从生成的 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)
,然后再次运行应用。
然后,系统会打开 Chrome 标签页,并显示一个请求权限的弹出式窗口。如果您点击 Allow
,便会在 Android Studio 控制台中看到一条日志:Permission granted: AuthorizationStatus.authorized
。您允许或屏蔽权限请求后,您的响应会随应用一起存储在浏览器中,系统不会再次显示该弹出式窗口。请注意,当您在 Android Studio 中再次运行 Web 应用时,可能会再次提示您授予权限。
注册
将此代码复制到 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 需要将 VAPID 密钥传递给 getToken
,以便向支持的 Web 推送服务授权发送请求。
首先,在 Firebase 控制台中打开 Firebase 项目的 Cloud Messaging 标签页,向下滚动到 Web 配置部分,找到现有密钥对或生成新的密钥对。点击突出显示的按钮以复制密钥,以便将其用作 vapidKey。
接下来,将“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
然后,在 Project Settings(项目设置)-> General(常规)标签页下,向下滚动并找到 Web App(网站应用),复制 firebaseConfig
代码部分并将其粘贴到 firebase-messaging-sw.js
。
最后,在 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 上启用推送通知和后台模式:
- 在 Android Studio 中,右键点击项目名称,然后依次选择 Flutter -> Open iOS module in Xcode。
- Xcode 启动后,在签名和项目目标的“Capabilities”标签页。如需了解详情,请参阅配置应用。
- 在 Android Studio 工具栏中,在目标选择器中选择一个 iOS 设备,然后运行应用。授予通知权限后,系统会在 Android Studio 控制台中输出注册令牌。
恭喜,您已成功向 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
。
接下来,在 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
处理程序处理。处理程序应该是顶级函数。当应用通过处理消息(请参阅处理互动)或与应用服务器同步而进入前台时,界面可以更新。
在主函数外面的 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 版开始,在基于网络的平台上处理后台消息需要不同的流程。因此,您需要在服务工件 web/firebase-messaging-sw.js
中添加单独的消息处理脚本。
messaging.onBackgroundMessage((message) => {
console.log("onBackgroundMessage", message);
});
设置应用服务器
- 在 Android Studio 中打开 https://github.com/FirebaseExtended/firebase_fcm_flutter/tree/main/server 项目,导入起始服务器代码。该服务器是一个基于 Gradle 的 Java 项目,依赖于 firebase-admin SDK,该 SDK 提供 FCM 消息发送功能。
- 设置 Firebase 服务账号,让 Firebase Admin SDK 能够授权对 FCM API 的调用。在 Firebase 控制台中打开项目设置,然后选择服务账号标签页。选择“Java”点击
Generate new private key
即可下载配置代码段。 - 将该文件重命名为
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!!");
}
- 复制从“注册”部分复制的 Android 注册令牌,并将其粘贴到变量
registrationToken
的值中。 - 点击 Run 图标 以运行主函数,并通过 FCM 将消息发送给用户。
当 Android 应用在后台运行时,消息会显示在通知栏中。
当 Android 应用在前台运行时,您会在 Android Studio 控制台中看到一条日志:“Handling a foreground message”。消息内容还会显示在界面中,因为界面订阅了新消息的流控制器。
如果您粘贴注册令牌并从应用服务器或其他受信任的服务器环境发送消息,您会看到类似的行为:
- 当网页应用在后台运行(即被其他窗口隐藏或其他标签页处于活动状态时),您会看到网络通知。
- 当该 Web 应用位于前台时,您可以在 Chrome 控制台中查看日志,方法是右键点击该 Web 应用,然后选择
Inspect
。消息内容也会显示在界面中。
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());
}
打开应用服务器,然后点击运行 以运行 FcmSubscriptionManager.java
文件中的 main 函数:
向主题发送包含平台替换值的消息
现在,您可以发送主题平台替换消息了。在以下代码段中:
- 您构建了一个发送请求,其中包含基本消息和标题“
A new app is available
”。 - 消息生成标题为“
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();
。点击 Run 图标 以发送主题消息。
7. 总结和后续措施
总而言之,您已了解如何使用 Flutter 和 FCM 开发富有吸引力的多平台应用,包括环境设置、依赖项集成以及消息接收和发送。如需深入了解,请参阅以下资料:
Codelab
- 如需详细了解如何将 Flutter 与其他 Firebase 产品搭配使用,包括用户身份验证和同步数据,请参阅了解如何将 Firebase 用于 Flutter。
- 如需详细了解 FCM(包括应用内消息和主题),请参阅使用 FCM 和 FIAM 向用户发送消息和使用 FCM 主题发送您的首个多播推送消息