FCM(Firebase Cloud Message)推送
Firebase介绍
Firebase是一家实时后端数据库公司,提供多种产品帮助开发者快速构建App功能。2014年被Google收购。
- IaaS(Infrastructure as a Service)基础设施即服务:提供基础设施。如阿里云
- PaaS(Platform as a Service)平台即服务:提供软件开发能力的平台,如涂鸦开发者平台
- SaaS(Software as a Service)软件即服务:提供软件开发,俗称软件外包
- BaaS(Backend as a Service)后端即服务:提供后台云服务、云存储,简化移动应用开发,如Firebase、七牛云、友盟等
支持的功能:有免费和付费
相关概念:Firebase说明、Android和Firebase更多说明
- Firebase产品:Firebase提供的功能或服务
- Firebase项目:一个项目中可以有多个应用(iOS、Android、Web等),同一项目中的资源共享
- Firebase应用:不同平台应用,同一平台不同包名应用
- Google Cloud:Firebase项目实际是Google Cloud项目,具有Firebase特定配置和服务。GCM->FCM
- Firebase控制台:管理Firebase项目、应用、产品等
- 谷歌三件套,功能边界
- Google Play服务框架:Android的后台服务,提供常用的Google API调用,如Google登录服务、Google地图服务等
- Google Play商店:Google应用商店,依赖Google Play服务
- Google Play游戏服务:提供手机游戏开发的API,不安装的话可能无法正常运行Google Play商店的游戏
架构
消息类型
通知消息 | 数据消息(透传消息) | 通知+数据 | |
---|---|---|---|
接收方式 | 由SDK处理 | 由应用自行处理 | |
数据格式 | 通知title、body | 自定义键值对 | 通知内容+数据内容 |
发送方式 | 控制台发送、服务器发送 | 服务器发送 | 控制台发送、服务器发送 |
客户端接收消息
应用状态 | 通知 | 数据 | 通知+数据 |
---|---|---|---|
前台 | onMessageReceived |
onMessageReceived |
onMessageReceived |
后台 | 系统任务栏显示 | onMessageReceived |
通知:系统任务栏显示,数据:通知栏跳转intent的extras属性。 |
接入流程
要系统带GMS,国内手机厂商一般做了阉割
手动添加Firebase
控制台创建Firebase项目
Firebase项目添加应用,填入应用包名
下载
google-services.json
文件,添加到application模块中Gradle添加google服务插件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16//项目build.gradle
buildscript {
repositories {
google() // Google's Maven repository
}
dependencies {
classpath 'com.google.gms:google-services:4.3.4' // Google Services plugin
}
}
allprojects {
repositories {
google() // Google's Maven repository
}
}模块引入插件(
app/build.gradle
)1
apply plugin: 'com.google.gms.google-services' // Google Services plugin
模块添加依赖
1
2
3
4
5
6
7
8
9
10
11
12//1.使用BoM,可以通过仅指定一个版本(BoM的版本)来管理所有Firebase库版本。
dependencies {
// Import the BoM for the Firebase platform
implementation platform('com.google.firebase:firebase-bom:26.2.0')
implementation 'com.google.firebase:firebase-messaging-ktx'
implementation 'com.google.firebase:firebase-analytics-ktx'//analytic可以移除,用于演示BoM作用
}
//2.不使用BoM
dependencies {
implementation 'com.google.firebase:firebase-messaging-ktx:21.0.1'
implementation 'com.google.firebase:firebase-analytics-ktx:18.0.0'//analytic可以移除
}创建一个Service继承
FirebaseMessagingService
,Manifest注册服务1
2
3
4
5
6
7<service
android:name=".MyFirebaseMessagingService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>获取令牌:
- 主动获取:
FirebaseMessaging.getInstance().getToken()
- Token刷新回调:onNewToken,应用卸载安装等会触发token刷新
- 主动获取:
模拟发送下行消息(下发给客户端,上行消息:客户端发给服务端):可以指定应用、指定主题、指定设备组、指定设备token等将消息发送给特定用户或群体
- 控制台发送
- REST API调用
- 后台应用不同语言接入服务端SDK,调用SDK方法
使用Android Studio Firebase Assistant添加
FIrebase Assistant是一个Android Studio插件,可创建并关联到Firebase项目,自动添加配置
使用方式:AndroidStudio->Tools->Firebase
打开Assistant工具,按照工具流程添加
存在问题:导入库版本不一定是最新的,可能和Android Studio版本有关。低版本库getToken方式不一样,需要手动更新版本。
获取Firebase服务授权
服务器向Firebase服务发送请求需要获取授权。有三种方式
- Google 应用默认凭据(ADC,Google Cloud Application Default Credentials):在Google服务器环境运行,可以直接使用默认凭据
- 服务帐号 JSON 文件:在非Google服务器环境运行,需要下载服务账号JSON文件。
- 配置到服务器环境变量中。
- 通过代码读取Json文件路径,可能存在凭据泄漏风险,推荐方式一
- 源自服务帐号的短期有效的 OAuth 2.0 访问令牌:根据服务账号JSON文件,生成临时访问令牌,添加到发送请求中。如果使用Admin SDK,SDK内部会自行处理,不需要手动生成。
生成访问令牌:
- 下载服务账号json文件
- 下载脚本,修改脚本
- 脚本和json文件放在同一目录,进入目录执行脚本
1 | import argparse |
REST API调用模拟发送消息
1 | // Postman请求 |
1 | curl -X POST -H "Authorization: Bearer ya29.ElqKBGN2Ri_Uz...HnS_uNreA" -H "Content-Type: application/json" -d '{ |
Firebase SDK初始化方式
多进程初始化问题:(Demo演示)Application调用Firebase
原因:Firebase通过ContentProvider初始化SDk,由于ContentProvider只在主进程运行,因此子进程如果调用Firebase方法,会报没有初始化SDK异常。
解决方案1:自定义ContentProvider,指定子进程,初始化Firebase
解决方案2:子进程如果不需要Firebase服务的时候,不要在Application中调用Firebase方法。
- 判断当前进程名为主进程名才调用Firebase方法
- 在主进程Activity中调用Firebase方法。—>Activity可能被创建多次
- 添加flag判断是否已经调用过Firebase方法
TV上遇到的问题
TV没有通知栏,后台无法收到通知消息、通知+数据消息
通知流程:
graph TB onStartCommand-->processIntent processIntent-->handleIntentOnMainThread handleIntentOnMainThread-->handleNotificationOpen{是否是打开通知栏Action} handleNotificationOpen--是-->跳转Activity handleNotificationOpen--否-->handleIntent handleIntent-->action{Intent类型} action--token刷新-->onNewToken action--消息接收-->handleMessageIntent handleMessageIntent-->alreadyReceivedMessage{是否接收过该消息} alreadyReceivedMessage--是-->END((结束)) alreadyReceivedMessage--否-->passMessageIntentToSdk passMessageIntentToSdk-->dispatchMessage dispatchMessage-->判断是否是通知消息 判断是否是通知消息--是-->return 判断是否是通知消息--否-->onMessageReceived
- 查看源码,发现判断条件在bundle参数中,可以修改Bundle参数。
- onStartCommand、onStart等声明为final,无法重写。
- handleIntent和handleIntentOnMainThread都可重写,保险写到handleIntentOnMainThread。
1 | override fun handleIntentOnMainThread(intent: Intent?): Boolean { |
其他问题
- 模拟器有时候收不到通知,可以随便打开一下google应用,触发gms。怀疑是模拟器save state导致
- am force-stop 退出的应用,不会收到notification
- kill杀掉的进程,可以收到notification
- 后台弹窗问题:使用Toast,并且target sdk version小于26(弹窗问题小结)
结束
gitbook介绍:GitBook文档、GitBook简明教程、mermaid插件