Android增量更新

一、增量更新

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,同时补充自己一些实际操作。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值