Firebase Cloud Messaging(FCM)是一种跨平台的消息传递解决方案,可让您可靠地免费发送消息。
使用FCM,您可以通知客户端应用程序可以同步新电子邮件或其他数据。您可以发送通知消息来推动用户的重新参与和保留。对于即时消息之类的用例,一条消息可以将最多4 KB的有效负载传输到客户端应用程序。
以下内容基于flutter 1.22.4
版本
在开始之前,该文档假定您能够创建(或具有现有的)Flutter项目,并且还具有使用中的Firebase项目。如果您不满足这些先决条件,请参考准备工作
dependencies:
flutter:
sdk: flutter
firebase_core: "^0.5.3"
firebase_messaging: "^8.0.0-dev.11"
2.下载依赖项
$ flutter pub get
参考:https://firebase.flutter.dev/docs/messaging/apple-integration/
如果您正在使用Flutter Android Embedding V2(Flutter版本> = 1.12),则Android不需要其他集成步骤。—— 比如我。
低版本请参考:Flutte接入firebase messaging
在使用Firebase Cloud Messaging之前,您必须首先确保已初始化FlutterFire。
await Firebase.initializeApp();
根据设备状态,传入消息的处理方式有所不同。要了解这些情况以及如何将FCM集成到您自己的应用程序中,首先重要的是确定设备可以处于的各种状态:
状态 | 描述 |
---|---|
Foreground | 当应用程序打开时,且在前台显示时。 |
Background | 打开应用程序时,但是在后台(最小化)。当用户按下设备上的“主页”按钮,通过应用程序切换器切换到另一个应用程序或在其他选项卡(Web)上打开应用程序时,通常会发生这种情况。 |
Terminated | 设备锁定或应用程序未运行时。用户可以通过设备上的应用程序切换器用户界面“将其刷掉”或关闭标签页(web)来终止应用程序。 |
不论哪种情况,该应用程序必须至少打开一次(以允许在FCM中注册,必须要能连接到谷歌)。
在Android上,如果强行终止程序,那么是收不到推送的。
在iOS上,如果用户从应用切换器上滑动了该应用程序,则必须再次手动将其重新打开,以使后台消息重新开始工作。
在iOS,macOS和Web上,必须先征询用户许可,然后才能在设备上接收FCM有效负载。
不需要在Android应用程序上请求权限。
代码:
FirebaseMessaging messaging = FirebaseMessaging.instance;
NotificationSettings settings = await messaging.requestPermission(
alert: true,
announcement: false,
badge: true,
carPlay: false,
criticalAlert: false,
provisional: false,
sound: true,
);
print('用户授予权限结果: ${settings.authorizationStatus}');
authorizationStatus属性可以返回一个值,该值可用于确定用户的总体决策:
authorized
: 用户已授予权限。denied
: 用户拒绝了权限。notDetermined
: 用户尚未选择是否授予许可。provisional
:用户授予了临时权限(请参阅[临时权限](https://firebase.flutter.dev/docs/messaging/usage/permissions#provisional-permission))。在Android上,authorizationStatus始终是authorized。
NotificationSettings上的其他属性返回在当前设备上是启用,禁用还是不支持特定权限。
有关更多信息,请查看Permissions文档。
根据应用程序的当前状态,传入的有效负载需要不同的实现来处理它们:
Foreground | Background | Terminated | |
---|---|---|---|
Notification | onMessage | onBackgroundMessage | onBackgroundMessage |
Data | onMessage | onBackgroundMessage (*see below*) | onBackgroundMessage (*see below*) |
Notification & Data | onMessage | onBackgroundMessage | onBackgroundMessage |
默认情况下,在应用程序处于前台时到达的通知消息在Android和iOS上均不会显示可见的通知。但是,可以覆盖此行为:在前台收到推送时里用flutter_local_notifications
来显示一条通知。
///前台消息
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
print('在前台收到消息!');
if (message.notification != null) {
RemoteNotification notification = message.notification;
///显示通知
if (notification != null && notification.android != null) {
FlutterLocalNotificationsPlugin().show(
notification.hashCode,
notification.title,
notification.body,
NotificationDetails(
android: AndroidNotificationDetails(
channel.id,
channel.name,
channel.description,
// TODO 向android添加适当的可绘制资源(在drawable下)
icon: 'launch_background',
),
),
payload: message.data.toString());
}
}
});
当前,在Android / Apple和基于Web的平台上处理后台消息的过程有所不同。
在后台运行应用程序时处理消息有些不同。可以通过onBackgroundMessage处理程序处理消息。
收到隔离信息后,就会生成隔离信息(仅适用于Android,iOS / macOS不需要单独的隔离信息,APNS真牛逼),即使您的应用程序未运行,也可以处理消息。
关于后台消息处理的方法,需要牢记以下几点:
static Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
print("收到后台消息: ${message.messageId}");
}
...
///后台消息
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
收到后台消息的时候,运行长时间的繁重任务会影响设备性能,并可能导致操作系统终止该过程。如果任务运行时间超过30秒,则设备可能会自动终止该进程。
onMessageOpenedApp:当从后台状态打开应用程序时,该流会发送RemoteMessage。此时可以监听到用户对此种通知的点击行为:
///点击后台消息打开App
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
print('从后台打开!');
});
onBackgroundMessage
是无法监听到此种通知的行为的,但是可以接收到用户对此种通知的点击行为:
getInitialMessage():如果从终止状态打开应用程序,则将返回包含RemoteMessage的Future。一旦使用完毕,RemoteMessage将被删除。
///应用从终止状态打开
var m = await FirebaseMessaging.instance.getInitialMessage();
if (m != null) {
print('应用从终止状态打开:${m?.notification?.title}');
}
要展示通知必须包含nofitication
字段
由于通知是可见的提示,因此用户通常会与通知进行交互(点击通知)。 Android和iOS上的默认行为是打开应用程序。如果应用程序终止,它将启动;如果它在后台,它将被带到前台。
firebase-messaging
软件包提供了两种方法来处理此交互(上文一提到,再着重介绍下):
建议同时处理两种情况。
///点击后台消息打开App
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
print('从后台打开!');
});
///应用从终止状态打开
var m = await FirebaseMessaging.instance.getInitialMessage();
if (m != null) {
print('应用从终止状态打开:${m?.notification?.title}');
}
以下是官方示例:
class Application extends StatefulWidget {
@override
State<StatefulWidget> createState() => _Application();
}
class _Application extends State<Application> {
@override
void initState() async {
super.initState();
// Get any messages which caused the application to open from
// a terminated state.
RemoteMessage initialMessage =
await FirebaseMessaging.instance.getInitialMessage();
// If the message also contains a data property with a "type" of "chat",
// navigate to a chat screen
if (initialMessage?.data['type'] == 'chat') {
Navigator.pushNamed(context, '/chat',
arguments: ChatArguments(initialMessage));
}
// Also handle any interaction when the app is in the background via a
// Stream listener
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
if (message.data['type'] == 'chat') {
Navigator.pushNamed(context, '/chat',
arguments: ChatArguments(message));
}
});
}
@override
Widget build(BuildContext context) {
return Text("...");
}
}
处理交互的方式取决于您的应用程序设置,但是上面的示例显示了一个使用StatefulWidget的基本示例。
至于前台通知的点击,请查看flutter_local_notifications
来设置.
用户可以订阅一个主题,我们发推送的时候对某一主题发出推送,订阅了这个主题的用户就会收到。
起到一个发送给多个用户推送的作用。
主要是我没找到通过http取到发推送的时候如何对所有用户发送。
要订阅设备,请使用主题名称调用subscribeToTopic方法:
await FirebaseMessaging.instance.subscribeToTopic('weather');
要取消订阅主题,请使用主题名称调用unsubscribeFromTopic方法:
await FirebaseMessaging.instance.unsubscribeFromTopic('weather');
此处的意思是主题名称为weather
.
如果您无法使用Firebase Admin SDK,则Firebase还支持通过HTTP, POST请求将消息发送到设备:
Authorization:服务器密钥
POST https://fcm.googleapis.com/fcm/send HTTP/1.1
//请求头
Content-Type: application/json
Authorization: key={服务器密钥}
//body
{
"to": "{fcmtoken}",
"notification": {
"icon": "juno_icon",
"title": "自己的土",
"body": "自己的地冷",
"sound": "default",
"badge": 1,
"content_available": true
},
"data": {
"title": "自己的土",
"body": "自己的地",
"id": 1,
"type": 2,
"route": "ceceapp://main/fortune"
}
}
ios后台推送要添加content_available
才能收到回调
相关文档
基于此写的示例项目已发布到github
Android,ios 前后台的推送都已调通,多个手机测试过。