Android集成增量更新功能

为什么需要使用增量更新?

增量更新主要通过新旧包生成差分包,客户端通过下载差分包就能与旧包合成新包。因为差分包一般比较小,所以能大大节省流量和加快下载速度。
在Android中的主要使用场景是APK的升级、或者在线资源的升级等。

安卓如何接入增量更新?

增量更新主要通过开源库BsDiff,来实现拆分和合并的功能。首先需要下载BsDiff的源码。由于BsDiff依赖于Bzip2,所以需要把Bzip2的源码也下载下来。

bsdiff网站:http://www.daemonology.net/bsdiff/

下载解压后把bspatch.c 文件拷贝到项目中,如果你需要差分功能,也可以将bsdiff.c同时拷贝到项目中。

bzip2官网:https://www.sourceware.org/bzip2/downloads.html

下载解压后发现很多无用的文件,我们看下Makefile文件中有这么的一段,这才是编译的核心源码:

OBJS= blocksort.o  \
      huffman.o    \
      crctable.o   \
      randtable.o  \
      compress.o   \
      decompress.o \
      bzlib.o

我们将这七个文件的.h和.c文件拷贝到项目中,发现报错,还少了一个bzlib_private.h文件,我们拷贝进去,最终是这样子的:

到了这一步可能bspatch.c文件的#include 这行会保错,这时候将#include 修改为#include "bzip/bzlib.h"即可。

生成差分包或合成新包的命令

通过bsdiff 生成patch包的命令:

bsdiff oldfile newfile patchfile
例如: bsdiff xx_v1.0.apk xx_v2.0.apk xx.patch

bspatch生成新包命令:

bspatch oldfile newfile patchfile
例如: bsdiff xx_v1.0.apk xx_v2.0.apk xx.patch

编写ndk代码

我们新建一个java类,并在类中声明一个native方法,按Alt加Enter键生成jni代码


    /**
     *
     * @param oldPath  旧文件的路径
     * @param bsPatchPath 差分包的路径
     * @param outPath 差分合成后的输出路径
     */
    private native static void bsPatch(String oldPath,String bsPatchPath,String outPath);
    

我们看看jni的具体实现,其实就是调用了bspatch.c的main方法,主要就是调用了bsdiff oldfile newfile patchfile这句命令:


//这个主要是为了导入其中的方法
extern "C" {
extern int bs_patch_main(int argc, char *argv[]);
}

extern "C"
JNIEXPORT void JNICALL
Java_com_flyer_bspatchupdate_jni_BsPatchJni_bsPatch(JNIEnv *env, jclass clazz, jstring old_path,
                                                    jstring bs_patch_path, jstring out_path) {

    //将java字符串转换成char指针
    const char *oldPath = env->GetStringUTFChars(old_path, 0);
    const char *patch = env->GetStringUTFChars(bs_patch_path, 0);
    const char *output = env->GetStringUTFChars(out_path, 0);

    int argc = 4;
    char *argv[argc];
    argv[0] = "bspatch";
    argv[1] = const_cast(oldPath);
    argv[2] = const_cast(output);
    argv[3] = const_cast(patch);

    bs_patch_main(argc,argv);

    // 释放相应的指针gc
    env->ReleaseStringUTFChars(old_path, oldPath);
    env->ReleaseStringUTFChars(bs_patch_path, patch);
    env->ReleaseStringUTFChars(out_path, output);
}

遇到的问题

运行过程中报错:java.lang.UnsatisfiedLinkError大多是因为没有找到对应的so库。
实际开发中可以解压相应的apk,看看lib下是否存在相应的so库,如果不存在可能就是项目配置有问题,导致没有将so打包进去。
在app下的build.gradle下配置下ndk即可


android {
    compileSdkVersion 29
    buildToolsVersion "29.0.2"
    defaultConfig {
        applicationId "........"
        minSdkVersion 21
        targetSdkVersion 29
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

        //这里配置需要打包的ABI架构so,如果不配置可能会导致找不到so
        ndk {
            abiFilters 'armeabi-v7a'
        }

    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

更多Android进阶技术请扫码关注公众号
微信扫码关注

你可能感兴趣的:(Android集成增量更新功能)