Android NDK实现apk文件的增量更新

0、前言

 很久没有更新博客了,这篇文章计划总结一下实习期间在公司做的技术预研——Android apk文件的增量更新。相关代码的下载可以访问以下github链接(点击此处浏览),本文也是在此基础之上进行总结的。

1、原理介绍

 关于增量更新,举个栗子,如果一个旧版应用有10M,一个新版应用有30M,在传统的应用更新过程中,用户必须将这30M的新版apk文件完整地从服务器下载到手机本地并安装,才能完成应用更新,但实际上更新的部分可能只占整个应用的一小部分,用户将不得不消耗极大的流量去下载与旧版apk文件相同的内容。
 在增量更新的过程中,服务器会生成一个例如12M左右的差分包,用户只需要将这个差分包下载到手机本地,与旧版应用的apk文件进行合并,即可得到新版应用的apk文件,这个过程实际上就是在打补丁,比起传统的应用更新,可节约18M左右的流量,在更新时间上也能提供更好的用户体验。

2、过程分析

 接下来将对增量更新的具体实现过程进行总结,主要是开源的二进制比较工具bsdiff的使用( bsdiff源码下载链接)。因为bsdiff依赖bzip2中的文件,所以项目中还需要引入bzip2的源码( bzip2源码下载链接)。在bsdiff源码中,bsdiff.c 用于生成差分包,bspatch.c 用于合成文件。

2.1 差分包的生成

 差分包的生成一般是在服务器端实现,每当有新版apk文件上传到服务器,过对新旧版本apk文件的比较,即可生成相对应的.patch差分包。由于相关项目的服务器是部署在Linux环境下,因此生成差分包的过程打算采用NDK编程的方式模拟实现,NDK开发环境的搭建可以参考以下链接( 点击此处访问
 首先新建一个DiffUtils类,声明native方法,用于调用底层的C函数,代码如下所示:
public class DiffUtils {
	/**
	 * 
	    * @Title: genDiff
	    * @Description: 比较新旧apk文件的差异,生成patch文件,存放于patchPath
	    * @param oldApkPath 示例:/sdcard/old.apk
	    * @param newApkPath 示例:/sdcard/new.apk
	    * @param patchPath  示例:/sdcard/xx.patch
	    * @return 0
	    * @throws
	 */
	public static native int genDiff(String oldApkPath, String newApkPath, String patchPath);
}

 接下来可以将ApkPatchLibraryServer/jni目录下的文件全部复制到自己工程的jni目录下,记得把文件名和函数名修改成与自己工程相对应的名字,如下图所示:


其中com_lyq_apkaddupdate_utils_DiffUtils.c文件中的Java_com_lyq_apkaddupdatedemo_utils_DiffUtils_genDiff方法,就是在Java代码中调用的用于生成差分包的native方法,代码如下所示:


 然后在jni目录下新建一个Android.mk文件,将C代码进行编译生成库文件,代码及相应注释如下所示:

#mk文件必须以定义LOCAL_PATH为开始,返回包含Android.mk的目录路径
LOCAL_PATH := $(call my-dir)
#负责清理LOCAL_xxx,因为所有的编译控制文件由同一个GNU Make解析和执行,
#其变量是全局的,所以清理后才能避免相互影响
include $(CLEAR_VARS)
#生成模块的名字
LOCAL_MODULE := ApkAddUpdateServer
#不检查未定义的符号,用于处理undefined reference to错误
LOCAL_ALLOW_UNDEFINED_SYMBOLS := true

#获取$(LOCAL_PATH)目录即jni目录下的所有要编译的.c文件,并把结果放在变量MY_CPP_LIST里
MY_CPP_LIST := $(wildcard $(LOCAL_PATH)/*.c)
MY_CPP_LIST += $(wildcard $(LOCAL_PATH)/bzip2/*.c)
LOCAL_SRC_FILES := $(MY_CPP_LIST:$(LOCAL_PATH)/%=%)

#BUILD_STATIC_LIBRARY:编译为静态库
#BUILD_SHARED_LIBRARY:编译为动态库 
#BUILD_EXECUTABLE:编译为Native C可执行程序
include $(BUILD_SHARED_LIBRARY)
 保存后编译器会自动开始编译或者clean一下工程开始编译,编译成功后,即可看到libs/armeabi/目录下将生成一个.so文件,运行程序调用该文件,传入新旧版本apk文件的路径,以及.patch差分包文件的路径,即可生成.patch差分包,如下图所示:


2.2 与旧版apk的合成

 合成新版apk的实现过程与差分包的生成类似。新建一个PatchUtils类,声明native方法,调用com_lyq_apkaddupdate_utils_PatchUtils.c文件中的Java_com_syd_apkaddupdateserver_utils_PatchUtils_patch方法,代码如下所示:


 重新生成一个.so文件,运行程序调用该文件,传入新旧版本apk文件的路径,以及.patch差分包文件的路径,即可生成新版apk文件,如下图所示:

 为了验证合成之后的apk文件是否与真正的新版apk文件相同,可以对二者进行MD5校验,如果获取到的MD5值相等,说明两份apk文件完全相同,本次增量更新成功,调用系统的应用安装程序,即可完成新版apk文件的安装。

        点击下载演示Demo

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值