现在公司对于app增量更新的需求越来越多,因为增量更新不仅仅可以节省流量,更重要的一点是减少用户更新app的时间,有益于用户体验。 这篇文章将介绍运用patch差分包的形式实现增量更新。为了方便,就将生成差分包和合并差分包这两个过程都放在安卓机上完成。正常情况下差分包的生成是在服务端完成的。
准备工作:
ndk配置,使用android studio2.2及以上版本(eclipse也是可以得,这里介绍android studio)
1)安装下图箭头标识的三个工具: LLDB是一个调试工具,有了它可以在Android Studio上对native代码进行断点调试 CMake是个开源的跨平台自动化建构系统,它用配置文件控制建构过程(build PRocess)的方式和Unix的Make相似,CMake配置文件取名为CMakeLists.txt NDK是一个工具集,它使得开发者可以使用native代码(c、c++等等)实现app的部分功能,它提供了一份稳定的、功能有限的api头文件声明;这是进行NDK开发的核心工具,将c/c++代码编译成动态链接库so就是由它完成的(确切的说是通过NDK调用gcc来完成的)

2)新建一个项目将include C++ support勾上即可

3)项目创建好后会有一个CmakeLists文件(配置c/c++代码的编译选项)和cpp文件夹(c/c++代码写在这里)

bsdiff和bspatch源码下载,只需要bsdiff.c和bspatch.c两个c代码文件就行

bzip2源码下载,因为bsdiff和bspatch都依赖bzip2。需要如下文件

以上准备完成后,将bspatch.c和bsdiff.c以及需要的bzip2的代码文件添加到项目的cpp文件夹下,再新建一个bs.h头文件,用于函数的声明,并将bspatch.c和bsdiff.c中的main函数都改名(只要名字不是main就可以),接下来就开始写代码了,其实要写的代码不多,总共不超过100行
java代码:
public class MainActivity extends AppCompatActivity { //旧版本 String old =getsdpath()+"hello.apk"; //新版本 String newp = getsdpath()+"hehehe.apk"; //差分包 String patch = getsdpath()+"patch.patch"; //旧版apk和差分包合并生成的新版apk String tmp = getsdpath()+"new.apk"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } public void click(View view){ switch (view.getId()){ case R.id.bt_diff: long s = System.currentTimeMillis(); diff(old,newp,patch); long s1 = System.currentTimeMillis(); Toast.makeText(this,"生成差分包成功,用时:"+(s1-s)+"ms",Toast.LENGTH_SHORT).show(); break; case R.id.bt_patch: long s2 = System.currentTimeMillis(); patch(old,tmp,patch); long s3 = System.currentTimeMillis(); Toast.makeText(this,"差分包合并成功,用时:"+(s3-s2)+"ms",Toast.LENGTH_SHORT).show(); break; } } private String getsdpath(){ return Environment.getExternalStorageDirectory().getPath()+ File.separator; } //生成差分包 public native int diff(String oldpath,String newpath,String patch); //旧apk和差分包合并 public native int patch(String oldpath,String newpath,String patch); // Used to load the 'native-lib' library on application startup. static { System.loadLibrary("native-lib"); }}重点是下面两个native函数,分别对应生成差分包和合并:
//生成差分包 public native int diff(String oldpath,String newpath,String patch); //旧apk和差分包合并 public native int patch(String oldpath,String newpath,String patch);C代码: bs.c:
#include "bs.h"JNIEXPORT jint JNICALLJava_com_example_lebronsn_bsdiffpatch_MainActivity_patch (JNIEnv *env, jobject instance, jstring oldpath_, jstring newpath_,jstring patch_) { const char* argv[4]; argv[0] = "bspatch"; argv[1] = (*env)->GetStringUTFChars(env,oldpath_, 0); argv[2] = (*env)->GetStringUTFChars(env,newpath_, 0); argv[3] = (*env)->GetStringUTFChars(env, patch_, 0); //该函数用于合并差分包 mypatch(4,argv); (*env)->ReleaseStringUTFChars(env,oldpath_, argv[1]); (*env)->ReleaseStringUTFChars(env,newpath_, argv[2]); (*env)->ReleaseStringUTFChars(env,patch_,argv[3]); free(argv); return 0;}JNIEXPORT jint JNICALLJava_com_example_lebronsn_bsdiffpatch_MainActivity_diff (JNIEnv *env, jobject instance, jstring oldpath_, jstring newpath_, jstring patch_) { const char* argv[4]; argv[0] = "bsdiff"; argv[1] = (*env)->GetStringUTFChars(env,oldpath_, 0); argv[2] = (*env)->GetStringUTFChars(env,newpath_, 0); argv[3] = (*env)->GetStringUTFChars(env, patch_, 0); //该函数用于生成差分包 mydiff(4,argv); (*env)->ReleaseStringUTFChars(env,oldpath_, argv[1]); (*env)->ReleaseStringUTFChars(env,newpath_, argv[2]); (*env)->ReleaseStringUTFChars(env,patch_,argv[3]); free(argv[0]); free(argv); return 0;}这段代码重点在调用的两个函数:mypatch(4,argv)和mydiff(4,argv)。 其中mypatch()是bspatch中的main函数改名而来,mydiff()是bsdiff中的main函数改名而来
头文件bs.h:
#ifndef BSDIFFPATCH_BS_H#define BSDIFFPATCH_BS_H#endif //BSDIFFPATCH_BS_H#include <malloc.h>#include <jni.h>int mydiff(int argc,char *argv[]);int mypatch(int argc,char * argv[]);JNIEXPORT jint JNICALL Java_com_example_lebronsn_bsdiffpatch_MainActivity_patch (JNIEnv *env, jobject instance, jstring oldpath_, jstring newpath_,jstring patch_);JNIEXPORT jint JNICALL Java_com_example_lebronsn_bsdiffpatch_MainActivity_diff (JNIEnv *env, jobject instance, jstring oldpath_, jstring newpath_, jstring patch_);CmakeList配置:
cmake_minimum_required(VERSION 3.4.1)add_library( native-lib SHARED src/main/cpp/bspatch.c src/main/cpp/bsdiff.c src/main/cpp/bs.c src/main/cpp/bzip2/blocksort.c src/main/cpp/bzip2/bzip2.c src/main/cpp/bzip2/bzip2recover.c src/main/cpp/bzip2/bzlib.c src/main/cpp/bzip2/compress.c src/main/cpp/bzip2/crctable.c src/main/cpp/bzip2/decompress.c src/main/cpp/bzip2/huffman.c src/main/cpp/bzip2/randtable.c )find_library( log-lib log )target_link_libraries( native-lib ${log-lib} )到这里整个就算完成了,再贴一个cpp文件夹的内容:

我把项目代码上传了,在这里下载。 生成差分包的时间会长一点,合并会相对来说快一点。
后记: bsdiff并不是专门为apk增量更新设计的,它可以对任何二进制文件进行差分和合并。bzip2的功能是利用哈夫曼编码对文件进行无损压缩(将差分包进行压缩便于网络传输)和解压。所以完整的流程是这样的:
bsdiff生成patch->bzip2压缩->android下载patch->bzip2解压patch->bspatch合并patch->新的apk
这只是分割线而已
新闻热点
疑难解答