Android增量更新 – 客户端使用bsdiff差分包与原包合并
bsdiff简介
Android增量更新需要用到二进制差分工具:bsdiff
bsdiff and bspatch are tools for building and applying patches to binary files.
官方网站:http://www.daemonology.net/bsdiff/
bsdiff for windows:http://www.pokorra.de/coding/bsdiff.html
Android版本区别设定
(1)旧版本
app.gradle
versionCode 1
versionName "1.0"
activity_main.xml
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="20dp"
android:text="1.0版本"
android:textSize="16sp"
android:textColor="#3BC1FF"
/>
(2)新版本
添加资源文件:assets/cctv.mp4
app.gradle
versionCode 2
versionName "2.0"
activity_main.xml
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="20dp"
android:text="2.0版本"
android:textSize="16sp"
android:textColor="#3BC1FF"
/>
NDK实现pacth
Java层声明native方法
public class BsPatch {
/**
* 合并
* @param oldFilePath
* @param newFilePath
* @param patchFilePath
*/
public static native void patch(String oldFilePath, String newFilePath, String patchFilePath);
static {
System.loadLibrary("BsPatch");
}
}
C层合并算法实现:diffupdate.c
Java层调用bspatch实现bsdiff差分包与原包合并
class AppUpdateTask extends AsyncTask<Void, Void, Boolean> {
@Override
protected Boolean doInBackground(Void... params) {
//1. 下载差分包
Log.i(TAG, "开始下载");
//File patchFile = DownloadUtil.download(PATCH_URL);
//String patchFilePath = patchFile.getAbsolutePath();
Log.i(TAG, "下载完成");
//2. 获取旧版本已经安装的apk文件(/data/app/)
String oldApk = ApkUtil.getSourceApkPath(MainActivity.this, getPackageName());
Log.i(TAG, "Old Apk: " + oldApk);
//3. 合并:oldFile+patchFile->newFile
BsPatch.patch(oldApk, NEW_APK_PATH, PATCH_FILE_PATH);
Log.i(TAG, "合并完成");
try {
Log.i(TAG, "New Apk MD5: " + MD5Util.getFileMD5String(NEW_APK_PATH));
} catch (IOException e) {
e.printStackTrace();
}
return true;
}
@Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
if (!result) {
Toast.makeText(MainActivity.this, "差分包合并失败", Toast.LENGTH_SHORT).show();
}
//1. 获取两个版本的签名进行对比
//获取已经安装应用的签名
String oldSign = SignUtil.getInstalledApkSignature(MainActivity.this, getPackageName());
//获取未安装Apk文件的签名
String newSign = SignUtil.getUnInstalledApkSignature(NEW_APK_PATH);
if (TextUtils.equals(newSign, oldSign)) {
//2. 安装
ApkUtil.installApk(MainActivity.this, NEW_APK_PATH);
} else {
Toast.makeText(MainActivity.this, "签名不匹配", Toast.LENGTH_SHORT).show();
}
Toast.makeText(MainActivity.this, "差分包合并成功", Toast.LENGTH_SHORT).show();
}
}
app.gradle 配置
defaultConfig {
...
externalNativeBuild {
cmake {
cppFlags "-frtti -fexceptions"
abiFilters 'x86', 'x86_64', 'armeabi', 'armeabi-v7a', 'arm64-v8a'
}
}
}
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
安装测试
> adb push diff.patch /sdcard/ //将差分包导入到SD卡中,模拟在线更新
[100%] /sdcard/diff.patch
> adb install DiffUpdate_v1.apk //安装旧版Apk以待测试增量更新
[100%] /data/local/tmp/DiffUpdate_v1.apk
pkg: /data/local/tmp/DiffUpdate_v1.apk
Success
>
运行日志输出,可以看到合并生成的 New Apk MD5 与服务器端合并生成的完全一致
cc.androidios.diffupdate I/yezhou: Old Apk: /data/app/cc.androidios.diffupdate-1/base.apk
cc.androidios.diffupdate I/yezhou: 合并完成
cc.androidios.diffupdate I/yezhou: New Apk MD5: 735a02764167048e738a7f6ea99f2b86
核心技术点
bspatch功能调用
bspatch的使用方法为
bspatch oldfile newfile patchfile
bspatch.c的main函数为其入口函数,这里将函数名改为bspatch_main,变为普通函数,即可实现被其它函数调用。
int bspatch_main(int argc, char * argv[])
CMakeLists.txt 配置
版权声明:
作者:Joe.Ye
链接:https://www.appblog.cn/index.php/2023/05/01/android-incremental-update-client-merge-bsdiff-differential-package-with-original-package/
来源:APP全栈技术分享
文章版权归作者所有,未经允许请勿转载。
共有 0 条评论