android增量更新, Say yes

今天学习了一下增量更新,这个技术已经出现很长时间了,但是现实中,估计只有大厂才利用了这一技术在做产品!
国内有些第三方服务平台,像友盟提供自动更新的服务,也是用的增量方式!
其他的像QQ,Sina微博,陌陌,蘑菇街等都用到了,解压一下它们的apk,看一下lib目录:
QQ:libbspatch.so
微博:libbsdiffjni.so
陌陌:libbsdiff.so
蘑菇街:libpatcher.so
这些只不过so的名字不一样而已,但都用到了增量更新.
其它的一些主流app解包后,都看到了libandfix.so这个库,这个是阿里推出的一个支持ART和Dalvik的热修复的框架,在线修复bug.

今天学习增量更新而非热更新
主角:http://www.daemonology.net/bsdiff
官方说明:
(1)bsdiff 和 bspatch是编译,安装补丁到二进制文件的一个工具,
(2)这个工具用到了bzip2的压缩功能,所以补丁的大小小于新旧版本的一个差值
(3)bsdiff非常吃内存

1.编译生成工具

开干,我用的是ubuntu,点击here下源代码,编译



解压,可以看到一共5个文件

shone@Dell:~/Soft/bsdiff-4.3$ ls
bsdiff.1  bsdiff.c  bspatch.1  bspatch.c  Makefile

然后编译make,报错

Makefile:13: *** missing separator.  Stop.

查看一下Makefile


无奈,在网上找了一下,找到了解决方法.
http://kinggoo.com/bsdiffupdate.htm#respond
原因是:目标体下一行的,命令要用TAB键开头,且不能隔一行。
也就是说在.ifndef的前面要有TAB开头才可以~因为他是安装的下一个子集命令。

接着编译,结果报错,找不到头文件

bsdiff.c:33:19: fatal error: bzlib.h: No such file or directory
 #include <bzlib.h>
                   ^
compilation terminated.

先前说过bsdiff依赖bzip2,有图


好,下载bzip2,解压
http://www.bzip.org/downloads.html
make
sudo make install
安装的时候,会创建一些文件,所以给权限
然后编译

cc -O3  -lbz2    bsdiff.c   -o bsdiff
/tmp/cctTxPKV.o: In function `main':
bsdiff.c:(.text.startup+0x2aa): undefined reference to `BZ2_bzWriteOpen'
bsdiff.c:(.text.startup+0x9e9): undefined reference to `BZ2_bzWrite'
bsdiff.c:(.text.startup+0xb2c): undefined reference to `BZ2_bzWrite'
bsdiff.c:(.text.startup+0xc7b): undefined reference to `BZ2_bzWrite'
bsdiff.c:(.text.startup+0xccf): undefined reference to `BZ2_bzWriteClose'
bsdiff.c:(.text.startup+0xd22): undefined reference to `BZ2_bzWriteOpen'
bsdiff.c:(.text.startup+0xd4d): undefined reference to `BZ2_bzWrite'
bsdiff.c:(.text.startup+0xd73): undefined reference to `BZ2_bzWriteClose'
bsdiff.c:(.text.startup+0xdc6): undefined reference to `BZ2_bzWriteOpen'
bsdiff.c:(.text.startup+0xdf1): undefined reference to `BZ2_bzWrite'
bsdiff.c:(.text.startup+0xe17): undefined reference to `BZ2_bzWriteClose'
collect2: error: ld returned 1 exit status
make: *** [bsdiff] Error 1

第一个反应还是,连接bzip2库除了问题,其实不用makefile脚本也可以得到2个二进制工具

CFLAGS          +=      -O3 -lbz2

PREFIX          ?=      /usr/local
INSTALL_PROGRAM ?=      ${INSTALL} -c -s -m 555
INSTALL_MAN     ?=      ${INSTALL} -c -m 444

all:            bsdiff bspatch
bsdiff:         bsdiff.c
bspatch:        bspatch.c

install:
        ${INSTALL_PROGRAM} bsdiff bspatch ${PREFIX}/bin
        .ifndef WITHOUT_MAN
        ${INSTALL_MAN} bsdiff.1 bspatch.1 ${PREFIX}/man/man1
        .endif

仔细看下这个Makefile, bsdiff和bspatch分别是2个模块,互不依赖,用make仅仅是多了可以指定目标到/usr/local目录,然后提供了一键安装功能,就是部署二进制工具和帮助(man)命令到/usr/local, Makefile仅仅是大项目管理的利器,还好这个文件不多,可以2次手动编译就完成了!

gcc bsdiff.c -lbz2 -o bsdiff

好可以生成,bzip2库之前已经安装在系统标准目录

gcc bspatch.c -lbz2 -o bspatch

2个工具都可以正常生成!

linux下链接库通常会去3个文件下找
/lib是内核级的,/usr/lib是系统级的,/usr/local/lib是用户级的

想了下,Makefile估计还是有点问题,然后自己改了下

CC=gcc

LDFLAGS=

CFLAGS=-Wall -O3 -g -lbz2


PREFIX          ?=      /usr/local
INSTALL_PROGRAM ?=      ${INSTALL} -c -s -m 555
INSTALL_MAN     ?=      ${INSTALL} -c -m 444


all:            bsdiff bspatch
bsdiff:         bsdiff.c
        $(CC) bsdiff.c  $(CFLAGS) $(LDFLAGS) -o  bsdiff
bspatch:        bspatch.c
        $(CC) bspatch.c  $(CFLAGS) $(LDFLAGS) -o  bspatch


install:
        ${INSTALL_PROGRAM} bsdiff bspatch ${PREFIX}/bin
        .ifndef WITHOUT_MAN
        ${INSTALL_MAN} bsdiff.1 bspatch.1 ${PREFIX}/man/man1
        .endif

这样make就可以成功生成2个工具了


Makefile的规则
  目标 : 需要的条件 (注意冒号两边有空格)
    命令  (注意前面用tab键开头)
  解释一下:
  1 目标可以是一个或多个,可以是Object File,也可以是执行文件,甚至可以是一个标签。
  2 需要的条件就是生成目标所需要的文件或目标
  3 命令就是生成目标所需要执行的脚本

2.生成补丁文件

差分生成补丁方式
bsdiff old_version.apk new_version.apk diff.patch
分别是3个参数,老版本,新版本,补丁
还没有apk,首要任务先生成2个版本的apk
这里要把补丁合成功能移植到手机客户端上,那么就要用到NDK了

bsdiff是二进制差分工具,其对应的bspatch是相应的补丁合成工具

镜头切换到androidstudio上

2.1 先定义一个调度native层的类

public class Updater {

    public static native void applyPatch(String oldPath, String newPath, String patchPath);

}

2.2 生成.h头文件

因为as的版本原因,生成.h的方式也不一样,我用的androidstudio版本是2.1.1v,网上方法大多不可行,正确的姿势是

shone@Dell:~/Public/work_androidstudio/PatchUpdate/app/build/intermediates/classes/debug$ javah com.sugar.patch.Updater

主要是先编译一下模块,然后进入到debug目录,用javah命令
好了,如果没有问题,会看见一个.h文件


2.3 编写补丁合成代码

<1>首先建立一个jni的文件夹,将.h头文件移动过来
<2>因为补丁合成用到bzip2解压,所以要把zip2的包拷贝过来
<3>然后将bspatch.c拷贝到jni下面
bspatch.c实际上只有2个函数,一个offtin和main(),增加一个native函数

JNIEXPORT void JNICALL Java_com_sugar_patch_Updater_applyPatch
  (JNIEnv *env, jclass clazz, jstring old_path, jstring new_path, jstring patch){
      int argc=4;
      char * argv[argc];
      argv[0]="bspatch";
      argv[1]=(*env)->GetStringUTFChars(env, old_path, 0);
      argv[2]=(*env)->GetStringUTFChars(env, new_path, 0);
      argv[3]=(*env)->GetStringUTFChars(env, patch, 0);

      int ret = domain(argc, argv);

       (*env)->ReleaseStringUTFChars(env,old_path, argv[1]);
       (*env)->ReleaseStringUTFChars(env,new_path, argv[2]);
       (*env)->ReleaseStringUTFChars(env,patch, argv[3]);
       return ret;
}

懂jni的都知道,这个函数名是不能乱写的,必须把.h头文件的那个声明函数拷贝过来,然后参数修改和增加主体,java调native会传值到这个函数里来!
然后这里会调用main()方法,这里我把main方法名字改成了domain,因为main是C程序的入口,这里不需要这个入口
下面是我自己的测试案例:

native代码写好了,那么java需要传入3个参数的值

java核心代码
String oldVersionPath = AppUtils.getOldVersionPath(context.get());
Updater.applyPatch(oldVersionPath, newVersionPath, downPatchPath);

这里需要三个路径,定义常量

public interface Contants {

    String rootDir = Environment.getExternalStorageDirectory().getAbsolutePath()
            + File.separator + "PatchCache" + File.separator;
    String downPatchPath = rootDir + "apk.patch";
    String newVersionPath = rootDir + "PatchUpdate_v_2_0.apk";
}

oldVersionPath为app在手机上的安装包路径,从ApplicationInfo这个类获得,newVersionPath为新版本apk包合成地址,downPatchPath为补丁地址

为了测试,这里把补丁文件apk.patch会先放到sd卡/PatchCache/这个目录下,等app合成完成后,新的apk会输出到sd卡/PatchCache/下


然后有了合成后的,就可以安装更新了

AppUtils.install(context.get(), newVersionPath);

服务端差分补丁

shone@Dell:~/Soft/bsdiff-4.3$ ls
app_v_1_0.apk  bsdiff    bsdiff.c  bspatch.1  Makefile
app_v_2_0.apk  bsdiff.1  bspatch   bspatch.c

app_v_1_0.apkapp_v_2_0.apk分别是1.0和2.0版本,测试的话
我下了几张高清图片放到了2.0版本的assets下面,这样2.0版本的apk大小会比较大,1.0版本大小是1.7M,2.0版本是16.9M,差分后apk.patch有14M!

shone@Dell:~/Soft/bsdiff-4.3$ ./bsdiff app_v_1_0.apk app_v_2_0.apk apk.patch
shone@Dell:~/Soft/bsdiff-4.3$ ls
apk.patch  app_v_1_0.apk  app_v_2_0.apk  bsdiff  bsdiff.1  bsdiff.c  bspatch  bspatch.1  bspatch.c  Makefile

好了,分析到这了
下面是我的测试项目,可以自己测测
https://github.com/shonegg/PatchUpdate

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容

  • 1.概述 1.1.什么是应用增量更新 当我们要更新一个应用的时候,以前很多更新的做法是下载一个新版本去覆盖一个旧版...
    揚灵阅读 3,033评论 8 19
  • 增量更新在Android开发中是一种很常见的技术。 增量更新的原理 增量更新的原理非常简单,就是将本地apk与服务...
    re冷星阅读 1,525评论 3 3
  • @[增量更新,差分包,bsdiff/patch] 背景 随着Android app的不断迭代升级,功能越来越多,a...
    SunYo阅读 13,641评论 2 7
  • 9月21日,夜宿洪椿坪。 洪椿坪位于峨眉山天池峰下,海拔1120米处的山腰里。是我们四天三夜的行走活动中,在山上第...
    文晓玲阅读 870评论 4 8
  • 姓名:陈权 公司:青柠养车 【知~学习】 《阿米巴经营》音频打卡第11天 《轻课口语》打卡第370天 【行~实践】...
    水青柠阅读 141评论 0 0