接入友盟厂商push通道遇到的坑

 

目录

调试友盟Push问题的检查清单

客户端、服务端数据协议

客户端接入方式

小米厂商通道

华为厂商通道

魅族厂商通道

VIVO厂商通道

  OPPO厂商通道

吐槽一下集成友盟厂商通道时发现的问题

扫描二维码关注公众号,回复: 9574477 查看本文章

调试友盟Push问题的检查清单

  1. 过滤UMLog标签就可以打印出客户端注册步骤相关的日志
  2. 过滤NAccs.开头的日志,可以看到SDK内部处理push的执行流程日志
  3. 在和服务端调试之前确保客户端配置正确并且注册成功。注册成功后会有成功的日志,这个日志要好好利用。类似于:在tag:MiPushBroadcastReceiver下面打印log: onCommandResult is called. regid= xxxxxxxxxxxxxxxxxxxxxxx接收到小米消息则会打印log: onReceiveMessage,msg= xxxxxxxxxxxxxxxxxxxxxxx
  4. 当收不到消息时,彻底杀死app之后重新启动再试
  5. 如果各项参数都设置正确了,仍然收不到push。确认下是否开启了通知栏通知权限。如果还不行,重装app、重启手机。
  6. 遇到疑难问题,没有解决思路的时候,文档中每个厂商章节最后边有个xx平台FAQ,可以借助这个文档排查问题(只有魅族没有提供)。

客户端、服务端数据协议

  1. 厂商通道,我们需要传递自定义参数,当然也希望传递尽可能多的自定义参数。所以一开始采用了body.custom参数,但是发现如果after_open:go_activity,这种情况下MipushTestActivity收到的intent是空。扒拉SDK源码后发现是解析intent数据的代码中if条件语句并没有判断这个值而是用的extra这个值。所以传递custom参数会导致MipushTestActivity#onMessage中intent为空。
  2. 那就采用的extra的方式传递,它是(key,value)方式。另外,使用custom传递会有最大1000个字节数的限制。而extra并没有说明是否有字节限制,测试发现满足我们要传的数据大小的要求。姑且认为没有限制吧。
  3. {
        "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"
        }
    }

客户端接入方式

  1. 友盟通道(非厂商通道)下发的push数据走的是UmengMessageHandler#dealWithCustomMessage(),原先接入的,不需要修改。
  2. 厂商通道,对于要传递自定义参数的接入需求。正确的接入方式是,
    1. 离线状态下走MipushTestActivity#onMessage,
    2. 在线状态下走UmengMessageHandler#dealWithCustomMessage()或者UmengMessageHandler#openActivity()
    3. 在线状态不要走MipushTestActivity#onMessage方式,否则会有一系列问题,比如intent为空,intent里数据是加密的等情况
  3. 厂商通道,下发的push数据,走的是UmengNotificationClickHandler,这是个基类,需要自己实现一个子类,并复写openActivity()和dealWithCustomAction()方法。openActivity对应于服务端的after_open=go_activity;dealWithCustomAction对应于服务端的after_open=go_custom。
  4. 所以如果在UmengNotificationClickHandler中实现了openActivity()和dealWithCustomAction()方法,就可以接收到数据(umessage),并做响应的跳转。而且可以在umessage.extra中传递自定义的数据。这是比较方便灵活的接入方式。
  5. 但是如果没有实现一个UmengNotificationClickHandler子类,默认走MipushTestActivity类,文档中说会通过MipushTestActivity#onMessage方法中传递的intent可以接收到数据。但是测试的时候发现并非如此。在应用活跃时收到的intent是空,拿不到任何数据,根本无法跳转。虽然这是文档中一再强调的接入方式,也是我一开始就是采用的接入方式,但是采坑了一周之后发现,这种方式并不适合传递自定义数据。要么是intent为空,要么是intent不为空但是body是加密的数据(SDK内部解密过程出错)。最后发现这个坑根本无法填上。所以才退而求其次,采用了UmengNotificationClickHandler方式。
  6. 但是使用UmengNotificationClickHandler不知道是否对统计push数据有影响,从SDK源代码上看,这种方式并SDK内部没有数据布点。但是MipushTestActivity的方式是有的。

小米厂商通道

  1. 小米在接入的时候还是比较友好的。而且发现小米厂商通道自动支持桌面角标(红点+数字都显示),其他厂商通道是不支持的。
  2. 我把MipushTestActivity这个文件放到了包名目录下,测试功能正常。不知道如果不放到这个目录下是否正常,没有测试这种情况。
  3. 遇到一台手机上的device token有两个的奇怪情况。见如下截图。后来发现原因是接入的时候使用了错误的方法导致的。把mPushAgent.addAlias改成mPushAgent.setAlias就可以了。
  4. 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) {
    
        }
    
    });
    

华为厂商通道

  1. 华为厂商通道SDK有个依赖库支持的minSDKVersion版本是16,接入华为意味着只能从16开始支持,符合华为丑的有自己风格的特点。
  2. 友盟没有没有全部适配华为在EMUI8.0+的机型,导致比如EMUI9.0的手机收不到离线消息。建议升级到最新的友盟push SDK,目前最新版是6.0.5。而且为了支持华为EMUI低版本机型,还需要把target SDK version改成25.华为的限制有很多,友盟文档里也写了,符合华为丑的有自己风格的特点。
  3. 在申请华为app id的时候需要一个证书指纹,这个证书就是签名apk的时候的证书。只有华为厂商通道需要这个指纹,符合华为丑的有自己风格的特点。
  4. 从上面几点来看,华为厂商通道侵入性很强,符合华为丑的有自己风格的特点。
  5. 需要在AndroidManifest文件中添加app id,但是奇葩的是需要写成如下形式。
    <meta-data
        android:name="com.huawei.hms.client.appid"
        android:value="appid=xxxxxx" />
    

    value中需要添加“appid=”这个前缀。只能说这种与众不同的方式,符合华为丑的有自己风格的特点。

魅族厂商通道

  1. 魅族无法收到离线push,其中一个错误原因是startPush onFailure s: 503.2, s1=accs channel disabled!
  2. 魅族也存在服务端显示下发成功,但是客户端收不到的情况。官方文档给出了一部分解释,如下图。
  3. 如果有类似这样的日志,可以忽略,并不是导致无法接受的问题原因。UmengPushAgent: startPush onFailure s: 503.2, s1=accs channel disabled!
  4. 友盟客服说魅族必须在application的onCreate中进行,并且不能延迟或异步初始化,不能做进程判断。运行起来确实如此。其他厂商接入都没问题了,偏偏魅族手机上无法获取device token。打印日志报错如下:

 详见问题链接 https://developer.umeng.com/docs/66632/detail/67140?um_channel=sdk 

后来发现我的接入的代码中并没有进程判断,但是有多进程,所以会遇到上面那个错误。其实只要重启几次App就可以注册成功了。

VIVO厂商通道

  1. 使用过程中发现vivo的厂商通道功能比较鸡肋,支持机型少,支持的系统版本少。

  2. Vpush bind成功了,但是手机接收不到push?
    确认系统通知开关是否打开。部分系统版本限制,只能在进程存活下接收通知

  3. 推送成功后但是没有收到消息的问题排查
    1)确认客户端是否已经成功集成并turnOnPush获取到regId,推送指定的regId是否是最新的regId;

    2) 确认手机是否已经打开通知栏开关权限;确认手机时间是否是获取网络时间,不要修改系统时间;

    3)检查消息是否已经送达但是折叠到了消息盒子里面?目前的策略是应用存活时展示,不存活时折叠;

    4)检查单个客户端每日可接收的消息数量是否超出了限制?目前正式应用是每天可接收5条群推消息;

    5)检查设备联网是否有问题,如果连接的wifi设置了代理,一般需要重启手机,可以切换手机网络重试;

    6)如果上诉条件检查了但还是没有接收到消息,可以提供消息Id(taskId)和客户端订阅推送时返回的regId给企业QQ客服定位原因。

  4. 安装测试包之后,vivo手机上该应用的通知权限详情页显示如下。也就是默认是关闭了应用图标标记(桌面角标)、顶部预览、锁屏显示功能。这些都需要手动开启。这些坑需要参考oppo的做法,需要应用程序主动监测是否有通知权限,并在没有开启权限的时候给与弹窗提示,让用户开启弹窗。否则该厂商通道是无法发挥作用的。

  5. 用户收到的推送消息是否有数量限制
    用户可以收到的单推数量不受限制,公共类消息(全推,群推,标签推)一个用户每天接收上限为5条。

  6. vivo推送支持哪些机型和系统版本?
  7. 目前SDK仅支持下表中的机型和对应的系统及以上系统。
  8. image.png
  9. 手机晚上无法收到推送?在限制时间之外发送推送,是会延迟推送还是被直接抛弃?
    1)为避免造成用户打扰,目前vivo手机接收的消息为7:00-23:00,服务器允许推送时间为7:00-22:00,单推不受此时间限制。

    2)在允许时间之外发送的群推或全推,会被抛弃,会计算在发送次数限制中,除非有做入口限制,才会不计。

  10. 如何判断系统是否支持Vpush?    
    可通过调用客户端isSupport()返回的公共状态码判断,状态码为101则系统不支持。     

  11. Vpush目前支持deeplink吗?    
    支持

  12. 在AndroidManifest注册时遇到的一个坑是App_id和App_key的填写,一开始把参数填反了。下面代码中已经标出了正确的填写顺序。
    <!--vivo push参数声明 -->
    <!-- vivo start-->
    <meta-data
     android:name="com.vivo.push.api_key"
     android:value="App ID" />
    <meta-data
     android:name="com.vivo.push.app_id"
     android:value="App Key" />
    <!-- VIVO end-->

    api_key要填写App id,app_id要填写app key。确实是奇葩设计,坑爹做法。

  13. vivo收到的push内容是一堆加密的串,而不是像其他厂商那样是已经解密之后的数据。如下图所示。
  14. 解析这些数据的逻辑在'com.umeng.umsdk:agoo-accs:3.3.8.8-open-fix2'包里面的AgooFactory类中,解析的方法叫做parseEncryptedMsg。从这个方法的实现可以看出。b对应的就是body数据。i对应的是id信息。此时拿到的body仍然是加密的数据。需要解密。
  15. 解密的逻辑仍然在'com.umeng.umsdk:agoo-accs:3.3.8.8-open-fix2'包里。在agoo包下的b类。它是一个runnable,实现解密的具体是现在AgooFactory.parseEncryptedMsg方法中。从代码可以看到它是HmacSHA1的加密方式。
  16. 至于为什么没有解密成功呢?这个需要再次确认原因。
  17. b类的解密处理完之后,在finally块里会执行onMessage方法,进而把解密之后的数据以intent的形式往下传,因而会进一步调用到MipushTestActivity的回调方法onMessage。
  18. 但是遇到的问题是app在线状态推送消息时,onMeassge中的参数intent是null。
  19. 为了方便排查问题,收到消息后SDK内部执行流程如下
UmengMessageHandler ->  
handleMessage ->  
dealWithNotificationMessage -> 
click -> 
NotificationProxyBroadcastReceiver ->  
onReceive -> 
getNotificationClickHandler.handleMessage -> 
openActivity(go_activity) -> 
startActivity -> 
MipushTestActivity -> 
BaseNotifyClickActivity.onNewIntent -> 
buildMessage -> 
把4中的b类加入线程池执行 -> 
见第5点 -> 
MipushTestActivity.onMessage方法被调用

OPPO厂商通道

  1. OPPO手机系统对开发者不友好,双清之后安装的debug包,会默认关闭通知栏的权限。需要重新打开。
  2. OPPO应用通知栏权限默认是关闭的,建议在APP内做弹框提示,调用requestNotificationPermission显示通知权限弹窗,引导用户一键开启通知栏权限。接入OPUSH通知栏弹窗需要客户端sdk1.1.0以上,建议接入最新版的客户端sdk。
  3. 如何开启“通知栏开关授权弹窗”功能?开发者可调用requestNotificationPermission显示通知权限弹窗,用户可通过弹窗自行选择是/否打开应用的通知权限。建议在Activity的onResume方法中调用该接口以避免和其他弹窗重叠。重复调用该接口,弹窗也仅会显示一次。
  4. 通知栏开关授权弹窗是否展示,有数据回调吗,能统计开启和没开启的人数吗?目前通知栏开关授权弹窗是没有数据回调的,不能统计开启人数。
  5. 所有机型都能调用通知栏开关授权弹窗接口吗?系统消息的版本已升级至1.1.0 版本的手机才能接收到通知栏弹窗。(查看方式:【应用管理→ 显示系统进程→ 系统消息】)
  6. 推送成功后为什么收不到消息(或者未展示)?

  7. 目前支持ColorOS3.1及以上的系统。
  8. 目前只支持通知栏消息,透传消息暂不支持。

  9. 没启动过的应用,无法收到消息。曾经启动过的应用,如果30天内该设备有联网行为,后续无需启动也可收到消息。

  10. Registrationid何时产生,何时失效?应用第一次启动时注册生效,后只有在刷机、还原手机(设置-其他设置-还原手机)、卸载应用时才会失效。失效及变更情况参见下表:

吐槽一下集成友盟厂商通道时发现的问题

  1. 找客服人员沟通技术问题时,对方一直无法理解,要求提供截图,提供更多详细信息。那如果他要是对友盟SDK内部原理有充分了解的话,是不存在这种问题的,无奈之后自己去debug SDK的执行流程,这被证明比问客服更有效
  2. 提供一个粗制滥造的demo。明明是集成厂商通道的demo却没有任何展示集成厂商通道的代码,一个厂商的都没有。只写了注册和初始化友盟基础功能的示例。写代码只注册,不解注册吗?
发布了348 篇原创文章 · 获赞 8 · 访问量 74万+

猜你喜欢

转载自blog.csdn.net/logan676/article/details/104522694
今日推荐