概述:
- 所谓的增量更新就是一个给用户省流量更新的方案,与手机OTA升级类似,相对于热更及后台自动更不同,增量更新的方案便是让用户通过下载差异包,与原有的APK进行合并形成新的APK安装文件。举个例子:用户手机安装的APP是1.0版本,大小为20M 。而2.0的版本则为30M ,那么当用户点击更新APP的时候,仅需要从后台下载10M的差异包,然后与原有1.0版本的APK进行合并生成2.0的APK文件。
步骤解析:
- 真实环境下:
1、从服务器下载差异包。
2、提取当前应用的apk文件(下方会给出方法)。
3、将差异包与APK合并。 - Demo环境:
1、本地打出差异包文件。
2、提取当前应用的apk文件(下方会给出方法)。
3、将差异包与APK合并。
———————————Demo环境 :————————————-
首先我们需要关注的是如何打出差异包:
首先是差异包patch的生成。与安卓手机OTA升级类似,在update.zip中的patch文件夹中有需要与系统文件同名但是以xxx.p 为后缀的文件,他们就是生成的差分patch文件。我们可以借鉴OTA系统升级的差分生成工具来生成我们单个应用apk的差分patch文件。
其实Android中已经为提供我们用来制作差分增量升级包的工具,”bsdiff”,(Android的代码目录下 \external\bsdiff )。这里给出已编译好的。
bsdiff是二进制差分工具,其对应的bspatch是相应的补丁合成工具。
使用差分命令:
bsdiff oldfile newfile patchfile 如:./bsdiff old.apk new.apk bsdiff.patch
使用补丁合成命令:
bspatch oldfile newfile patchfile 如:./bspatch old.apk new2.apk bsdiff.patch
此处生成的 bsdiff.patch 便是差异包。而new2.apk 就是新合成的apk文件。
我们可以使用md5命令来校验两个apk文件是否一致。
md5 new.apk 及md5 new2.apk
安装注意:
以上就是如何生成差异包。
Android项目具体操作:
- 首先提取APK
public class ApkExtract {
public static String extract(Context context) {
context = context.getApplicationContext();
ApplicationInfo applicationInfo = context.getApplicationInfo();
String apkPath = applicationInfo.sourceDir;
return apkPath;
}
}
制作bspatch so
1、 声明一个类,写个native方法
public class BsPatch {
static {
System.loadLibrary("bsdiff");
}
public static native int bspatch(String oldApk, String newApk, String patch);
}
2、配置ndk的环境,在module的build.gradle下面添加:
defaultConfig {
ndk {
moduleName = 'bsdiff'
}
}
3、app/main目录下新建一个文件夹jni,把之前下载的bsdiff中的bspatch.c拷贝进去。按照jni的规则,在里面新建一个方法:
JNIEXPORT jint JNICALL Java_com_mrliu_utils_BsPatch_bspatch
(JNIEnv *env, jclass cls,
jstring old, jstring new, jstring patch){
int argc = 4;
char * argv[argc];
argv[0] = "bspatch";
argv[1] = (char*) ((*env)->GetStringUTFChars(env, old, 0));
argv[2] = (char*) ((*env)->GetStringUTFChars(env, new, 0));
argv[3] = (char*) ((*env)->GetStringUTFChars(env, patch, 0));
int ret = patchMethod(argc, argv);
(*env)->ReleaseStringUTFChars(env, old, argv[1]);
(*env)->ReleaseStringUTFChars(env, new, argv[2]);
(*env)->ReleaseStringUTFChars(env, patch, argv[3]);
return ret;
}
//将下放的main方法改为patchMethod方法。
4、此时尝试运行,会提示依赖bzlib,从文件顶部的include中也能看出来
5、添加依赖:
http://www.bzip.org/downloads.html
http://www.bzip.org/1.0.6/bzip2-1.0.6.tar.gz
6、将下载好的文件进行解压:
将其中的.h和.c文件提取出来,然后可以选择连文件夹copy到我们module的app/main/jni下,结果如下:
7、修改bsdiff中的include
#include "bzip2/bzlib.h"
8、此时运行,出现以下BUG,是main方法重复,删掉错误类的main方法即可:
Error:(70) multiple definition of `main'
以上便完成了jni的编写。
Android代码编写:
将刚开始制作的old.apk安装。将bsdiff.patch放到sd卡的根目录。
开启读写SDCard权限,代码中校验需要的文件是否存在
在Activity中调用:
private void doBspatch() {
final File destApk = new File(Environment.getExternalStorageDirectory(), "new2.apk");
final File patch = new File(Environment.getExternalStorageDirectory(), "bsdiff.patch");
//一定要检查文件都存在
BsPatch.bspatch(ApkExtract.extract(this),
destApk.getAbsolutePath(),
patch.getAbsolutePath());
if (destApk.exists())
ApkExtract.install(this, destApk.getAbsolutePath());
}
通过Intent安装:
public static void install(Context context, String apkPath) {
Intent i = new Intent(Intent.ACTION_VIEW);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
i.setDataAndType(Uri.fromFile(new File(apkPath)),
"application/vnd.android.package-archive");
context.startActivity(i);
以上便是整个增量更新的过程。
单纯的使用功能:下载so文件。在调用native之前loadLibrary。