Android增量更新

来源:互联网 发布:phpexcel导出大量数据 编辑:程序博客网 时间:2024/06/05 10:20

一、增量更新

1.概述

增量更新,是指通过分析出新apk与旧apk之间的增量文件,然后提取老版的app安装文件,并与增量文件合成新的安装包,之后重新安装即可。

增量更新可以让我们不必加载整个安装包,即可实现app的更新,节省了不少流量,提供更佳的用户体验。有些应用市场,就是通过此方式实现流量的节省。

2.实现步骤

1)利用新apk与旧apk生成增量文件;

2)提取手机上的旧apk;

3)合成旧apk与增量文件,安装合成的新apk。

接下来一步步来实现上述的步骤。

二、实现

1.生成增量文件

这个我们使用工具bsdiff.exe即可生成差异文件,这个,我已经忘了之前从哪里找到的windows上的exe文件,直接提供下载地址:windows下bsdiff与bspatch下载地址

当然也有linux版本的,需要自己下载,make,下载地址:http://www.daemonology.net/bsdiff/bsdiff-4.3.tar.gz。

使用方法也很简单:

在所在目录中,cmd命令生成增量文件:bsdiff old.apk new.apk new.patch

2.提取手机上的旧apk

上面的都是在pc上完成,下面的提取与合成都放在app上完成。

提取旧apk,直接提供一个工具方法:

/** * 提取本应用的apk路径 */public static String extract(Context context) {    context = context.getApplicationContext();    ApplicationInfo applicationInfo = context.getApplicationInfo();    return applicationInfo.sourceDir;}

3.合成与安装

合成需要使用到Native方法,因此要打包一个so库文件,也方便以后使用,这里也涉及到ndk与jni的使用。下面我一步步实现。

1)下载与配置NDK

首先,要下载NDK,一般在AS中打开SDKManager在SDKTools中下载。但是这里不要这么做,在实践中,发现sdk中更新的sdk如果过高,在打出的so库中使用的一些方法会找不到,因为有些手机使用的库较早。我在刚刚接触这个功能时,sdk是r14,但是打包出的so库在荣耀7和魅族上都会抛出找不到指定方法的异常。抠脚一天,才在网上找到可能是NDK版本过高的原因,因此这里我实验通过的版本是r10e,下载地址:http://dl.google.com/android/ndk/android-ndk-r10e-windows-x86_64.exe。下载之后,安装到sdk目录中。

首先在gradle.properties中配置


然后是local.properties


好了,配置就差不多了。可能大家在用的时候还是会遇到一些配置问题,请自行百度NDK配置,我就配了这俩地方。

2)实现合成nativie方法与打包

a)合成的native方法如下:

package com.example.davidchen.patchdemo.util;/** * 增量更新,合成 * Created by DavidChen on 2017/1/4. */public class BsPatch {    static {        System.loadLibrary("bsdiff");    }    public static native int bspatch(String oldApk, String newApk, String patch);}
b)先make project,之后在指定的目录...\app\build\intermediates\classes\debug\com\example\davidchen\patchdemo\util下找到编译出来的class文件,再用javah -jni com.example.davidchen.patchdemo.util.BsPatch命令生成对应的头文件。文件位置在...\app\build\intermediates\classes\debug目录下。


接下来就是c实现部分

c)首先建立jni目录:

d)将之前的头文件剪切到该目录中,再建立c实现文件(这里是Patch.c)。当然还有核心的实现方法。这里还有个依赖的bzip,要从网上下载,网址:http://www.bzip.org/downloads.html。当然这个库里还有些要去掉的多余的文件与方法。这里提供一个精简过的包以及上面的c实现:native方法c实现。但是不要直接用我上面生成的文件,因为native方法的命名是由要求的,直接使用会出问题,但是代码可以拷过去,注意改一下方法名和include即可。


e)配置ndk生成对应不同cpu的abi架构的so

说一下,一般我们为了缩减apk大小,会选择最少的so,怎样去适配不同手机的cpu架构呢,一般的机子,大部分都是支持armeabi或armeabi-v7a,而且x86的机子也会支持armeabi的类库。因此我们一般只需要armeabi的so。


之后可以在...\app\build\intermediates\ndk\debug\lib目录中找到生成的so,拷贝到项目...\app\libs\目录下(当然也可以不拷贝,因为有c实现的时候可以打包后直接就加载到c的方法,但是如果不要c实现就要这些so了,下面会介绍)。

3)实现合成并调用方法安装

这里写了个在activity中运行的合成例子:

...protected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.activity_test);    String path = Environment.getExternalStorageDirectory().getPath();    doBsPatch(this, path + "/new.apk", path + "/new.patch");}/** * 合成 * * @param latestPath 要生成的新apk位置 * @param patchPatch 增量文件位置 */public static void doBsPatch(final Context context, String latestPath, String patchPatch) {    final File latestApk = new File(latestPath);    final File patch = new File(patchPatch);    //一定要检查文件都存在    if (!patch.exists()) {        Toast.makeText(context, "合成失败", Toast.LENGTH_SHORT).show();    }    new Thread(new Runnable() {        @Override        public void run() {            // 使用native方法,是因为c的算法比java的算法要快100倍            BsPatch.bspatch(ApkExtract.extract(context),                    latestApk.getAbsolutePath(),                    patch.getAbsolutePath());            if (latestApk.exists()) {                ApkExtract.install(context, latestApk.getAbsolutePath());            }        }    }).start();}...
上面的install方法实现:

/** * 安装apk * * @param apkPath apk所在目录 */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);    android.os.Process.killProcess(android.os.Process.myPid());}

注意声明读写权限。OK,测试图就不上了。

注意:so文件可以直接用来放到libs中对应的abi架构目录中使用,这样以后就不用再麻烦的用那么多的c文件和生成步骤了,只要在build.gradle中的android内添加:

sourceSets {    main {        jniLibs.srcDirs = ['libs']    }}
指定jni加载的so库位置,便可以直接通过java的native方法进行使用。

三、应用

增量更新的应用还有些要注意的。

一般步骤是:

pc:生成新版本的apk-->与旧版本的apk生成增量文件。

app:检测到更新-->下载差异文件-->提取旧apk,合成-->校验文件MD5-->安装。

这里校验是有必要的,防止生成的apk无法安装,给出一个app上获取文件MD5的方法:

/** * 获取单个文件的MD5值 * * @param file 文件 * @return 文件MD5值 */ public static String getFileMD5(File file) {    if (!file.isFile()) {        return null;    }    MessageDigest digest;    FileInputStream in;    byte buffer[] = new byte[1024];    int len;    try {        digest = MessageDigest.getInstance("MD5");        in = new FileInputStream(file);        while ((len = in.read(buffer, 0, 1024)) != -1) {            digest.update(buffer, 0, len);        }        in.close();    } catch (Exception e) {        e.printStackTrace();        return null;    }    BigInteger bigInt = new BigInteger(1, digest.digest());    return bigInt.toString(16);}



声明:参考了Hongyang大神的博客:http://blog.csdn.net/lmj623565791/article/details/52761658,同时补充自己一些实际操作。


原创粉丝点击