Android增量更新研究

来源:互联网 发布:ubuntu查看分区挂载点 编辑:程序博客网 时间:2024/05/29 18:32

Android增量更新研究

很多线上的android

apk都有增量更新功能,他能使你更新app的时候,无需完全下载一个新的安装包,而只需下载一个新旧版本之间的一个补丁(patch),然后在本地合成新的安装包。

环境:ubuntu16.04/android

studio2.1

工具:bsdiff/bspatch

说明:http://www.daemonology.net/bsdiff/

最新版本地址:http://www.daemonology.net/bsdiff/bsdiff-4.3.tar.gz

下载后解压:


发现是C语言写的,需要编译,终端打开当前路径,输入:make,回车:


注意:这里的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

编译以后,生成了两个文件:bsdiff和bspatch。


bsdiff是用于生成patch的,命令格式:bsdiff

oldfile newfile patchfile

比如,旧版本:test1.0.apk,新版本:test2.0.apk,patch文件名称:test1.0_2.0.patch

输入:./bsdiff

test1.0.apk test2.0.apk test1.0_2.0.patch,等待几十秒,目录下会生成

test1.0_2.0.patch。


以上就是生成patch包的过程,这就完成了。

--------------------------------------华丽的分割线--------------------------------------

生成patch包以后,就是合成包了。

Bspatch就是用来合成包的,语法和bsdiff一模一样,参数顺序都一样:

bspatch

oldfile newfile

patchfile,只不过,bsdiff生成的文件是patchfile,而bspatch生成的文件是newfile。

试一下,为了区分,合成的新包,加了个”_NEW”后缀。如图:


命令测试成功了。

下一步,我们需要在android里实现这个功能。

因为需要用到jni,所以需要首先搭建NDK,不再介绍。

我们先计划一下:通过更新接口,查询时候有新版本,服务器,根据请求者的版本号,生成对应的patch包,命名规则:应用名_oldVersion-newVersion.patch,合成的新包命名:应用名_newVersion.apk,应用下载相应patch到cache目录,如果命名符合规则,则合成新包。合成新包以后,自动安装。

1,创建一个工程:PatchDemo:

2,创建一个新android

library

module,名字:bspatch;在bspatch模块的main目录下新建一个jni目录,将bsdiff目录里的bspatch.c复制到jni目录。因为项目依赖bzip2,需要自行下载bzip2,然后解压,带目录复制到jni目录,其实被依赖的只是部分文件,我并没有一一筛选。

再看下项目结构:


3,然后回到app

module,创建类BSPatcher,声明方法:

packagecom.zhouweixian.patchdemo.patch;

public

classBSPatcher {

static{

System.loadLibrary("bspatch");

}

public static native voidapplyPatch(String oldPath, StringnewPath, String patchPath);

}

4,打开as自带的终端,cd

app/src/main/java/,

使用javah生成头文件。javah

com.zhouweixian.patchdemo.patch.BSPatcher


可以看到,头文件已经生成了,剪切到bspatch

module的jni目录

打开bspatch.c,将main函数改一下名字,这里改成domain了。因为不再是主函数,而是要生成.so文件,被我们的java代码调用。

5,回到BSPatcher文件,找到里面的applyPatch方法,正常情况下,这个函数应该显示红色,光标选中,代码提示alt+enter(这个因人而异,快捷键可以调)如图:


选中第一条回车,as会自动创建一个格式良好的jni方法名,在bspatch.c文件里:


这样代码也就差不多了,打开app

module的build.gradle文件,添加一个NDK代码块:

ndk{

moduleName"bspatch"

ldLibs"log","z","m"

abiFilters"armeabi","armeabi-v7a","x86"

}


然后Build-->make

project,make完成,在bspatch

module里,找到build/intermediates/ndk/debug/lib目录,打开,我们发现,各个架构的.so文件都已生成:


将lib目录下的内容复制到bspatch/jniLibs目录下:


添加app对bspatch的依赖

到这里,jni的工作已经没有了,剩下的,就是如果调用bspatch的问题了。

创建一个PatchTask.java。因为生成新包的过程比较耗时,需要在工作线程中完成。

packagecom.zhouweixian.patchdemo.patch;

importandroid.os.AsyncTask;

importcom.zhouweixian.patchdemo.MyApplication;

/**

*将旧安装包和补丁合成新安装包,输入参数,补丁文件路径,合成的新包的路径

*输出参数,合成成功的新安装包的路径,如果失败返回null

* Created by zwx on 16-10-18

*/public

classPatchTaskextendsAsyncTask{

@Override

protectedString doInBackground(String... params){

try{

String oldVersionPath =AppUtils.getOldVersionPath(MyApplication.getInstance());

BSPatcher.applyPatch(oldVersionPath, params[0],

params[1]);

returnparams[0];

}catch(Exceptione) {

e.printStackTrace();

}

return null;

}

@Override

protected voidonPostExecute(Stringstr) {

super.onPostExecute(str);

if(str

!=null){

AppUtils.install(MyApplication.getInstance(), str);

}

}

@Override

protected voidonProgressUpdate(Integer... values) {

//可能没有明确的进度,需要提示用户等待,成功合成新安装包后自动安装super.onProgressUpdate(values);

}

}

在MainActivity里,添加一个button,在点击事件里,处理安装包的合成:

@Override

public

voidonClick(View v) {

switch(v.getId()) {

caseR.id.button:

newVersion=mEditText.getText().toString();

newPatchTask().execute(PathConstant.getNewApkPath(newVersion),

PathConstant.getPatchPath(newVersion));

break;

}

}

经测试,将新安装包放在应用的缓存目录会导致包解析失败,具体原因不明。

0 0
原创粉丝点击