一 Android 增量更新简介
首先需要明确,Android增量更新与热修复是不同的技术概念。
热修复一般是用于当已经发布的app有Bug需要修复的时候,开发者修改代码并发布补丁,让应用能够在不需要重新安装的情况下实现更新,主流方案有Tinker、AndFix等。
而增量更新的目的是为了减少更新app所需要下载的包体积大小,常见如手机端游戏,apk包体积为几百M,但有时更新只需下载十几M的安装包即可完成更新。
增量更新原理简单来讲,就是通过二进制算法找出新版本和旧版本安装包的差异,并将差异提取出来生成所谓的补丁包(差分包)。移动端检查更新时,只需要向服务器申请下载相对应的补丁包,然后将差分包与自身旧版本apk合并生成最新版本的apk。最终安装合并生成的apk即可完成版本更新。
功能的实现主要是借助第三方差分工具,相当于做记录,方便以后回忆。
二 增量更新过程的演示
增量更新主要有两个过程,第一是后台将最新的apk(v1.0.1)与旧版本(v1.0.0)做对比,并生成差分包。第二步是移动端下载相对应的差分包,并在本地合并生成完整的最新apk,并引导用户安装。
对于apk包的差分和合并,需要借助bsdiff工具来实现
下载bsdiff_win_exe.zip并解压到本地
其中bsdiff.exe是window用来生成差分包的工具,而bspatch是用来合成差分包的工具
2.1 生成差分包
首先,分别打一个旧的apk(v1.0.0.apk),和一个新的apk(v1.0.1.apk),并存放在之前解压的目录。
然后打开Windows命令行工具,切换到该目录,打入命令bsdiff v1.0.0.apk v1.0.1.apk patch.patch
就能在目录下看见生成的差分包patch.patch
2.2 合成差分包
保持在当前目录,命令行输入bspatch v1.0.0.apk new.apk patch.patch
就能在当前目录下看见合成的完整安装包new.apk
生成的new.apk与v1.0.1.apk是完全相同的,安装即可。
三 Android端应用增量更新
上述过程是为了演示整个流程,现在要应用到Android端。Android移动端在增量更新过程中,只负责下载和合并差分包,并引导用户安装。因此假设已经下载好对应的差分包。主要需要三步:第一是获取本身旧apk路径;第二是将差分工具集成到Android端;第三是调用方法合并差分包并引导用户安装。
3.1 获取已安装的旧apk路径
//获取现在运行的apk路径
String oldApk = getApplicationInfo().sourceDir;
3.2 集成差分合并功能到Android端
bsdiff开源工具源码为.c文件,即Android端需要配置JNI(以下是基于CMake)。
为方便集成,已将所需功能打成so包,可以直接导入so包,跳过此步骤。百度网盘链接(提取码:8ia7)
bsdiff源码依赖bszip,所以需要同时下载两者的源码;或者百度网盘下载(提取码:psbu)
3.2.1 导入所需源文件
- 解压bsdiff-4.3.tar.gz文件,将bspatch.c文件复制到Android 的cpp目录中
- 解压bzip2-1.0.6.tar.gz文件,并按图将所需源文件复制到Android 的cpp/bzip目录中
- 修改bspatch.c文件内容
(1)修改bzlib.h的导入声明:打开bspatch.c文件,修改头文件
(2)找到main方法,并将其改名为execute_patch
3.2.2 配置CMakLists.txt文件
cmake_minimum_required(VERSION 3.4.1)
# 查找文件系统中指定模式的路径,如/* 匹配根目录的文件(注意路径)
file(GLOB bzip_source ${CMAKE_SOURCE_DIR}/bzip/*.c)
# 设置本地动态库 编译生成动态库
add_library(
#模块名
native-lib
# 动态库/分享可以
SHARED
#源文件
native-lib.cpp
#配置相应的文件引用
bspatch.c
${bzip_source}
)
find_library(
log-lib
log)
target_link_libraries(
native-lib
${log-lib})
3.2.3 往native-lib.cpp里添加调用方法
extern "C" {
extern int execute_patch(int argc, char *argv[]);
}
extern "C"
JNIEXPORT void JNICALL
Java_com_example_myapplication_utilities_BsPatchUtil_patch(JNIEnv *env, jobject instance, jstring oldApk_,
jstring patch_, jstring output_) {
//将java字符串转换成char指针
const char *oldApk = env->GetStringUTFChars(oldApk_, 0);
const char *patch = env->GetStringUTFChars(patch_, 0);
const char *output = env->GetStringUTFChars(output_, 0);
//bspatch ,oldfile ,newfile ,patchfile
char *argv[] = {"", const_cast<char *>(oldApk), const_cast<char *>(output),
const_cast<char *>(patch)};
execute_patch(4, argv);
// 释放相应的指针gc
env->ReleaseStringUTFChars(oldApk_, oldApk);
env->ReleaseStringUTFChars(patch_, patch);
env->ReleaseStringUTFChars(output_, output);
}
注意:Java_com_example_myapplication_utilities_BsPatchUtil_patch
方法名需要根据实际定义更改
3.3 定义方法:Java层使用合成功能
定义个BsPatchUtil
类,调用c代码:(该方法名因与上面提到的Java_com_example_myapplication_utilities_BsPatchUtil_patch
方法名相对应)
public class BsPatchUtil {
static {
System.loadLibrary("native-lib");
}
/** * @param oldApkPath 旧apk文件路径 * @param newApkPath 新apk文件路径 * @param patchPath 生成的差分包的存储路径 */
public static native void patch(String oldApkPath, String newApkPath, String patchPath);
}
3.4 合成差分包
//已安装的旧apk的路径
val oldApk = applicationInfo.sourceDir
// 差分包的路径
val patch = ...
// 合成之后的新apk的存储路径
val output = ...
//合成apk包
BsPatchUtil.patch(oldApk, patch, output)
合成差分包需要在子线程中运行,防止阻塞主线程。最终引导用户安装新生成的apk即可。
今天的文章Android增量更新分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/21221.html