BsDiff算法介绍:
bsdiff是由Conlin Percival开源的一个优秀的差分算法,而且是跨平台的。在目前很多大厂的app中都包含一个bspatch.so的库,其实主要是用于组装差分包的。感兴趣的同学可以看一下。增量更新使用的好处主要有两点:1、对用户来说,下载速度快,省流量,提高用户体验 2,对服务器来说,减少服务器的带宽压力。
源码下载:
https://github.com/cnSchwarzer/bsdiff-win/releases
算法原理:
https://www.cnblogs.com/startkey/p/10678173.html
android使用:
1、 native工程
android studio新建native c++工程,新建好功能后,打开main目录,可以看到入下图所示:

在cpp文件夹中拷贝bsdiff源码中的bzip2文件夹,并且将bsdiff.c 和bspatch.c文件也拷贝到cpp目录中,然后再CMakeLists.text中进行配置:
cmake_minimum_required(VERSION 3.4.1)
//bzip2文件夹下的文件较多是,使用目录来进行引入
aux_source_directory(bzip2 SOURCES)
add_library(
DiffUtils //此处是可以为您所需的library的名字
SHARED
native-lib.cpp
bspatch.c //新引入的文件
bsdiff.c //新引入的文件
${SOURCES})
include_directories(bzip2)
target_link_libraries(
DiffUtils //此处是可以为您所需的library的名字
log)
2、Java ,JNI,C++结构搭建
在java目录中添加BsPatchUtils工具供java代码调用:
public class BsPatchUtils {
static{
System.loadLibrary("DiffUtils"); //此处的library的名字未您在CMakeLists.text中指定的名称
}
//组装差分包
public static native int patch(String oldApk,String newApk,String patchFile);
//获取差分包
public static native int diff(String oldApk ,String newApk,String dissFile);
}
3、功能实现
在 BsPatchUtils工具中对应的patch ,diff静态nativie方法上使用alt+enter快捷键,生成对应的jni代码,如:cpp/native-lib.cpp所示:
注意:
1. 下载好bsdiff源码后,自己可以编译生成对应的exe文件,在命令行执行bsdiff命令可知,需要的参数说明:
命令行:
bsdiff oldfile newfile patchfile
bspatch oldfile newfile patchfile
oldfile -------原文件的名称
newfile ------新文件的名称
patchfile --------差分文件名
上述差分和组包指令需要四个参数:指令,oldfile ,newfile ,patchfile ,那么我们在下面的使用中就需要传递四个参数。
extern "C" {
//特别说明:此处的executePatch 方法是将bspatch.c中的main方法修改了一下名字,方便区分的, executeDiff方法类似。
extern int executePatch(int argc, char *argv[]);
extern int executeDiff(int argc, char *argv[]);
}
/*
* TODO 组装新包
*/
extern "C"
JNIEXPORT jint JNICALL
Java_com_leon_bsdiffupdatedemo_BsPatchUtils_patch(JNIEnv *env, jclass clazz, jstring old_apk,
jstring new_apk, jstring patch_file) {
// TODO: implement patch()
int args = 4;
char *argv[args];
argv[0] = "DiffUtils";
argv[1] = (char *) (env->GetStringUTFChars(old_apk, 0));
argv[2] = (char *) (env->GetStringUTFChars(new_apk, 0));
argv[3] = (char *) (env->GetStringUTFChars(patch_file, 0));
//此处executePathch()就是上面我们修改出的
int result = executePatch(args, argv);
env->ReleaseStringUTFChars(old_apk, argv[1]);
env->ReleaseStringUTFChars(new_apk, argv[2]);
env->ReleaseStringUTFChars(patch_file, argv[3]);
return result;
}
4、java使用
public void patch() {
File newFile = new File(getExternalFilesDir("apk"), "app.apk");
File patchFile = new File(getExternalFilesDir("apk"), "patch.apk");
int result = BsPatchUtils.patch(getApplicationInfo().sourceDir, newFile.getAbsolutePath(),
patchFile.getAbsolutePath());
if (result == 0) {
install(newFile);
}
}
private void install(File file) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { // 7.0+以上版本
Uri apkUri = FileProvider.getUriForFile(this, getPackageName() + ".fileprovider", file);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
} else {
intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
}
startActivity(intent);
}
总之,使用差分算法对安装包进行差分包处理,这样在服务器端只提供差分包共用户下载更新,虽然更新下载速度比较快,但是每次都需要安装,这个问题作一记录。
网友评论