目录
调试友盟Push问题的检查清单
- 过滤UmengPushAgent开头的日志可以看到客户端整个执行流程
- 过滤UMLog标签就可以打印出客户端注册步骤相关的日志
- 过滤NAccs.开头的日志,可以看到SDK内部处理push的执行流程日志
- 在和服务端调试之前确保客户端配置正确并且注册成功。注册成功后会有成功的日志,这个日志要好好利用。类似于:在tag:MiPushBroadcastReceiver下面打印log: onCommandResult is called. regid= xxxxxxxxxxxxxxxxxxxxxxx接收到小米消息则会打印log: onReceiveMessage,msg= xxxxxxxxxxxxxxxxxxxxxxx
- 当收不到消息时,彻底杀死app之后重新启动再试
- 如果各项参数都设置正确了,仍然收不到push。确认下是否开启了通知栏通知权限。如果还不行,重装app、重启手机。
- 遇到疑难问题,没有解决思路的时候,文档中每个厂商章节最后边有个xx平台FAQ,可以借助这个文档排查问题(只有魅族没有提供)。
客户端、服务端数据协议
- 厂商通道,我们需要传递自定义参数,当然也希望传递尽可能多的自定义参数。所以一开始采用了body.custom参数,但是发现如果after_open:go_activity,这种情况下MipushTestActivity收到的intent是空。扒拉SDK源码后发现是解析intent数据的代码中if条件语句并没有判断这个值而是用的extra这个值。所以传递custom参数会导致MipushTestActivity#onMessage中intent为空。
- 那就采用的extra的方式传递,它是(key,value)方式。另外,使用custom传递会有最大1000个字节数的限制。而extra并没有说明是否有字节限制,测试发现满足我们要传的数据大小的要求。姑且认为没有限制吧。
-
{ "msg_id": "uu481201399440513912", "display_type": "notification", "alias": "", "random_min": 0, "body": { "title": "测试自定义参数", "ticker": "测试自定义参数", "text": "无", "after_open": "go_app", "url": "", "activity": "", "custom": "", "play_vibrate": "true", "play_sound": "true", "play_lights": "true" }, "extra": { "key1": "value1", "key2": "value2" } }
客户端接入方式
- 友盟通道(非厂商通道)下发的push数据走的是UmengMessageHandler#dealWithCustomMessage(),原先接入的,不需要修改。
- 厂商通道,对于要传递自定义参数的接入需求。正确的接入方式是,
- 离线状态下走MipushTestActivity#onMessage,
- 在线状态下走UmengMessageHandler#dealWithCustomMessage()或者UmengMessageHandler#openActivity()
- 在线状态不要走MipushTestActivity#onMessage方式,否则会有一系列问题,比如intent为空,intent里数据是加密的等情况
- 厂商通道,下发的push数据,走的是UmengNotificationClickHandler,这是个基类,需要自己实现一个子类,并复写openActivity()和dealWithCustomAction()方法。openActivity对应于服务端的after_open=go_activity;dealWithCustomAction对应于服务端的after_open=go_custom。
- 所以如果在UmengNotificationClickHandler中实现了openActivity()和dealWithCustomAction()方法,就可以接收到数据(umessage),并做响应的跳转。而且可以在umessage.extra中传递自定义的数据。这是比较方便灵活的接入方式。
- 但是如果没有实现一个UmengNotificationClickHandler子类,默认走MipushTestActivity类,文档中说会通过MipushTestActivity#onMessage方法中传递的intent可以接收到数据。但是测试的时候发现并非如此。在应用活跃时收到的intent是空,拿不到任何数据,根本无法跳转。虽然这是文档中一再强调的接入方式,也是我一开始就是采用的接入方式,但是采坑了一周之后发现,这种方式并不适合传递自定义数据。要么是intent为空,要么是intent不为空但是body是加密的数据(SDK内部解密过程出错)。最后发现这个坑根本无法填上。所以才退而求其次,采用了UmengNotificationClickHandler方式。
- 但是使用UmengNotificationClickHandler不知道是否对统计push数据有影响,从SDK源代码上看,这种方式并SDK内部没有数据布点。但是MipushTestActivity的方式是有的。
小米厂商通道
- 发现小米厂商通道自动支持桌面角标(红点+数字都显示),其他厂商通道是不支持的。
- 但是小米系统比较恶心,只有小米系统会禁止App后台启动。app置于后台时,点击push无法把app置于前台。
- 小米手机中“后台弹出界面”的权限默认被拒绝了,这样在后台Service中或者其他一些后台操作都无法启动Activity了。在小米手机的应用权限管理中有一个“后台弹出界面权限”,该项权限会限制当APP处在后台时弹出Activity的动作,该权限时默认关闭的,可以在小米系统的权限管理页看到:
- 对于这种限制,小米的官方通知是这样的,所以想解决就找法务去谈吧,只有加到白名单才可以正常弹出。
- 我把MipushTestActivity这个文件放到了包名目录下,测试功能正常。不知道如果不放到这个目录下是否正常,没有测试这种情况。
- 遇到一台手机上的device token有两个的奇怪情况。见如下截图。后来发现原因是接入的时候使用了错误的方法导致的。把mPushAgent.addAlias改成mPushAgent.setAlias就可以了。
- addAlias和setAlias的区别,文档中写的很清楚。文档链接 https://developer.umeng.com/docs/66632/detail/98583#h1--tag-alias-4
//别名增加,将某一类型的别名ID绑定至某设备,老的绑定设备信息还在,别名ID和device_token是一对多的映射关系 mPushAgent.addAlias("别名ID", "自定义类型", new UTrack.ICallBack() { @Override public void onMessage(boolean isSuccess, String message) { } }); //别名绑定,将某一类型的别名ID绑定至某设备,老的绑定设备信息被覆盖,别名ID和deviceToken是一对一的映射关系 mPushAgent.setAlias("别名ID", "自定义类型", new UTrack.ICallBack() { @Override public void onMessage(boolean isSuccess, String message) { } });
华为厂商通道
- 华为厂商通道SDK有个依赖库支持的minSDKVersion版本是16,接入华为意味着只能从16开始支持,符合华为丑的有自己风格的特点。
- 友盟没有没有全部适配华为在EMUI8.0+的机型,导致比如EMUI9.0的手机收不到离线消息。建议升级到最新的友盟push SDK,目前最新版是6.0.5。而且为了支持华为EMUI低版本机型,还需要把target SDK version改成25.华为的限制有很多,友盟文档里也写了,符合华为丑的有自己风格的特点。
- 在申请华为app id的时候需要一个证书指纹,这个证书就是签名apk的时候的证书。只有华为厂商通道需要这个指纹,符合华为丑的有自己风格的特点。
- 从上面几点来看,华为厂商通道侵入性很强,符合华为丑的有自己风格的特点。
- 需要在AndroidManifest文件中添加app id,但是奇葩的是需要写成如下形式。
<meta-data android:name="com.huawei.hms.client.appid" android:value="appid=xxxxxx" />
value中需要添加“appid=”这个前缀。只能说这种与众不同的方式,符合华为丑的有自己风格的特点。
魅族厂商通道
- 魅族注册成功的日志要过滤MzPushMessageReceiver,文档中说在MeizuPushReceiver下面打印log。如果用MeizuPushReceiver在某些手机上是没有日志的。使用MzPushMessageReceiver会打印出日志。成功日志是这样的:
03-04 18:42:27.986 29690-30360/? I/MzPushMessageReceiver: onRegisterStatus BasicPushStatus{code='200', message='already register PushId,dont register frequently'}pushId='xxx', Become invalid after 421388 seconds }
- 魅族也存在服务端显示下发成功,但是客户端收不到的情况。官方文档给出了一部分解释,如下图。
- 如果有类似这样的日志,可以忽略,并不是导致无法接受的问题原因。UmengPushAgent: startPush onFailure s: 503.2, s1=accs channel disabled!
- 友盟客服说魅族必须在application的onCreate中进行,并且不能延迟或异步初始化,不能做进程判断。运行起来确实如此。其他厂商接入都没问题了,偏偏魅族手机上无法获取device token。打印日志报错如下:
详见问题链接 https://developer.umeng.com/docs/66632/detail/67140?um_channel=sdk
后来发现我的接入的代码中并没有进程判断,但是有多进程,所以会遇到上面那个错误。其实只要重启几次App就可以注册成功了。
VIVO厂商通道
-
vivo注册成功的日志是这样的
2020-03-04 18:27:46.411 28994-28994/? I/VivoPush.PushMessageReceiver: (xxx)PushMessageReceiver com.iqoo.secure ; type = 10 ; requestId = null
-
成功收到离线消息后,在我的vivo手机上该消息是折叠的状态
-
使用过程中发现vivo的厂商通道功能比较鸡肋,支持机型少,支持的系统版本少。
-
Vpush bind成功了,但是手机接收不到push?
确认系统通知开关是否打开。部分系统版本限制,只能在进程存活下接收通知。 -
推送成功后但是没有收到消息的问题排查
1)确认客户端是否已经成功集成并turnOnPush获取到regId,推送指定的regId是否是最新的regId;2) 确认手机是否已经打开通知栏开关权限;确认手机时间是否是获取网络时间,不要修改系统时间;
3)检查消息是否已经送达但是折叠到了消息盒子里面?目前的策略是应用存活时展示,不存活时折叠;
4)检查单个客户端每日可接收的消息数量是否超出了限制?目前正式应用是每天可接收5条群推消息;
5)检查设备联网是否有问题,如果连接的wifi设置了代理,一般需要重启手机,可以切换手机网络重试;
6)如果上诉条件检查了但还是没有接收到消息,可以提供消息Id(taskId)和客户端订阅推送时返回的regId给企业QQ客服定位原因。
-
安装测试包之后,vivo手机上该应用的通知权限详情页显示如下。也就是默认是关闭了应用图标标记(桌面角标)、顶部预览、锁屏显示功能。这些都需要手动开启。这些坑需要参考oppo的做法,需要应用程序主动监测是否有通知权限,并在没有开启权限的时候给与弹窗提示,让用户开启弹窗。否则该厂商通道是无法发挥作用的。
-
用户收到的推送消息是否有数量限制
用户可以收到的单推数量不受限制,公共类消息(全推,群推,标签推)一个用户每天接收上限为5条。 - vivo推送支持哪些机型和系统版本?
- 目前SDK仅支持下表中的机型和对应的系统及以上系统。
-
手机晚上无法收到推送?在限制时间之外发送推送,是会延迟推送还是被直接抛弃?
1)为避免造成用户打扰,目前vivo手机接收的消息为7:00-23:00,服务器允许推送时间为7:00-22:00,单推不受此时间限制。2)在允许时间之外发送的群推或全推,会被抛弃,会计算在发送次数限制中,除非有做入口限制,才会不计。
-
如何判断系统是否支持Vpush?
可通过调用客户端isSupport()返回的公共状态码判断,状态码为101则系统不支持。 -
Vpush目前支持deeplink吗?
支持 - vivo收到的push内容是一堆加密的串,而不是像其他厂商那样是已经解密之后的数据。如下图所示。
- 解析这些数据的逻辑在'com.umeng.umsdk:agoo-accs:3.3.8.8-open-fix2'包里面的AgooFactory类中,解析的方法叫做parseEncryptedMsg。从这个方法的实现可以看出。b对应的就是body数据。i对应的是id信息。此时拿到的body仍然是加密的数据。需要解密。
- 解密的逻辑仍然在'com.umeng.umsdk:agoo-accs:3.3.8.8-open-fix2'包里。在agoo包下的b类。它是一个runnable,实现解密的具体是现在AgooFactory.parseEncryptedMsg方法中。从代码可以看到它是HmacSHA1的加密方式。
- 至于为什么没有解密成功呢?这个需要再次确认原因。
- b类的解密处理完之后,在finally块里会执行onMessage方法,进而把解密之后的数据以intent的形式往下传,因而会进一步调用到MipushTestActivity的回调方法onMessage。
- 但是遇到的问题是app在线状态推送消息时,onMeassge中的参数intent是null。
- 为了方便排查问题,收到消息后SDK内部执行流程如下
UmengMessageHandler ->
handleMessage ->
dealWithNotificationMessage ->
click ->
NotificationProxyBroadcastReceiver ->
onReceive ->
getNotificationClickHandler.handleMessage ->
openActivity(go_activity) ->
startActivity ->
MipushTestActivity ->
BaseNotifyClickActivity.onNewIntent ->
buildMessage ->
把4中的b类加入线程池执行 ->
见第5点 ->
MipushTestActivity.onMessage方法被调用
OPPO厂商通道
- OPPO手机系统对开发者不友好,双清之后安装的debug包,会默认关闭通知栏的权限。需要重新打开。
- OPPO应用通知栏权限默认是关闭的,建议在APP内做弹框提示,调用requestNotificationPermission显示通知权限弹窗,引导用户一键开启通知栏权限。接入OPUSH通知栏弹窗需要客户端sdk1.1.0以上,建议接入最新版的客户端sdk。
- 如何开启“通知栏开关授权弹窗”功能?开发者可调用requestNotificationPermission显示通知权限弹窗,用户可通过弹窗自行选择是/否打开应用的通知权限。建议在Activity的onResume方法中调用该接口以避免和其他弹窗重叠。重复调用该接口,弹窗也仅会显示一次。
- 通知栏开关授权弹窗是否展示,有数据回调吗,能统计开启和没开启的人数吗?目前通知栏开关授权弹窗是没有数据回调的,不能统计开启人数。
- 所有机型都能调用通知栏开关授权弹窗接口吗?系统消息的版本已升级至1.1.0 版本的手机才能接收到通知栏弹窗。(查看方式:【应用管理→ 显示系统进程→ 系统消息】)
-
推送成功后为什么收不到消息(或者未展示)?
- 目前支持ColorOS3.1及以上的系统。
-
目前只支持通知栏消息,透传消息暂不支持。
-
没启动过的应用,无法收到消息。曾经启动过的应用,如果30天内该设备有联网行为,后续无需启动也可收到消息。
-
Registrationid何时产生,何时失效?应用第一次启动时注册生效,后只有在刷机、还原手机(设置-其他设置-还原手机)、卸载应用时才会失效。失效及变更情况参见下表:
支持桌面角标的厂商
- 测试发现小米所有机型都支持角标(红点)
- 魅族、三星app在线时支持角标显示
- 华为app离线时支持角标显示
- vivo、oppo均不支持
吐槽一下集成友盟厂商通道时发现的问题
- 找客服人员沟通技术问题时,对方一直无法理解,要求提供截图,提供更多详细信息。那如果他要是对友盟SDK内部原理有充分了解的话,是不存在这种问题的,无奈之后自己去debug SDK的执行流程,这被证明比问客服更有效
- 提供一个粗制滥造的demo。明明是集成厂商通道的demo却没有任何展示集成厂商通道的代码,一个厂商的都没有。只写了注册和初始化友盟基础功能的示例。写代码只注册,不解注册吗?