自动更新替换方案
这个服务因为目前面临N多非技术的挑战,导致我们很难再维护好这个服务:
- iOS的自动更新已经被苹果官方严格禁止了,苹果官方也数次联系友盟,要求我们及早把iOS的更新服务停掉;
- Android面临的问题更多,比如应用市场(集成友盟自动更新插件会导致市场审核被拒)、部分系统厂商(部分厂商系统上,增量更新功能不能正常工作)以及部分运营商的拦截(比如有开发者反馈我们的下载CDN链接在某些地区的运营商会被禁止访问)。
4.1日起,我们已经停止向新用户透出该服务;今年10.15以后,老用户也不再提供更新包上传服务(网站上传入口不可见,已经发版的SDK,后端仍然提供服务,待自然流量消亡)。下面我们为开发者提供了两种服务迁移方式:
1. 使用友盟消息推送( http://push.umeng.com/pushIndex )的方式,前提是必须集成友盟的消息推送SDK,通过推送下载链接的方式来通知终端用户有新版本下载。 用户点击通知栏后,跳转到App下载页面。此种方式目前比较安全,受应用市场、厂商系统、运营商的干扰不大。此外,使用消息推送方式的好处是,即使App在没有打开的情况下,仍有可能主动触达到用户(借助于消息推送业务线强大的App互保联盟,只要设备上有一个集成过友盟消息推送的App是活跃的,其它集成友盟推送的App的消息也可以送达, 当前应用内更新的方案是App必须打开过,才会触发自动更新的请求 ),增加触达面。 友盟消息推送的后台截图如下:
消息下发后,终端用户在通知栏就可以看到“新版本更新提示了”,参照图中右上角的红框部分。
2. 如果对该服务有强依赖,建议自己去实现一套(不建议使用其它第三方自动更新服务,会面临和使用友盟自动更新同样的问题), 我们已经为大家整理了友盟的技术方案,大家可以仿照友盟的技术方案去实现自己的自动更新服务:
友盟自动更新系统的示意图如下:
图中手机代表客户端。服务端的各个模块描述如下:
- WebConsole:提供上传更新包的网站操作界面。
- FS:文件系统,存储apk文件和增量更新包,增量更新的原理后文会提到。
- DB:用于存储文件的属性,例如版本号,更新描述,文件的md5等。
- Server: 接收客户端请求,返回文件下载链接。
- CDN:提供文件下载服务(友盟用到的是阿里云的CDN服务)。
基本流程
1 用户在WebConsole上传更新包、填写更新版本和更新日志,程序将更新包存储到FS,版本(version-code)、更新日志、文件md5及其他配置信息存储到DB。
2 客户端请求Server,传入客户端的appkey、版本号、md5等信息。Server与DB存储的信息比较,如果需要更新则返回更新包的url,否则返回不更新。
3 客户端收到服务器端的返回结果后判断是否需要更新,如果需要更新,则弹窗提示用户有新版本更新,用户确认后下载安装包,安装新版本。
客户端和Server之间使用https接口通信。使用POST请求方式,交互的信息都在http的content中,格式为json。以下简单示例协议中的关键字段。
Request:
1
2
3
4
5
|
{
"appkey"
:
"xxxxxxxxxx"
,
"version_code"
:
1
,
"old_md5"
:
"xxxxxxxxxxxxxxxxx"
}
|
其中version_code是客户端软件的版本号,old_md5是客户端apk文件的md5值。
Response:
如果不需要更新则返回下面的response
1
2
3
|
{
"update"
:
"No"
}
|
如果需要更新, 则返回下面的reponse:
01
02
03
04
05
06
07
08
09
10
|
// 全量更新
{
"update"
:
"Yes"
,
"new_version"
:
"xxxxx"
,
"update_log"
:
"xxxx"
,
// 更新日志,用于在界面上显示
"delta"
:
false
,
"new_md5"
:
"xxxxxxxxxxxxxx"
,
"target_size"
:
"601132"
}[/p][p=
21
,
null
, left]
|
01
02
03
04
05
06
07
08
09
10
11
12
|
// 增量更新
{
"update"
:
"Yes"
,
"new_version"
:
"xxxxx"
,
"update_log"
:
"xxxx"
,
// 更新日志,用于在界面上显示",
"delta"
:
true
,
"new_md5"
:
"xxxxxxxxxxxxxx"
,
// full-apk的md5
"target_size"
:
"601132"
,
// full-apk的size
"patch_md5"
:
"xxxxxxxxxxxxxxxxx"
,
// patch文件的size
"size"
:
"337852"
// patch文件的md5
}
|
服务端处理流程
流程图如下:1. 客户端发送请求至服务端,请求内容除了必要的验证信息以外,最重要的信息就是version_code,或者类似的用于比较版本号以判断是否需要升级的字段信息。
2. 服务端接收到请求后,验证请求的有效性。
3. 若请求有效,则对比请求中的version_code是否是最新的。
4. 若不是最新的version_code,则说明需要进行更新,此时需要首先判断是否能够进行增量更新。如果请求中version_code对应的apk文件在服务端存在且md5一致,则可以进行增量更新,否则不能。
5 如果不能增量更新,则直接返回apk文件的CDN下载链接。
6 如果能进行增量更新,首先判断对应的patch文件是否存在,如果不存在则调用bsdiff命令生成patch文件后返回patch文件的CDN链接;如果存在就直接返回patch文件CDN链接。
客户端处理流程
1.客户端首先请求server,获得是否有新版本的更新信息。
2. 如果没有更新,则客户端不进行更新动作。
3. 如果服务端返回的是有更新,客户端会根据全量更新和增量更新两种情况来处理: 如果服务器端返回的是全量更新,则会开启service下载完整版的apk文件; 如果服务器端返回的是增量更新,则会开启service下载patch文件到本地,然后使用JNI进行bspatch,给原apk文件打补丁,生成新版本的apk文件,生成的apk文件要进行MD5校验,如果与后台上传的apk文件的MD5值相等,则认为bspatch成功。
更新对话框如下:
4. 客户端在下载完成后,会提示安装,若用户忽略,则会在下次检测更新的时候,首先判断本地是否已经存在最新版的apk文件,若已存在,则会提示安装。
一些经验
0. 客户端与服务器端之间的数据传输要进行加密处理,推荐使用https协议。
1. 建议使用全量更新,目前已知增量更新方案在部分系统厂商上不能正常工作。
2. 当遇到apk有较大改动时,可能会出现差分包和新apk大小相差不大的情况。这种情况下,建议进行全量升级。因为合并差分包的耗费的时间可能会超过全量升级所花费的时间。
3. 当apk本身较小时,全量更新更加合适
4. 若系统内置的apk文件无法获取到,则无法进行增量更新(bspatch是根据系统内置的apk文件与patch文件来合并生成新版本的apk文件)。
5. 为防止增量更新合成的apk文件有误,需要对合成的apk文件和最新版的apk文件进行MD5校验。
渠道更新
在本文描述的处理流程基础上,增加很少的扩展就可以实现分渠道更新。具体的做法是:
1 在上传安装文件时分不同渠道存储,相应的DB里面存储的时候也增加channel的字段。
2 客户端请求中增加一个字段channel,用于标识客户端的渠道。
3 服务端根据不同的渠道返回不同的下载链接。
参见http://bbs.umeng.com/thread-11135-1-1.html
bsdiff & bspatch:http://www.daemonology.net/bsdiff/