一种一次消息推送实现多包名消息分发的方法

2017/11/17 meizupush

支持多包名推送呼声最高的还是游戏分发,由于游戏分发看中多渠道。因此同一款游戏可能存在不同包名,按照现有的情况,一个包名接入 Push需要给每一个包名申请一个为一个AppId,AppKey。倘若应用包名数量比较小,还可以接受。但是如果渠道过多,就可能出现需要申请几十甚至几百个应用,工作量可想而知。因此多包名推送的需求由此而来。

一 现有方案分析

按照现有的实现方案分析,在不改造现有的推送逻辑情况下,第三方服务端开发者如果需要支持多包名,在推送消息时,需要将组装一次,分别按照包名分发给各个包名的应用,这样模式就是多次消息分发,给开发者造成困扰,同时也浪费推送带宽,增加推送信道资源。如下图: image

从上图可以看出:

  • 开发者需要单独调用设置各个要推送的包名依次推送【这将开发者开发复杂度】
  • 同一类型消息发送次数取决于需要发送的包名的个数【浪费信道资源,同一类型消息发送多遍】

二 优化方案

优化方案主要要解决以下问题

  • 一个手机安装多个渠道的apk,尽可能减少服务端发送消息的次数
  • 降低服务端发送消息的复杂度,尽量避免使用轮询发送的方式

NOTE: 以下为新的方案设计图 image

  • 服务端

服务端提供接口,用于让开发者设置多包名,推送的时候将开发者设置的包名传递到推送服务

  • 客户端

客户端收到多包名推送的请求,校验手机中的各个包名是否存在,如果存在就将消息依次分发给各个应用

NOTE: 此方案的设计思想淡化现在单个应用的单一推送,因为服务端推送时本质还是按照客户端imei下发给各个手机,推送服务在这里需要接管多包名的消息分发逻辑,当消息到达客户端时,由推送服务进行逻辑分发,降低push平台的分发复杂性与开发者接入复杂程度。

三 实现方案

按照优化方案,客户端和服务端需要改造

3.1 推送协议改造

  • 目前推送消息格式proto定义如下:
message NotifyBody
{
    //指定推送的应用包名
    required string app     = 1;
    // 推送的消息体内容
    required string body = 2;
    // 扩展字段
    optional string ext = 3;  //扩展信息(json格式){"ct1":{"pushType":"0"}, "statics":{"taskId":"123456"}, ...}
};

如上现在定义的推送消息体格式,目前app固定代表推送给当前应用的包名。以上也是为了适应单包名推送,body代表现在的通知栏消息格式定义,为了兼容性,我们只能在ext上做文章

  • ext 通知栏格式定义如下

需要增加restrictedPackageName,用于传递多包名配置

{
    "ctl": {
       "pushType": 0, //0:通知栏消息; 1: 透传消息 2: 上报日志指令
       "wakeup":0, //透传消息是否强制唤醒应用,仅仅当此消息为透传消息才携带此字段: 1:强制唤醒 0 不强制唤醒
       "cached": 0,    //0:不缓存消息; 1: 缓存通知栏消息
       "cacheNum":10  //通知栏消息最大缓存数量
    },
    "statics": {
       "taskId": "41159",   // 任务taskID
       "time": "1475118843"  // 任务创建时间
       "pushExtra":0 //是否上报push extra 信息 , 0 不上报,1 上报,如果没有该字段默认上报
    },
    "restrictedPackageName": ["com.meizu.upspushdemo","com.meizu.upspushdemoxm"]
}

  • 精简字段
{
    "ctl": {
       "pushType": 0, //0:通知栏消息; 1: 透传消息 2: 上报日志指令
       "wakeup":0, //透传消息是否强制唤醒应用,仅仅当此消息为透传消息才携带此字段: 1:强制唤醒 0 不强制唤醒
       "cached": 0,    //0:不缓存消息; 1: 缓存通知栏消息
       "cacheNum":10  //通知栏消息最大缓存数量
    },
    "statics": {
       "taskId": "41159",   // 任务taskID
       "time": "1475118843"  // 任务创建时间
       "pushExtra":0 //是否上报push extra 信息 , 0 不上报,1 上报,如果没有该字段默认上报
    },
    "rpn": { "com.meizu.upspushdemo":0,
             "com.meizu.upspushdemoxm":1
           }, //记录用户选择的多包名,如果用户填写了多包名,此字段必须把用户所有设置的多包名全部传递过来,不管透传还是通知栏
    "srpn":0 //1代表支持,0 代表不支持多包名,此字段主要控制消息是否只传递给主包名,是否上报反订阅需要校验该手机是否安装其他子包名应用       
}

3.2 服务端改造

服务端在请求推送时,填写ext字段时,增加restrictedPackageName字段,用于向手机推送服务传递多包名配置,此外推送填写的包名始终是主包名packageName

3.3 客户端改造

  • 旧版本兼容性
    • 现象:如果主包名不存在,只推送其他包名,此功能将失效
    • 原因:如果多包名配置推送到旧版的推送服务,即是无法解析restrictedPackageName,多包名配置失效,但是如果当前手机安装了主包名应用还是可以收到消息
  • 新版功能

客户端改造完成之后可以解析服务端发送的restrictedPackageName,进而进行消息转发

3.3 订阅与反订阅逻辑

由于多报名订阅使用的是同一套AppIdAppKey,因此现有的订阅方式需要更改

  • 订阅时上报当前应用的包名

  • pushId生成逻辑

    由于现在pushid生成逻辑是imei+appid,现有情况如果不同包名在同一手机获取的pushid是一致的,为了区分最好根据包名区分

  • 卸载失效逻辑

    当其中一个应用别卸载,需要反订阅此包名,这里可能需要高级反订阅接口

待解决问题

  • 数据上报问题
  • 多渠道问题

    一般情况下同一个手机安装多个不同包名的相同应用情况比较少,例如同一款游戏在不同应用商店上架就会存在多包名,如果它们分别通过魅族应用商店安装在flyme上,通过小米应用商店安装在MiUI上,魅族的推送是在非flyme上是无法生效的,这时候只能依靠各个不同厂商的推送,也就是我们现在要做的统一推送平台,实现不同通道转发。

  • 结论

    因此最总我们要解决的是在不同flyme手机通过不同渠道下载的应用进行消息分发.

Search

    Post Directory