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

来源:互联网 发布:淘宝旧货二手市场 编辑:程序博客网 时间:2024/06/06 17:07

0、前言

        很久没有更新博客了,这段时间总算是顺利毕业并且在实习的公司转正了,以后的目标就是多学习一些技术,争取早日成为能够独当一面的软件工程师。这篇文章计划总结一下实习期间在公司做的技术预研——Android apk文件的增量更新。相关代码的下载可以访问以下github链接:https://github.com/cundong/SmartAppUpdates,本文也是在此基础之上进行总结的。

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开发环境的搭建可以参考以下链接:http://www.cnblogs.com/yejiurui/p/3476565.html
首先新建一个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

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 户口注销了社保怎么办 科一指纹录不上怎么办 右倒库右边太宽怎么办 手机录不了指纹怎么办 6sp指纹不灵敏怎么办 手指纹汗多怎么办? 手指没指纹怎么办身份证 青岛身份证丢了怎么办 新身份证没激活怎么办 坐轻轨没身份证怎么办 办身份证指纹录不上怎么办 指纹固化剂干了怎么办 指纹解锁没反应怎么办 荣耀v8指纹失灵怎么办 指纹多次不匹配怎么办 华为指纹被禁用怎么办 手脱皮没有指纹怎么办 手脱皮手机指纹怎么办 手脱皮录指纹怎么办 科二指纹打不上怎么办 三星手机无法解锁怎么办 iphone7指纹坏了怎么办 苹果8录不上指纹怎么办 手机套总是粘指纹怎么办 华为p9指纹禁用怎么办 华为p10升级失败怎么办 手机指纹锁没反应怎么办 华为手机指纹禁用怎么办 excel输入值非法怎么办 excel表数字乱码怎么办 excel表格打不开了怎么办 表格中数字乱码怎么办 手机颜色变了怎么办 身份证上的字母怎么办 身份证被盗用贷款怎么办 刑拘在逃不归案怎么办 在逃人员抓不到怎么办 卖假烟被网上追逃怎么办? 同事贷款不还怎么办 支付宝怎么办信用卡2 钱站逾期一天怎么办