3

Android推送的群魔乱舞

 2 years ago
source link: http://www.androidchina.net/11033.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Android推送的群魔乱舞 – Android开发中文站

最新消息:欢迎访问Android开发中文站!商务联系微信:loading_in
你的位置:Android开发中文站 > 热点资讯 > Android推送的群魔乱舞

国内的Android推送就是个悲剧

国内Android缺少Google的生态,如Google的Paly Store,Google Mobile Services(GSM)等,导致衍生出很多畸形的产业,比如五花八门的APP市场,光怪陆离的推送平台,这里要说的是推送平台。Google本身的GSM服务是包含一套推送在里面的,跟iOS系统的推送类似,它保证每台手机维护一个推送通道就能收到各方推送,但由于Google没法进入中国市场,国产Android基本上算被阉割了一个核心部件,由此衍生的种种弊端数不胜数,首当其冲的就是推送。

国内的手机厂商基本都有自家的推送服务,来替代GSM的缺失,性能、用法参差不齐。在离线场景下(APP死亡),如果想要收到推送,就必须接入对应厂家的推送服务,否则压根收不到。所以Android APP在诞生之初基本就要集成华为push、小米push、魅族push、oppo push、Vivo push等,相对GSM,复杂且没有增益,就好比用江南七怪代替了黄老邪,难用的一B。然而,你别无选择。不过国内各种厂商倒是乐此不疲,他们多了一个触达用户及统计的渠道,并且还能不受Google挟制,对于开发者而言,就要麻烦很多,工作量平白翻了很多倍;有的聊天APP为了走自家的推送SDK,还要琢磨各种黑科技:包活,APP相互唤起等,恶之花,开的漫山遍野。更有意思的是,为了解决这种问题,制定出规范,还促生个各种机构,像推送联盟,绿色联盟等,但并没什么卵用,成立3年,乱象依旧,很多说Android很垃圾,那推送的这个问题要负一大半责任。

吐槽完,你仍然要接。

为什么一定要接厂商的推送SDK呢?不接入收不到推送吗?想要弄清这个东西,就要对推送有个简单的了解,推送:它的点在推(push上,与其对应的是拉(Pull),核心就是客户端跟服务器建立一个长链接,服务器会将信息分发到各个客户端,简化示意如下:

1737065cc4f37326~tplv-t2oaga2asx-zoom-in-crop-mark:1304:0:0:0.awebp

对于手机端APP来说,推送分APP在线推送还是离线推送,其实就是APP是否存活,APP存活情况下,有多种选择,如果APP通过Socket跟自家服务器建立了链接,则可以由自家服务器直接推送到APP端,也可以通过后端推送到第三方推送服务,借由第三方推送给APP端,也就是在线情况下,可以不用接入第三方SDK。但是在APP死亡的情况,只有一种方式:借由第三方推送服务,推送给手机端,这种场景,APP必须接入第三方厂商SDK,拿华为平台为例,其推送模型如下:

1737530ac6fb7aaa~tplv-t2oaga2asx-zoom-in-crop-mark:1304:0:0:0.awebp

与两者对应也有两种消息的概念:透传消息与通知栏消息:

  • 透传消息:APP存活情况下,由推送服务直接把消息发送给APP应用,由APP自己选择如何处理,注意透传的前提是APP存活 ,透传消息可以不用接入第三方SDK。
  • 通知栏消息:在设备接收到消息之后,由系统弹出标准安卓通知,用户点击通知栏才激活应用,这种场景,APP无需存活(活着也不受影响),离线场景下,只有通知栏消息这一条路。

透传消息每个APP自己维护一条通道,离线消息只要一条系统通道,简单看下两者对比,示意如下:

173745c183504909~tplv-t2oaga2asx-zoom-in-crop-mark:1304:0:0:0.awebp

对于在线透传消息,由于是在APP存活的情况下收到的,APP端可以统计到所有必要信息,无论是推送达时间、推送内容还是通知的点击都能统计到;但是离线推送就没那么幸运,很多信息APP自己是拿不到的,但是,业务方通常非常关心到达率、点击率这些数据,必须有一个有效的解决方案。

推送统计问题 (离线推送)

如何到达率

这里不考虑在线推送,只考虑离线(APP死亡),那么离线推送APP能统计到达吗?

答案是 不能,原因其实很简单,APP进程都死了,怎么统计。这种情况下,通知的展示属于系统行为,APP压根无法感知,更无从统计。不过,各三方推送服务平台扔提供了推送到达统计的能力,即采用三方推送平台的回执,以上面的华为推送模型为例:

1737530ac6fb7aaa~tplv-t2oaga2asx-zoom-in-crop-mark:1304:0:0:0.awebp

可以看到,离线推送的情况下,华为设备在展示完通知栏消息后,会给华为Push服务一个回执,而华为Push服务会把这个回执头传给开发者服务器,如此,APP服务端就能判断推送是否到达。

如何统计点击率

同样,在离线推送的场景下,能统计到点击事件吗?关于这个场景,不同的厂商ROM及SDK真是乱七八糟,有的支持,有的不行,简单整理下如下:

ROM 小米 华为 魅族 oppo vivo
App是否可以统计到离线点击事件

因此,各方平台给的方式并没太多参考意义,必须通过其他方式来统计点击,离线推送基本都是通过scheme方式来处理,可以通过加参数来搞定,后续详述。

推送送达率=本次推送真正送达的设备数/所覆盖的所有设备数(按理说,是应该清理掉无效设备)

哪些因素影响送达率

    1. 留存率。已经卸载了APP,肯定收不到,但是有些三方平台可能会归结到分母中,需要自家后台根据回执手动清理regID。
    1. 消息有效期,基本所有第三方PUSH平台都支持设置有效期,有效期越短,触达设备就越少,送达率会下降,可以适当选择有效时间。
    1. 联网情况, 在有效期内,设备没联网,也无法送达,但会被计入分母
    1. 目标人群设备的选取,活跃人群设备送达率肯定要高于全量推送

因此为了能精准的计算送达率,APP服务端要定期清理无效regID(推送token),否则统计的送达率也会偏低

各离线推送平台接入事项

很多大公司都有自家的推送SDK来处理透传消息,小公司一般不具备这个能力,所以在接入Push的时候也分两种情况,

  • 1:有自己加的PushSDK,
  • 2:没有自家PushSDK

如果APP有自己的PushSDK,那只要接入第三方离线推送能力就好了,一些关于透传的处理配置可以完全不用关心,用自己PushSDK那套就可以。如果没有自家PushSDK,那就需要选择一个SDK进行透传处理,当然,仍要接入第三方离线推送能力。不过即使如此,各家ROM的接入规则也个不相同,比如小米有个奇葩的权限叫:“后台弹出界面权限 ”,如果后端服务Push姿势不对,可能会引入奇葩问题:比如,手机能收到PUSH,但是拉不起界面,坑爹。

简单看下各ROM计入注意事项,只看离线能力,不考虑透传:

关于MIPUSH的接入,直接看官方文档即可,没太多问题,需要注意的是,小米有个奇葩的权限设置:后台弹出界面权限 ,该权限默认是关闭,这个选项可能会影响推送通知的点击行为,小米有两大类点击行为:

完全自定义点击行为

在这种行为下,开发者可以拦截通知点击事件,自定义如何处理后续事件,点击后,MiPushMessage通过PushMessageReceiver继承类的onNotificationMessageClicked方法传到APP进程,开发者可自行处理,如果想要启动界面,只需要在其中调用context.startActivity方法即可,但是,这种自定义的行为会受到后台弹出界面权限的影响,尤其是高版本的MIUI ROM中。

173712a7a3ac2fdf~tplv-t2oaga2asx-zoom-in-crop-mark:1304:0:0:0.awebp

你会发现,在这些手机上,此方式压根没法拉起APP,除非通过先启动一个Service,然后在Service中拉起,非常像小米的一个BUG,并且,即使通过此下策能拉起,你会发现,拉起速度非常慢,可能是过多AMS交互通信导致的,所以这种策略可以毙了。

预定义点击行为

预定义点击行为不用用户在onNotificationMessageClicked中处理,系统会直接拉起目标页面,小米支持三种预定义点击行为:

  • (1) 打开当前的Launcher Activity
  • (2) 打开当前app内的任意一个Activity
  • (3) 打开网页。

APP一般会采用第二种行为,打开APP任意一个Activity,其实最终会选择一个DeepLink Activity,由其路由到其他界面。服务端调用Message.Builder类的extra(String key, String value)方法,将key设置为Constants.EXTRA_PARAM_NOTIFY_EFFECT,value设置为Constants.NOTIFY_ACTIVITY便可以达到该效果,用户点击了客户端弹出的通知消息后,封装消息的MiPushMessage对象通过Intent传到客户端,客户端可在Activity中解析,并自行处理后续流程。离线推送情况下,推送服务端核心字段如下:

17371a4f67c2a118~tplv-t2oaga2asx-zoom-in-crop-mark:1304:0:0:0.awebp

采用离线非透传消息,并利用extra自定义Click行为,最后推送给小米的消息格式简化如下:

{
 title=通知标题, 
 description=通知内容, 
 restrictedPackageNames=[com.test.example], 
 notifyType=1, 
 notifyId=1249808047, 
 <!--打开任意Activity配置-->
 extra.intent_uri=yanxuan://re?opOrderId=crm_a1d05c1d3d1743e192a08b461a376785_20200715,
 extra.notify_effect=2
}

extra.intent_uri的值就是APP端定义的私有scheme,点击通知会直接拉起相应的DeepLink Activity,从而唤起应用,至于DeepLink Activity最终路由到哪个界面,可以从extra.intent_uri中解析出来。对于上文层说过的click事件不易统计的问题,可以通过在scheme家参数的方式解决,如下:

extra.intent_uri= yanxuan://re?opOrderId=0200715, 
extra.intent_uri= yanxuan://re?opOrderId=0200715&platform=xiaomi 

之后在路由Activity中可以解析出platform参数,从而标记click事件及来源平台。预定义行为系统会帮我们处理好唤起,在APP中,不需要在onNotificationMessageClicked再次响应click事件了,避免重复处理。后面其余各方SDK的能力基本都跟小米类似,大同小异,没多少花样。

流程同小米类似,按文档即可,预定义行为有如下四种:

  • 1:用户定义Uri,打开目标界面
  • 2:点击后打开特定网页
  • 3:点击后打开应用
  • 4:点击后打开富媒体信息

一般选择自定义Uri行为,所有数据通过intent uri传输给APP,依旧是私有scheme的DeepLink实现方式。对应参数意义如下:

17371e1f83b68861~tplv-t2oaga2asx-zoom-in-crop-mark:1304:0:0:0.awebp

基本上,选择type=1 同 intent uri配合,uri生成格式如下:

Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("pushscheme://com.huawei.codelabpush/deeplink?name=abc&age=180"));
String intentUri = intent.toUri(Intent.URI_INTENT_SCHEME);

最终通过API发送给华为push平台数据格式简化如下:

"msg":{
    "action":{
        "param":{
            "intent":"intent://member?url=http%3A%2F%2Fm.you.163.com%2Fmembership%2Findex&_yanxuan_hwpush=1&_mid=a397314518947995648#Intent;scheme=yanxuan;launchFlags=0x4000000;end"
        },
        "type":1
    },
    "body":{
        "title":"huawei免邮券礼包",
        "content":"快来领取你的每月专属免运费券,立即领取>>"
    }
}

同小米类似,如果需要添加额外参数,放到scheme中,不再敖述。

接入类似,支持四种预定义行为:

  • 打开应用主页
  • 打开应用内页面
  • 打开URI页面
  • 客户端自定义

同样选择预定义Uri页面,具体参数如下

17371e99c0b483fd~tplv-t2oaga2asx-zoom-in-crop-mark:1304:0:0:0.awebp

最终发送数据格式简化如下:

 {
  noticeBarType = 0,
  title = 'meizu明天之后⏰恢复原价', 
  content = '店庆爆款返场!乳胶床垫直降500,拉杆箱仅7折!每满150减25消费券全品类通用,最后1天>>',
  clickType = 2, 
  url = 'yanxuan://yxwebview?url=https%3A%2F%2Fact.you.163.com%2Fact%2Fpub%2FDisjY2u1n9p4SB3.html%3Fanchor%3DSeen3xcj%26opOrderId%3Dcrm_task_20200414160053263_1'
 }

clickType = 2 配合Uri scheme来实现,预定义拉起对应界面,如果需要添加额外参数,同上。

接入类似,oppo无法感知click事件,支持五种预定义行为(有冗余):

  • 0,启动应用;
  • 1,打开应用内页(activity的intent action)
  • 2,打开网页;
  • 4,打开应用内页(利用activity全名)
  • 5, Intent scheme URL
1737526b32522382~tplv-t2oaga2asx-zoom-in-crop-mark:1304:0:0:0.awebp

处理类似,选click_action_type选择5,通过私有scheme拉起APP,具体数据格式如下

{
    "notification":{
        "app_message_id":"a467798011733344256",
        "channel_id":"NotificationChannel",
        "click_action_url":"yanxuan://yxwebview?url=https%3A%2F%2Fact.you.163.com%2Fact%2Fpub%2FDisjY2u1n9p4SB3.html%3Fanchor%3DSeen3xcj%26opOrderId%3Dcrm_task_20200414160053263_1",
        "click_action_type":5,
        "content":"明天之后恢复原价",
        "title":"明天之后恢复原价"
    },
    "target_type":2,
    "target_value":"CN_04f112241e183f6309611df2a95d6237"
}

click_action_type= 5 配合 scheme拉起APP,,如果需要添加额外参数,同上。

vivo跟oppo很类似,不过它也可以收到click事件(并没什么卵用),因此支持完全自定义(然而不用),支持五种Click行为

  • 1:打开APP首页
  • 2:打开链接
  • 3:自定义
  • 4:打开app内指定页面

同样,为了防止禁止后台启动,不采用自定义的方式,而直接打开打开app内指定页面, “skipType”:4,

{
    "classification":1,
    "content":"adssdsr345436",
    "notifyType":1,
    "pushMode":1,
    "regId":"15905547110541891320627",
    "requestId":"a467798011733344256",
    "skipContent":"yanxuan://yxwebview?url=https%3A%2F%2Fact.you.163.com%2Fact%2Fpub%2FDisjY2u1n9p4SB3.html%3Fanchor%3DSeen3xcj%26opOrderId%3Dcrm_task_20200414160053263_1",
    "skipType":4,
    "title":"adssdsr345436"
}

skipType:4配合 scheme拉起APP,,如果需要添加额外参数,同上。

各ROM接入事项小结

以上是几种离线推送的接入方式,整体总结就是:

  • 尽量选择预定义Uri scheme方式,不要采用自定义的方式
  • 可以在scheme中填加参数,统一鉴别click事件
  • 在预定义的方式下,不要在click回调中重复处理事件
  • 如果只要离线推送功能,没必要处理透传配置(比如什么Receiver Service之类的配置)
  • 不得不接入第三方SDK是为了离线推送
  • 各家离线推送大同小异,为了统一建议统一采用预定义Uri方式,配合私有scheme拉起APP
  • 额外追踪参数可以通过添加scheme字段解决
  • 不同ROM可能有自己的额外限制,比如小米,尽量避免受其限制

最后,Android的推送困境是个悲剧…


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK