Android平台-实现应用增量更新

1.概述

1.1.什么是应用增量更新

当我们要更新一个应用的时候,以前很多更新的做法是下载一个新版本去覆盖一个旧版本。随着现在应用越来越大,我们就不得不考虑流量的问题。

Google也意识到不断更新应用对用户流量的损耗,于是在Google I/O上提及了增量升级,或者叫差分升级的方法,并在新版本的Google Play中得到支持。

简单的来说,增量更新是指在进行更新操作时,只更新需要改变的地方,不需要更新或者已经更新过的地方则不会重复更新,增量更新与完全更新相对。

1.2.增量更新原理

增量升级的原理其实不难,我们首先使用旧版本的apk与新版本的apk做差分,就能得到更新部分的补丁,也叫差分包。这个差分包虽然不是新旧版本的简单相减,但显而易见的是,用户不需要全部下载新版本apk了,我们只要下载更小的那个补丁包(差分包)。

在用户下载完差分包后,需要在手机端将它们组合起来。一般手机的应用安装在data/app下,我们可以复制出就版本apk至SD卡中,与下载好的差分包进行组合。最后得到一个新版本的apk后与服务器上的新版本进行校验,正确后就可以安装了。

2.环境搭建

2.1.NDK下载安装

NDK(native develop kits),是一个交叉编译的工具链。交叉编译是指:在一个平台下(CPU,操作系统)可以编译出在另外一个平台可以运行的代码,例如我们正要做的:windows AMD intel x86架构->手机android arm处理器。

下载地址:http://www.android-doc.com/tools/sdk/ndk/index.html

2.2.Cygwin安装

Cygwin是一个可以在windows下模拟出linux环境的一个工具,NDK必须在linux环境下进行编译等工作。

下载地址:http://www.cygwin.com

安装过程略。需要注意的是在Selectpackages安装界面中把Default改为Install,直接点击Default即可。

完成安装后,我们启动Cygwin,输入make  -v命令,出现如下信息说明安装成功了。

输入make  -v命令

我们cd到NDK的目录,执行./ndk-build命令,出现如下信息则说明大功告成。

执行./ndk-build命令

2.3.在Eclipse中或MyEclipse中安装CDT插件(可选)

将下载好的安装包解压,把features、plugins目录下的文件对应的复制到Eclipse(MyEclipse)中即可,重启软件。

3.实现过程

3.1.差分patch文件的生成

首先要生成旧版本和新版本的差分比patch文件,我们可以借助bsdiff开源库的windows版本。我们先下载bsdiff压缩包,解压后有以下两种工具。

解压bsdiff

Bsdiff.exe就是一个二进制差分工具,bspatch.exe就是相应的补丁合成工具了。我们的增量升级的差分包,是要在服务端完成的,也就是pc端去完成。我们打开命令行,转到bsdiff所在目录下,将新旧版本的apk也放到该目录下,执行命令:

bsdiff.exeoldName.apknewName.apkpatch.patch

Patch文件的名字可自己定义。如测试程序中的两个版本的apk。

测试

3.2.patch文件放至服务器

将生成的差分包xx.patch放置到升级服务器上,供用户下载升级。如果多版本,则必须对不同版本都进行差分。如果版本跨度太大,可以选择整包升级。

测试中将上一步生成的Update.patch包放在发布服务器Tomcat上。

3.3.Android合成新apk

3.3.1.编写本地方法

我们建一个Android工程,命名为UpdateDemo,用来实现应用增量更新功能。在工程中建一个包,编写本地方法。

编写方法

3.3.2.So文件的调用

我们首先用NDK编译出一个*.so文件。这个文件网上有编译好的,可以直接下载使用。附录中详述了如何去编译.so文件。

将下载好的.so文件放置于3.3.1新建的工程目录libs\armeabi文件夹下。

.so文件

我们现在就可以调用patch方法来合成新apk了。在主程序MainAcitivity类中加入以下代码,该代码就是调用我们所需的so库文件。

调用so库文件

这里得注意,我们的so文件前lib是系统生成加上去的,所以在调用中我们只需将名字去掉lib的名字作为参数。

3.3.3.配置XML

无论在下载还是合成删除中,我们都必须获取手机SD卡的读写权限,我们在UpdateDemo工程中AndroidManifest.xml加入以下代码。

AndroidManifest.xml

3.3.4.下载patch差分包

我们在UpdateDemo工程中加上添加一个更新按钮,实现点击按钮能够弹出下载选框,点击下载就可以下载服务器上的patch包了。我们设定下载的目录就是SD卡的跟目录。运行该程序,界面如图。

apk界面

我们点击更新按钮,如下。

更新

3.3.5.复制旧安装包

在合成过程中,我们需要旧安装包。在Android中非系统程序默认安装在data/app文件夹下,在非root情况下,我们可以对其本身安装包进行读操作,这样我们就可以将它复制到SD根目录下(和之前下载的patch文件同目录)。

在下载完成后,下载函数返回DOWN_OVER,线程接到这个信号后,调用PatchThread()函数。

主线程

我们在PatchThread()中调用复制旧安装包backupApplication(String packageName, String dest)方法。该方法第一个参数为安装包的ID号,如本例中的com.tutor.update,dest为复制目标路径。该方法中,主要函数如下。

backupApplication方法

该函数能够找到data/app下相应的安装包。

测试中我们下载完patch文件后,立刻复制旧安装包。

版本更新

我们用360助手查看SD中文件。

SD中文件

3.3.6.合成新apk

接下来就可以调用本地方法合成新apk了。

同样在PatchThread()函数中,当复制成功后,我们就可以调用如下方法了。

合并apk

参数都是旧、新和patch文件的路径。我们可以用360助手查看,新的apk已经合成,我们可以在程序中设定它的名字。这样,我们的新apk合成成功。

新apk合成成功

3.3.7.MD5校验

合成新apk后,我们无法预知它的正确性,在下载或在合成过程中,文件都有可能出错,所以紧接着我们需要对它进行MD5校验。

用MD5校验工具对服务器上的新apk进行校验,得到校验码。然后Android端合成新apk后对新apk也进行校验。我们在UpdateDemo工程中再建一个包,编写MD5类。

编写MD5

我们在MainAcitivity类中的PatchThread()函数中构造MD5对象,调用check方法即可。

用返回的校验值和服务器上的校验值对比,相同则进行安装,不同则提示校验失败。

校验失败

3.3.8.安装新apk

校验正确后自动安装即可。紧接着校验函数,我们加入判断,如果校验正确,则调用以下方法;如果错误,我们就跳出提示信息。

安装新apk

安装完成后打开软件,已经是V2版本了,我们增量更新成功。

量更新成功

3.3.9.删除残余文件

最后我们只要把用户下载的patch文件和旧apk删除即可,用户最终可以得到新apk,新apk用户可以自行处理。

删除时我们只要在安装后或在校验错误后调用delete()函数即可。

delete()函数

用助手查看SD目录,只有新apk了。

只有新apk

如果校验不通过,所有相关文件都会被删除。这样,我们就完成了我们的更新操作。

4.各种生成差分包大小列表

增量更新虽然不用将新apk的内容全部下载,但如果版本相差过大,或者apk本身非常小,还是建议下载整包。以下做了个小测试。

生成差分包大小列表

我们能够观察到,当apk不足1M时,差分包大小同样也有几百K,所以没必要去差分。当版本相差过大,增加内容非常多时,我们也建议直接整包更新。差分时包越大耗时越长。

5.附录

测试中我们用到网上已有的so库,直接调用即可。我们也可以自己在客户端生成so文件。

我们先下载bzip2-1.0.6.tar.gz。新建一个Android工程,将可能用到的下列文件复制到新建的Android工程的jni目录下(没有的新建一个目录)。

下载地址:http://www.bzip.org/downloads.html。

bzip2-1.0.6.tar.gz

5.1.Android.mk配置

在该jni目录下新建文件,命名Android.mk,配置如下。

Android.mk

5.2.方法实现

5.2.1.头文件生成

打开cmd命令行,转到工程目录的bin文件夹下,输入以下命令。

生成头文件

系统会自动生成一个.h文件,我们把它拷贝到jni目录下。

.h文件

5.2.2.编译成so库

我们在jni目录下新建com_example_jni_MainActivity.c,完成c代码。

com_example_jni_MainActivity.c

打开Cygwin,转到工程目录,使用ndk命令编译成so库即可。

编译成so库

我们可以看到libBSdiff.so已经编译成功,在lib/armeabi目录下。

libBSdiff.so

这样,我们就可以使用该so文件去合成新apk了。

推荐阅读更多精彩内容

  • 在前几年,整体移动网络环境相比现在差很多,加之流量费用又相对较高,因此每当我们发布新版本的时候,一些用户升级并不是...
    涅槃1992阅读 2,343评论 1 37
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 141,800评论 18 609
  • @[增量更新,差分包,bsdiff/patch] 背景 随着Android app的不断迭代升级,功能越来越多,a...
    SunYo阅读 5,948评论 2 6
  • 经艳子姐介绍加入组织后,真真切切感受到笔友们对文字的喜爱,对写作的热情,不同年龄,不同职业,天南海北的人聚在一起,...
    半山桃源阅读 44评论 5 4
  • 为什么在一起 两个人选择在一起,可以是因为热恋的爱情,也可以不是因为难以自拔的爱。 试想,你...
    青糯君阅读 188评论 0 3