增量概述
之前在创业公司,人手不够,业务人员也要参与功能测试。有一段时间,应用的版本迭代非常快,基本上两天一版,测试时要重新下版本。当时,就有参与测试的人员抱怨说:测得这么频繁,能不能出个补丁啊,就不用整个下了。我那时候的回答的:这和游戏不一样,都是重新下载的。后来才发现,增量更新也是能够实现的。现在我带大家来了解下增量更新的条件与步骤。
增量更新的重点在于生成增量文件并且和老文件合并:
1. 获取老的apk(如果手机上存在老版本应用的话)
2. 生成增量文件(对比老apk)
3. 增量文件和老apk合并
增量文件的生成都是通过工具做二进制的一个diff和patch了。
工具的下载地址:
http://www.daemonology.net/bsdiff/bsdiff-4.3.tar.gz
解压后执行一下步骤
1.解压文件里面有个文件:Makefile,以文本的形式打开,将install:下面的if,endif添加一个缩进。
添加后文件如下所示:
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
2.生成的bspatch和bsdiff只需要用到bsdiff,bsdiff用于服务端生成的增量文件,bspatch用于合并old.apk和增量文件肯定,在应用内部做
在拿到bsdiff和bspatch以后,可以愉快的使用他们的:修改应用代码生成老的和心的apk
生成增量文件
./bsdiff old.apk new.apk old-to-new.patch
这样就生成了一个增量文件old-to-new.patch
增量文件和old.apk合并成新的apk
./bspatch old.apk new2.apk old-to-new.patch
至此我们已经在测试中完成的增量文件的生成和合并,但在实际中合并的过程是在客户端实现的:提取原来的apk,与增量文件合并
客户端操作
1.提取当前apk
public class ApkExtract {
public static String extract(Context context) {
context = context.getApplicationContext();
ApplicationInfo applicationInfo = context.getApplicationInfo();
String apkPath = applicationInfo.sourceDir;
Log.d("hongyang", apkPath);
return apkPath;
}
}
2.制作bspatch so
这里需要一些ndk的知识
首先声明一个类,写个native方法,如下:
public class BsPatch {
static {
System.loadLibrary("bsdiff");
}
public static native int bspatch(String oldApk, String newApk, String patch);
}
三个参数已经很明确了;
同时别忘了在module的build.gradle下面:
defaultConfig {
ndk {
moduleName = 'bsdiff'
}
}
接下来就是去完成c的代码的编写了;
首先在app/main目录下新建一个文件夹jni,把之前下载的bsdiff中的bspatch.c拷贝进去;
然后按照jni的规则,在里面新建一个方法:
JNIEXPORT jint JNICALL Java_com_zhy_utils_BsPatch_bspatch
(JNIEnv *env, jclass cls,
jstring old, jstring new, jstring patch){
int argc = 4;
char * argv[argc];
argv[0] = "bspatch";
argv[1] = (char*) ((*env)->GetStringUTFChars(env, old, 0));
argv[2] = (char*) ((*env)->GetStringUTFChars(env, new, 0));
argv[3] = (char*) ((*env)->GetStringUTFChars(env, patch, 0));
int ret = patchMethod(argc, argv);
(*env)->ReleaseStringUTFChars(env, old, argv[1]);
(*env)->ReleaseStringUTFChars(env, new, argv[2]);
(*env)->ReleaseStringUTFChars(env, patch, argv[3]);
return ret;
}
上面的操作完成后,最后一步就简单了,首先准备两个apk:
old.apk new.apk
1
1
然后制作一个patch,下面代码中的PATCH.patch;
将old.apk安装,然后将new.apk以及PATCH.patch放置到存储卡;
最后在Activity中触发
private void doBspatch() {
final File destApk = new File(Environment.getExternalStorageDirectory(), "dest.apk");
final File patch = new File(Environment.getExternalStorageDirectory(), "PATCH.patch");
//一定要检查文件都存在
BsPatch.bspatch(ApkExtract.extract(this),
destApk.getAbsolutePath(),
patch.getAbsolutePath());
if (destApk.exists())
ApkExtract.install(this, destApk.getAbsolutePath());
}//启读写SDCard权限,记得在代码中校验需要的文件都存在。
install实际就是通过Intent去安装了:
public static void install(Context context, String apkPath) {
Intent i = new Intent(Intent.ACTION_VIEW);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
i.setDataAndType(Uri.fromFile(new File(apkPath)),
"application/vnd.android.package-archive");
context.startActivity(i);
}
以上来自于弘洋的博客,相关工具已经封装好了,原地址
http://blog.csdn.net/lmj623565791/article/details/52761658