记一次Flutter JPush SDK 导致的问题(Android 点击Notification 无反应)

本文详细记录了在Flutter项目中,由FCM切换至极光推送时遇到的问题及解决过程。问题在于Android端集成极光JPush插件后,首次安装无法获取registrationID,点击推送通知无回调。经分析发现,Firebase_messaging插件导致JPushPlugin对象重复初始化,造成回调丢失。通过删除firebase_messaging或禁用其后台消息处理解决该问题。总结强调慎用静态变量,以及在Flutter中可直接修改本地插件代码进行调试。

背景

原来的Flutter 项目直接使用FCM 进行推送,目前有需求将FCM 变为极光推送。

代码版本

Flutter 3.0
Jpush_flutter 2.3.4

问题

在原有项目中直接集成极光JPush 的pub Flutter 插件进行支持。Jpush Flutter
按照官方文档集成以后,Android 端和iOS 端都可以正常接收推送消息,但是在Android 端有几个很奇怪的表现
1、首次安装,调用Flutter 代码
getRegistrationID() 没有收到相应的回调。
2、点击推送消息,onOpenNotification 中也没有收到相应的回调(实际上addEventHandler 所有的回调都没有收到)

解决思路

  1. 理清Jpush 在Flutter 的运行方式。
    实际上,我们看到Jpush_flutter 插件中,主要是以原生代码为主,插件做的就只是做桥接进行通讯。
    在这里插入图片描述
    可以看到除了JpushPlugin 剩下的就是极光自身android 集成要求中的内容了。
    再看jpush_flutter.dart 就能确定,这个插件中只处理通讯问题。

  2. 运行方式大致了解了,在运行过程中,我们查看日志,当点击推送Notification 的时候,Java 层的日志有打印,但是Flutter 层的日志没有打印,所以这里可以断定是插件通讯的问题。

  3. 翻看JPushPlugin.java 文件中,可以看到,java 的日志也只打印了一部分在这里插入图片描述
    其中就可以看到大部分都是判断dartIsReady 这个字段。
    幸运的是,这里代码量不大,我们再几个使用到和修改 dartIsReady字段的地方进行日志打印。
    发现,dartIsReady 只有被设置为true ,并没有设置为false
    并且在调用 onOpenNotification 的时候,dartIsReady 却为false,
    这个表现,直觉告诉我,JpushPlugin 对象被重复初始化了,两个对象不是同一个。
    打印中加入 hashCode,证实以上猜想。

  4. 排查为什么会有重复创建的问题,最简单就算在实例化JPushPlugin 对象的时候打印方法调用栈。
    所幸,我们能直接修改插件中的代码,并且运行也会生效。
    在这里插入图片描述

  5. 发现两次初始化,第一次是由FlutterActivity 中开始的创建
    第二次是在FlutterFirebaseMessagingBackgroundExecutor 中创建了FlutterEngine 过程中初始化插件。

  6. 删除了Firebase_messaging 以后(包括其他相关代码)JPush 一切正常。 到这里,基本可以断定是Firebase_messaging 插件导致的。

翻看代码
在这里插入图片描述
在这里看到,backgroundFlutterEngine 生成的FlutterEngine 是作为 backgroundFlutterEngine 使用。(具体为什么,到现在没找到原因)

问题分析

  1. firebase_messaging 会导致所有插件再次初始化,疑问点是,为什么其他插件正常,反倒只有极光不正常
  2. 根据上一个疑问,我们回看JPushPlugin 发现代码中,有JpushReceiver, (极光SDK 中用于接收回调事件的地方),并且跟踪代码,这里所有的 调用,都是直接调用 JPushPlugin 中的静态方法,并且,静态方法中,通过instance 获取到 JpushPlugin 实例。
  3. 问题点就出在这里,因为重复初始化,导致生产了两个JpushPlugin 实例,极光的初始化,需要在dart 代码中调用setup 进行初始化,然而,setup 的过程在第一个实例化的时候就开始了,第二个实例化对象并没有setup 导致dartIsReady 始终为false
  4. 并且所有JpushReceiver 使用的instance 都是第二个实例化出来的对象。

结束

最终我们通过删除了firebase_messaging 解决了这个问题,但是实际业务上会有使用到firebase_messaging 相关,但是因为目前的问题,只能删除。
实际上到此,这个问题已经花了4 个小时去查找了。

结束2

第一次对接FCM 的同事想了一想这个问题,并且联系起来,
在firebase_messageing 集成过程中有这么一行
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
删除了以后,使用firebase_messageing ,Jpush 也正常了
完美解决

总结:

  1. 在代码中,慎用static 这类型全局静态变量,因为无论从Android GC的角度,还是开发可读性的角度,甚至是代码维护的角度,都是不良的。
  2. 根据问题反思,这个问题,在Flutter 的module 模式下也会出现,因为 Flutter 原生的Module 是多引擎模型。(当然,如果是module 也不会单独集成极光插件)
  3. 解决问题过程中,忽略了太多Log 细节,实际上 dartIsReady = false 这个问题,自己翻看代码和Log 就能发现(解决BUG 的过程中,发现dartIsReady = false 这里已经过去了3小时)
  4. 在Flutter 开发中,所有插件都是代码形式下载到本地,在运行过程中,才进行编译和打包的,所以可以开心的本地修改插件内的代码,去验证问题,(但是涉及到其他同事插件是pub 下载的,所以也只能是调试用)
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值