文章目录
- 简介
- 各开发语言官方文档汇总
- Android原生
- React-Native
- Flutter
- Firebase版本查询
- Firebase中的每个功能包都有很多版本,以下可以查询可用的版本号
- 引入关键
- Android原生
- ReactNative
- RN0.60以下的版本
- RN0.60以上版本
- Flutter
- 消息类型
- 通知消息格式
- 数据消息格式
- 包含可选数据载荷的通知消息
- 处理消息
- 配置接收推送消息
- 配置接收通知和数据类型
- Flutter的接收消息实现
- 测试推送消息
- Flutter配置
- 接收推送消息的关键
- 相关问题
- 通知渠道
- 1. Flutter中集成出现
- 2. Flutter集成出现,应用在后台,点击通知栏推送的消息Notification,无法回调onResume方法
- 3. 获取到Token但无法收到推送消息
- 4.报错Service not registered:
- 相关链接
简介
涉及Android原生、ReactNative版本、Flutter集成Flirebase推送遇到的问题,以及一些注意事项。今年几个项目都采用了Firebase推送,有AndroidX版本,也有不是AndroidX的版本,需要根据项目选择合适的版本。本文不是从头教你配置Firebase,建议先看官方文档,这里是汇总一下注意事项和可能出错的情况。
各开发语言官方文档汇总
Firebase的推送功能,在官方叫Firebase cloud-messaging云信息传递 (简称FCM)
Android原生
- Firebase Cloud Messaging
- Firebase官方提供的原生demo 查看/messaging目录下的项目
React-Native
- rnfirebase官网 针对RN v0.60 以上的版本使用,这是一种新的引入方式,支持androidx,RN版本没有提供demo
- rnfirebase官网v5版本,支持RN v0.60以下版本,不支持androidx
3.3.x | 5.2.x | 5.4.x | 5.5.x | 5.6.x | |
React Native | 0.50-52 | 0.52-58 | ^0.59.3 | ^0.59.3- ^0.61x | 0.60+ |
Play Services Android SDK | 11.8.0 + | ^16.1.0 | ^16.1.0 | ^16.1.0 (or ^17.x via jetifier) | same as 5.5.x |
Firebase iOS SDK | 4.7.0 + | ^5.10.x - ^5.18.x | ^5.19.x - ^5.20.x | ^5.19.x - ^6.x | 6.13+ |
Flutter
- Flutter装Firebase官方文档
- Flutter的官方demo demo里面的代码可能不是最新的,建议还是参考README.md或官方文档配置
- FlutterFire官方文档 Flutter 提供了一组 Firebase 插件,统称为 FlutterFire
- pub仓库firebase_messaging
Firebase版本查询
2019-06-17发布了新版本,从这个版本开始,各个Firebase功能库支持AndroidX,如果不想使用AndroidX版本,需要2019-06-17之前的库版本。
- 官方版本更新说明
- 以上这些版本开始支持Androidx
Firebase中的每个功能包都有很多版本,以下可以查询可用的版本号
- mvnrepository Maven Repository仓库
- wanandroid国内提供的一个查询平台,本好用
引入关键
建议先看官方文档,这里只列举一些关键操作,并不是完整操作流程。
Android原生
- 装库,build.gradle配置 /android/app/build.gradle
apply plugin: 'com.android.application'
...
apply plugin: 'com.google.gms.google-services' // <- Add this line,这个一定要放在所有的apply plugin中最下面, 或者直接添加到文件的底部。
implementation 'com.google.firebase:firebase-iid:20.2.4'
implementation 'com.google.firebase:firebase-messaging:20.2.4'
最好直接参照 Firebase官方提供的原生demo 查看/messaging目录下的项目
ReactNative
RN0.60以下的版本
不支持AndroidX的版本,不能使用太高的版本。
- 先装库
npm install react-native-firebase
react-native link react-native-firebase
- 配置/android/app/build.gradle
apply plugin: 'com.android.application'
...
apply plugin: 'com.google.gms.google-services' // <- Add this line,这个一定要放在所有的apply plugin中最下面,或者直接添加到文件的底部。
implementation "com.google.firebase:firebase-core:16.0.9"
implementation "com.google.android.gms:play-services-base:16.1.0"
implementation "com.google.firebase:firebase-messaging:18.0.0"
implementation "com.google.firebase:firebase-auth:17.0.0"
RN0.60以上版本
这是支持AndroidX的库
- 装库
# Using npm
npm install --save @react-native-firebase/app
npm install --save @react-native-firebase/messaging
# Using Yarn
yarn add @react-native-firebase/app
yarn add @react-native-firebase/messaging
- 配置/android/app/build.gradle
apply plugin: 'com.android.application'
...
apply plugin: 'com.google.gms.google-services' // <- Add this line,这个一定要放在所有的apply plugin中最下面
以下都不需要了,如果添加了可以移除:implementation “com.google.firebase:firebase-core:16.0.9” implementation “com.google.android.gms:play-services-base:16.1.0” implementation “com.google.firebase:firebase-messaging:18.0.0” implementation “com.google.firebase:firebase-auth:17.0.0”
Flutter
目前环境信息:
Flutter 1.20.2 • channel unknown • unknown source
Framework • revision bbfbf1770c (7 weeks ago) • 2020-08-13 08:33:09 -0700
Engine • revision 9d5b21729f
Tools • Dart 2.9.1
- Flutter装库 在pubspec.yaml文件中添加:
dependencies:
firebase_messaging: ^7.0.2
firebase_core: ^0.5.0
- 配置/android/app/build.gradle
apply plugin: 'com.android.application'
...
apply plugin: 'com.google.gms.google-services' // <- Add this line,这个一定要放在所有的apply plugin中最下面
implementation 'com.google.firebase:firebase-messaging:20.2.4'
implementation 'com.google.firebase:firebase-iid:20.2.4'
implementation 'com.google.firebase:firebase-auth:19.4.0'
消息类型
FCM 消息简介
有两种类型:
- 通知消息,有时被称为“显示消息”。此类消息由 FCM SDK 自动处理。由系统通知栏显示。
- 数据消息,无法直接在ui层显示,由客户端应用处理。
使用情景 | 如何发送 | |
通知消息 | 推送到系统通知栏显示 | 设置 notification 键,也可以设置 data 键 |
数据消息 | 客户端应用负责处理数据消息,也叫消息负载 | 仅设置 data 键 |
通知消息格式
token仅做示例用途 当app处于后台,notification中的内容会显示在通知栏上。
{
"message":{
"token":"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
"notification":{
"title":"Portugal vs. Denmark",
"body":"great match!"
}
}
}
数据消息格式
token仅做示例用途
data键里的内容表示 消息负载
{
"message":{
"token":"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
"data":{
"Nick" : "Mario",
"body" : "great match!",
"Room" : "PortugalVSDenmark"
}
}
}
总结:
- 应用在前台,不会自动弹出通知栏。可以自己实现,先创建通知栏通道,再接收到消息后显示自定义通知栏。
- 应用在后台,会弹出系统通知栏。
包含可选数据载荷的通知消息
- 在后台运行时,应用会在通知面板中接收通知有效负载,且仅在用户点按通知时处理数据有效负载。
- 在前台运行时,您的应用将会接收一个消息对象,且两种载荷都可用,表示可以收到这两种数据。
{
"message":{
"token":"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
"notification":{
"title":"Portugal vs. Denmark",
"body":"great match!"
},
"data" : {
"Nick" : "Mario",
"Room" : "PortugalVSDenmark"
}
}
}
处理消息
在 Android 应用中接收消息 接收消息,请使用继承 FirebaseMessagingService 的服务。您的服务应该重写 onMessageReceived 和 onDeletedMessages 回调方法。
不管是Android原生、React-Native、Flutter都需要设置继承 FirebaseMessagingService 的服务,重写onMessageReceived来接受推送过来的消息。
只不过React-Native和Flutter插件都自动帮我们做好了监听服务,不需要手动在AndroidManifest.xml文件中添加
<service
android:name=".java.MyFirebaseMessagingService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
配置接收推送消息
- 当应用在后台或被杀死时送达的通知消息。在这种情况下,通知将传送至设备的系统任务栏。默认情况下,用户点按通知即可打开应用启动器。
- 在后台所接收的同时具备通知和数据载荷的消息。 在这种情况下,通知将传送至设备的系统任务栏,数据载荷则传送至启动器 Activity 的 intent 的 extras 属性中。
Firebase有两种消息类型,通知类型和数据类型。
应用状态 | 通知 | 数据 | 两者皆有(通知类型和数据类型) |
前台 | onMessageReceived | onMessageReceived | onMessageReceived回调数据,但不会不出系统通知栏 |
后台 | 系统通知栏 | onMessageReceived | 通知:出现系统通知栏 数据:intent 的 extras 属性中 |
实际使用中,大多数会使用两者皆有的情况,包含通知和数据类型。
- 当应用在前台的时候,会回调onMessageReceived方法。
- 当应用在后台的时候,会显示出通知栏, 但不会回调onMessageReceived方法。然后点击后,通过intent 的 extras 可以获取携带的数据类型。
配置接收通知和数据类型
- 重写FirebaseMessagingService中的onMessageReceived方法,注意在这个方法的主线程中处理任务不能超过10秒,否则会引起ANR。
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
Log.d(TAG, "From: " + remoteMessage.getFrom());
// 获取data数据类型中的数据
if (remoteMessage.getData().size() > 0) {
Log.d(TAG, "Message data payload: " + remoteMessage.getData());
}
// 获取notification中的内容
if (remoteMessage.getNotification() != null) {
Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getBody());
}
}
- 当应用在后台,显示系统通知栏,点击获取其中的data数据。
先给Activity配置启动模式,可以给主Activity设置。
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:launchMode="singleTask" // 添加这一行,设置启动模式
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
在MainActivity中重写
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
// 当应用第一次启动,比如应用在没启动的情况下,收到Firebase推送,点击进来可以获取到里面携带的data参数。
if (getIntent().getExtras() != null) {
for (String key : getIntent().getExtras().keySet()) {
Object value = getIntent().getExtras().get(key);
Log.d(TAG, "Key: " + key + " Value: " + value);
}
}
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
// 由于前面设置了启动模式,当应用在后台时,收到Firebase推送,点击进来可以会走onNewIntent回调,获取到里面携带的data参数。
Bundle bundle = intent.getExtras();
if(bundle != null){
for(String key: bundle.keySet()){
Object value = bundle.get(key);
Log.i(TAG, "key = " + key + " value = " + value);
}
}
}
}
Flutter的接收消息实现
Flutter的库不仅实现了FirebaseMessagingService,还实现了FlutterFirebaseMessagingReceiver来接收数据,观察源码发现FlutterFirebaseMessagingService中的onMessageReceived方法为空,主要依靠FlutterFirebaseMessagingReceiver
//AndroidManifest.xml配置内容
<service android:name=".FlutterFirebaseMessagingService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT"/>
</intent-filter>
</service>
<receiver
android:name=".FlutterFirebaseMessagingReceiver"
android:exported="true"
android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
</intent-filter>
</receiver>
测试推送消息
打开Firebase后台控制器,发送到指定的token设备。token的获取可以参考官方demo。
这里的设置只是notification通知类型,即推送的格式如下:
{
"message":{
"token":"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
"notification":{
"title":"请问"
"body":"测试"
}
}
}
可以通过以下方法添加数据类型。
这样就是一条 通知+数据类型 的推送消息,即推送的格式如下:
{
"message":{
"token":"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
"notification":{
"title":"请问"
"body":"测试"
},
"data" : {
"name" : "SuperBin"
}
}
}
Flutter配置
- Firebase Cloud Messaging for Flutter
当应用在后台,收到推送来的消息,点击notification,想要回调onResume方法,需要添加数据click_action: FLUTTER_NOTIFICATION_CLICK。
接收推送消息的关键
- 在Android P(8.0) 或更高版本,打开设置中“电池”,将应用设置成“不被优化”等。官方文档说明
后台受限应用(Android P(8.0) 或更高版本),接触限制 从 2019 年 1 月开始,FCM 将不会向由用户置于后台限制的应用传送消息(例如,通过“设置”->“应用和通知”->“[appname]”->“电池”)
- 优先选择三星手机,或者带有google服务的国产手机,要记得打开服务,而且国产手机的app被杀死后,由于国产系统的定制化会断开Firebase的连接,无法在收到推送消息。
- 在国内使用,打开vpn。
- 允许应用弹出通知栏。
- 通过firebase库的getToken()方法,获取的token值,跟app是绑定的,那app启每次启动,getToken()获取的值是不变的。在重新安装应用或deleteToken()等清除token的操作后,才会获取到新的token值。
- 应用放在后台,但不能杀死。
- 查看控制台是否有出现Firebase相关的错误。
- 重启手机或模拟器。
相关问题
通知渠道
- 官方文档-通知渠道 从 Android 8.0(API 级别 26)开始,必须为所有通知分配渠道,否则通知将不会显示。 可以参考Flutter库实现,先构建android的消息通道,再自定义显示通知栏。
1. Flutter中集成出现
PluginRegistry cannot be converted to FlutterEngine类型转换问题
2. Flutter集成出现,应用在后台,点击通知栏推送的消息Notification,无法回调onResume方法
在标题"Flutter配置",就有讲解问题,点击跳转阅读
3. 获取到Token但无法收到推送消息
- 先按 接收推送消息的关键
- 如果以上都没问题,还无法收到,则大部分是Firebase后台配置的问题,可以考虑不用Firebase的推送测试功能,直接跟公司的后台对接试试。
- 看一下配置/android/app/build.gradle,com.google.gms.google-services是不是在所有的apply plugin中最下面
apply plugin: 'com.android.application'
...
apply plugin: 'com.google.gms.google-services' // <- Add this line,这个一定要放在所有的apply plugin中最下面
- 也可以考虑修改google-services版本信息,比如官方目前最新推荐是4.3.4,可以改成4.3.0或其他版本。
// classpath 'com.google.gms:google-services:4.3.4'
classpath 'com.google.gms:google-services:4.3.0'
- 在Firebase控制台,查看一下是否出现同包名的情况,如果存在两个不同项目下,有相同的包名,则Firebase后台检测的时间会比较久。尽量不要在不同项目中,使用相同的包名。
这一步会很慢很慢,可以直接跳过,正在验证中的应用会在右侧显示一个图标,如下图所示。根据我的测试,我在一个项目中创建了两个应用,左边的应用没有图标,表示验证通过,能稳定收到推送。但有右边的应用,处于验证状态,现象就比较难预计,如果能收到推送就说明走通流程了,就不用管这个图标了。但有可能会出现,能获取到token但无法收到推送,再按上面的流程排查一下。
4.报错Service not registered:
还没仔细研究,并不影响消息的推送
java.lang.IllegalArgumentException: Service not registered: com.google.android.gms.measurement.internal.zzjn@4fb2406