极客星球 | MobPush 之 FCM 离线消息解密
一、背景
MobPush 已实现 tcp 方式实时推送,但前提是需要 APP 处于运行模式,离线模式下无法收到推送,为了解决此问题,提高推送到达率,MobPush 接入华为、小米、oppo、vivo、FCM、魅族六大厂商推送。现因厂商推送到达时,应用无法获取到通知信息,所以无法确认厂商通知是否真正达到客户端。
经对 FCM 分析,找到相关方案,无论在线还是离线状态下接收 FCM 厂商消息都能获取到具体内容,本文将与大家分享 FCM 推送消息获取小妙招。
二、探索发现
本次探索,直接通过 FCM 后台进行推送,并使用 google pixel 手机和 oppo 海外手机分别进行实验。当使用 google pixel 手机时,发现无论应用是否处于运行状态均能收到 FCM 消息,且在离线状态下收到消息之后,应用进程被唤醒。当使用 oppo 海外版测试推送时,在线状态正常接收消息,但在离线状态下无法收到消息,通过观察 APP 运行日志发现,每次收不到消息时 FCM 都会有日志信息:
经过对 FCM sdk 和 google play service 进行反编译,终于在 google play service 的 BroadcastDoneReceiver 类中找到日志出处:
通过搜索 BroadcastDoneReceiver 的创建和调用栈,最终追溯到 TCP 读取消息的地方,具体逻辑是:搜到 tcp 消息解析之后,创建 BroadcastDoneReceiver 实例,创建 action 为““com.google.android.c2dm.intent.RECEIVE””的 intent,发送有序广播:
根据该接口源码的介绍,以 BroadcastDoneReceiver 实例为参数,系统会以该实例作为广播的最后接收者,用来获取广播的发送结果,当有应用获取收到广播时会调用 setResult 方法设置结果,并在 BroadcastDoneReceiver 实例中通过 getResult 获取结果,当无应用收到广播时,便有以上所说错误日志诞生。
进一步探索,发现应用集成 FCM 后,会在 AndroidManifest.xml 中注册上面说到的 action 对应的广播接收者 FirebaseInstanceIdReceiver,其信息如下图:
查看 FirebaseInstanceIdReceiver 的源码,发现确有通知消息的处理逻辑,以及 setResult 的调用,如下图,证实了上面的结论:
于是我们在应用中自定义广播,并按上图方式注册在 AndroidManifest.xml 中,然后推送 fcm 消息,惊喜发现能正常接收到广播,并且在广播的 intent 中已带有通知所有信息。
三、总结
FCM 厂商消息到达时,无论在线还是离线状态下,都会发送广播 FirebaseInstanceIdReceiver,并且带有推送消息内容,所以我们可以用相同方式在应用中注册自定义的广播获取推送消息,进行统计或者有需要的业务需求。之后也会对其他厂商进行调研,看是否有类似发现。
版权声明: 本文为 InfoQ 作者【MobTech袤博科技】的原创文章。
原文链接:【http://xie.infoq.cn/article/b1cd4ac697111ac74d725ad7e】。文章转载请联系作者。
评论