什么是增量更新

增量更新是将两个不同版本的包,通过bsdiff工具进行二进制对比,生成差分文件。在更新的时候只需要将差分文件与当前包进行合成,生成新的apk。
通过生成差包,使用户在安装应用时不需要重新下载新版本,只需要更新需要更新的部分,可以大大节约用户流量。

实战

实战参考:

​https://github.com/cundong/SmartAppUpdates​​项目

1、下载上面地址的压缩文件,解压后如下图:

Android 增量更新_android


打开Eclipse导入ApkPatchLibrary

2、NDK配置:

这篇博客仅限看完1、2步操作(剩下部分作为熟悉与了解吧),

之后选中ApkPatchLibrary项目按照下面这篇博客仅配置(3)小节即可。

配置完毕clean当前项目,可以在libs目录下出现libApkPatchLibrary.so包。

Android 增量更新_so文件_02


上面是别人为我们提供的so但是如果我们自己的项目想要使用so库需要

3、新建项目添加权限

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>

4、开始jni调用

(1)右击项目:Android Tools ——》Add Native Support输入,将要生成的so库名称:ApkPatchLibrary,项目右击选择refresh。

(2)将ApkPatchLibrary项目中jni目录下的几个文件进行拷贝。

Android 增量更新_差分_03


(3)编写本地方法( static native)并加载(System.loadLibrary())

package com.example.apkdifftest;
public class PathUtils

/**
* @param oldApkPath 旧apk地址
* @param newApkPath 新apk地址
* @param patchPath
* @return
public static native int patch(String oldApkPath, String newApkPath,
String patchPath);
/**
* 2、加载so文件(不加lib跟.so)
*/
static{
System.loadLibrary("ApkPatchLibrary");
}
}

(4)对复制的文件进行修改。

Android 增量更新_so文件_04


对文件名进行修改,修改格式为包名+类名,如上图所示。

Android.mk的修改

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
//调用的本地产生的so文件(so文件在项目clean时会自动创建)
LOCAL_MODULE := ApkPatchLibrary
//调用的c代码
LOCAL_SRC_FILES := com_example_apkdifftest_PathUtils.c
//Android中log打印库

c文件与h文件修改
h文件:将方法名中的包名部分该为自己的包名

a_com_example_apkdifftest_PathUtils_patch(JNIEnv *, jclass, jstring, jstring, jstring);

c文件

//修改1
#include "com_example_apkdifftest_PathUtils.h"
//修改2
JNIEXPORT jint JNICALL Java_com_example_apkdifftest_PathUtils_patch(JNIEnv *env,
jobject obj, jstring old, jstring new, jstring patch)

(5)
界面:一个TextView显示版本号,Button点击时进行差分包合成,合成成功将进行安装。重新打开的app将显示新的版本号。

public class MainActivity extends Activity implements OnClickListener{
private TextView mTextView;
private Button mButton;
//3、差分包路径
private String path=Environment.getExternalStorageDirectory()+File.separator;
private String new_apk_path;
private String patch_path;

private Handler mHanler=new Handler(){
public void handleMessage(android.os.Message msg) {
if(msg.what==0){
//这里需要进行签名验证
installApk();

}else {
Toast.makeText(getApplicationContext(), "合成失败", Toast.LENGTH_SHORT).show();
}


}

};

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView=(TextView) findViewById(R.id.tv);
mButton=(Button) findViewById(R.id.bt);
mButton.setOnClickListener(this);
File file=new File(path+"ApkPatch");
if(!file.exists()){
file.mkdirs();
}
new_apk_path=file.getAbsolutePath()+File.separator+"ApkDiffTest.apk";
patch_path=file.getAbsolutePath()+File.separator+"ApkDiffTest.patch";
Toast.makeText(getApplicationContext(), patch_path, Toast.LENGTH_LONG).show();
}

@Override
public void onClick(View arg0) {
//开启子线程,从网络下载差分包,
//这里直接将差分包放到上面的目录下了
new PatchThread().start();
}
private void installApk() {
File file=new File(new_apk_path);
if(!file.exists()){
Toast.makeText(getApplicationContext(), "新的包不存在", Toast.LENGTH_SHORT).show();

}
Uri uri=Uri.fromFile(file);
Intent intent=new Intent(Intent.ACTION_VIEW);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setDataAndType(uri, "application/vnd.android.package-archive");
startActivity(intent);
}
class PatchThread extends Thread{
@Override
public void run() {
String old_apk_path=getApplicationContext().getApplicationInfo().sourceDir;
int result=PathUtils.patch(old_apk_path, new_apk_path, patch_path);
if(result==0){
mHanler.sendEmptyMessage(0);
}else{
mHanler.sendEmptyMessage(-1);
}
super.run();
}
}



}

(6)差分包的生成,使用bsdiff工具

工具下载地址:​​http://www.daemonology.net/bsdiff/​

我的是windows系统就直接下载的window下的工具

Android 增量更新_android_05


将下载的压缩文件解压到bsdiff4.3-win32,同时将版本1.0与版本2.0的apk放到bsdiff4.3-win32文件加下。

Android 增量更新_so文件_06


差分包是通过命令行产生的:​​bsdiff oldversionpath newversionpath patchpath​

Android 增量更新_差分_07

PS:CDT配置:

也可以通过ApkPatchLibrary设置过的CDT直接设置给自己的项目,具体如下图所示。

Android 增量更新_差分_08