01.增量更新之window下的apk的差分

1.概述

  • 相信大家都见过在应用市场省流量更新软件,一个几百M的软件可能只需要下载一个20M的增量包就能完成更新。那么它是如何做的呢?
  • 技术核心:就是让用户下载当前版本和新版本直接的差分包,然后将当前版本的apk和差分包合并,重而生成新的apk,达到节省流量。
  • 大致流程就是上面说的,但是其中的核心技术就在于,1.对旧版本apk和新版本apk的差分,生成差分包.2.对旧版本和差分包的合并。

对于技术的核心,我们通过bsdiff这个c/c++的开源库做,做这个技术前,我们最好先下几个必要的文件。
下载bsdiff http://www.daemonology.net/bsdiff/ 这上面下载的是linux版本
bsdiff依赖于bzip2,所以还要下载bzip2 http://www.bzip.org/downloads.html

这两个文件,我们后面的时候使用,这次的目的是:在window下通过vs和eclipse的配合使用来实现apk的旧版本和新版本的差分。

这次使用的文件是bsdiff4.3-win32-src.zip版本,具体的下载,自行百度。

2.编译bsdiff-win版,解决报错问题

下载的bsdiff4.3-win32-src.zip文件是bsdiff和bzip一块包装好的,不需要再下载其他东西。
1. 新建vs项目,将bsdiff4.3-win32-src下面的所有 .c .h文件都赋值到项目中,这是为了编译生成相应的.dll文件,这步该怎样做参考jni开发流程 这篇文章。
2. 编译生成.dll文件,肯定会报错,下面将错误一个个解决。

1> 用了不安全的函数错误

错误  1   error C4996: 'strcat': This function or variable may be unsafe. Consider using strcat_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.  c:\users\administrator\documents\visual studio 2013\projects\ndk\ndk_03\ndk_03\bzlib.c  1416    1   ndk_03

解决:
可以在c/c++文件的头部添加

#define _CRT_SECURE_NO_WARNINGS

如果c/c++文件较多可以使用如下做法
这里写图片描述

2> 用了过时的函数错误

错误  1   error C4996: 'setmode': The POSIX name for this item is deprecated. Instead, use the ISO C++ conformant name: _setmode. See online help for details.    c:\users\administrator\documents\visual studio 2013\projects\ndk\ndk_03\ndk_03\bzlib.c  1422    1   ndk_03

解决
可以在c/c++文件的头部添加

#define _CRT_NONSTDC_NO_DEPRECATE

如果c/c++文件较多可以如下
这里写图片描述

3>SDL检查

错误  2   error C4703: 使用了可能未初始化的本地指针变量“V”    c:\users\administrator\documents\visual studio 2013\projects\ndk\ndk_03\ndk_03\bsdiff.cpp   273 1   ndk_03

解决
这里写图片描述

3.阅读源码

最后仔细阅读bsdiff.cpp的源码,如果看不懂也要看个大概,可以看到bsdiff.cpp的核心方法是int main这个方法,我们就是调用这个方法来做apk的差分。调用main方法肯定是不行的,所以需要将bsdiff.cpp文件中的int main方法名修改为可读性强的名称,我修改后的名称如下。

int diff_patch_main(int argc,char *argv[]){
    ...
    if(argc!=4) errx(1,"usage: %s oldfile newfile patchfile\n",argv[0]);
    ...
}

可以看到其中的解释,argc是一个常量4,argc[]指针数组的第一个参数,可以是一个随意的字符串,第二个是老版本的文件,第三个是新版本的文件,最后一个是差分后的差分文件。有了这个信息后,就可以开始下面的步骤了。

4.根据bsdiff.cpp中的代码,编写java层代码,生成头文件

上面说到了,在bsdiff.cpp的mian 中可以传递老版本的apk,新版本的apk,差分后的差分包的文件。
可以写成native如下

public class PatchDiffUtil {
    /**
     * 拆分
     * @param oldApkPath 
     * @param newApkPath 
     * @param diffPath
     */
    public native static void diff(String oldApkPath,String newApkPath,String diffPath);

    static {
        System.loadLibrary("ndk_patch_update");
    }
}

使用javah命令生成.h文件,然后将生成的.h文件和相应的jni.h和jni_md.h一起复制到vs项目中,这步同样参考jni开发流程

5.编写JNI函数,供Java层调用(注意统一编码)

在bsdiff.c++中引用com_gxl_util_PatchDiffUtil.h,实现其中的diff方法.

JNIEXPORT void JNICALL Java_com_gxl_util_PatchDiffUtil_diff
(JNIEnv * env, jclass cls, jstring old_apk_path_str, jstring new_apk_path_str, jstring patch_path_str){
    //将jstring转成char*
    char* old_apk_path=(char*)env->GetStringUTFChars(old_apk_path_str, NULL);
    char* new_apk_path = (char*)env->GetStringUTFChars(new_apk_path_str, NULL);
    char* patch_path = (char*)env->GetStringUTFChars(patch_path_str, NULL);

    //调用bsdiff来拆分old apk和new apk
    int argc = 4;
    char *argv[4];
    //四个参数,1.随便命名,2.老apk路径,3.新apk路径,4.拆分后的路径
    argv[0] = "bsdiff";
    argv[1] = old_apk_path;
    argv[2] = new_apk_path;
    argv[3] = patch_path;

    diff_patch_main(argc, argv);
    //释放
    env->ReleaseStringUTFChars(old_apk_path_str, old_apk_path);
    env->ReleaseStringUTFChars(old_apk_path_str, new_apk_path);
    env->ReleaseStringUTFChars(old_apk_path_str, patch_path);
}

可以看到实现的c语言的逻辑很容易。

6.生成.dll动态库,PatchDiffUtil加载动态库

7.调用java层native方法完成拆分

public static void main(String[] args) {
        PatchDiffUtil.diff(Contant.old_apk_path, Contant.new_apk_path, Contant.patch_path);
        System.out.println("拆分完毕!");
    }


public class Contant {

    public static final String old_apk_path="D:/EclipseWorkSpace/apk/ndk_03_update_old.apk";

    public static final String new_apk_path="D:/EclipseWorkSpace/apk/ndk_03_update_new.apk";

    public static final String patch_path="D:/EclipseWorkSpace/apk/apk.patch";
}

本人做过了,这样的步骤,差分后是完全没有问题的。这些文章的前面,后面所有的东西本人都做过一遍,基本上都没有问题,如果有会单独说出的。所有如果过程中有什么错误,最好再看一下。

猜你喜欢

转载自blog.csdn.net/a_thousand_miles/article/details/81135363
01.
今日推荐