Android增量更新

bspatch 官网:http://www.daemonology.net/bsdiff/

bzip2官网:http://www.bzip.org/downloads.html

下载工具包:https://github.com/zhaopingfu/DiffPatchToolsAndLinux/tree/master/tools

EclipseDemo地址:https://github.com/zhaopingfu/DnLsn11_update_server

VSDemo地址:https://github.com/zhaopingfu/DnPfDiff/tree/master/DnPfDiff

客户端Demo地址:https://github.com/zhaopingfu/DnPfLsn12Bspatch

为什么要用增量更新?

普通更新:假如一个旧包是10M,当发现有新版本之后(20M),就将20M下载下来,然后安装

增量更新:假如一个旧包是10M,当发现有新版本之后(20M),之后先生成一个差分包(以二进制的方式比较新包和旧包的差异,相同的地方记录索引,不同的地方记录索引并将内容压缩并记录) ,之后下载下来,然后和手机上已经安装的app进行合并,最后安装

比较之下发现增量更新会比普通更新更加省流量,那么有什么用呢?

如果不用360等其他app商店下载的话,一般都自己搭服务器,就按照阿里云服务器来算的话,1M流量差不多按照5毛钱来算,下载一个包节省10M,1000w的用户的话就是1000w * 10 * 0.5 ,这是一笔很大的生意啊

这里有个问题:假如我们安装完app之后就把安装包删除了,那么下载差分包之后还能合并吗?

答案当然是可以的,因为在我们第一次下载了,安装的时候,系统会帮助我们拷贝一份放在外置卡的data/app/路径下,每一个app按照自己的包名划分,一般没有root的话,这个路径下的文件是没有权限删除的,所以90%的情况下都是可以的,另外的10%是用户将手机root,获得了最高权限,然后将备份的安装包都删除了,这时候就要向服务器反馈了,将全量的包下载下来

生成差分包

步骤:
1、先生成一个windows下的差分工具

VS2013DEMO地址:https://github.com/zhaopingfu/DnPfDiff/tree/master/DnPfDiff

首先下载一个bsdiff4.3-win32-src.zip解压:https://github.com/zhaopingfu/DiffPatchToolsAndLinux/tree/master/tools

创建一个VS项目(这里用的是VS2013的),将平台设置为x64的

在工程路径下创建两个文件夹:src  include,将头文件放入include,.c和.cpp放入src里

这里在源文件里找不到头文件,需要一些设置

vs 找头文件 设置:右键工程 --->  属性 ---> c++ -----> 附含包目录(头文件的目录)
vs 解决 _CRT_SECURE_NO_WARNINGS:右键工程 --->  属性 ---> c++ -----> 命令行 添加 -D _CRT_SECURE_NO_WARNINGS
vs 关闭sdl 安全检查:右键工程 --->  属性 ---> c++------>常规 ---->SDL检查 否
vs 切换平台之后 需要重新配置上述依赖

上面都好了之后运行项目,生成一个.exe文件

在cmd中执行这个.exe

    PfDiff.exe appOld.apk appNew.apk apk.patch
    PFDiff.exe:刚才生成的.exe可执行文件
    appOld.apk:旧的安装包
    appNew.apk:新的安装包
    apk.patch:生成的差分包

执行完之后会看到在当前路径下生成了一个apk.patch差分文件 

2、Eclipse中生成差分文件

在Eclipse中创建一个web工程

public class DnPfDiff {

    public static native void diff(String oldPath, String newPath, String patchPath);

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

之后进入项目的src路径下,生成头文件

javah com.pf.updata.DnPfDiff

这里写图片描述

之后,将头文件放入VS项目中

这里会发现在头文件中找不到jni.h,这里要找jni.h,注意是window下的
JDK下面的是window下的,SDK下的是linux下的

这里要在JDK里复制jni.h和jni_md.h

在bsdiff.cpp中引入刚才生成的头文件,然后把main方法改个名字,改为bsdiff_main

/*
* Class:     com_pf_update_DnPfDiff
* Method:    diff
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_com_pf_update_DnPfDiff_diff
(JNIEnv *env, jclass jcls, jstring old_path_jstr, jstring new_path_jstr, jstring patch_path_jstr)
{
    int argc = 4;
    char *argv[4];

    char *old_path_cstr = (char*)env->GetStringUTFChars(old_path_jstr, NULL);
    char *new_path_cstr = (char*)env->GetStringUTFChars(new_path_jstr, NULL);
    char *patch_path_cstr = (char*)env->GetStringUTFChars(patch_path_jstr, NULL);

    argv[0] = "bsdiff_Pf";
    argv[1] = old_path_cstr;
    argv[2] = new_path_cstr;
    argv[3] = patch_path_cstr;

    bsdiff_main(argc, argv);

    env->ReleaseStringUTFChars(old_path_jstr, old_path_cstr);
    env->ReleaseStringUTFChars(new_path_jstr, new_path_cstr);
    env->ReleaseStringUTFChars(patch_path_jstr, patch_path_cstr);
}

之后生成一个.dll动态库,注意不是exe文件

然后放入eclipse工程的根目录中

eclipse里写个main方法即可执行,生成差分包


public class ContantsWin {

    // 路径不能包含中文
    public static final String BASE_PATH = "E:\\software\\Eclipse\\eclipse-jee-oxygen-R-win32-x86_64\\projects\\DnLsn11_update_server\\WebContent\\download\\";

    public static final String OLD_APK_PATH = BASE_PATH + "apkOld.apk";

    public static final String NEW_APK_PATH = BASE_PATH + "apkNew.apk";

    public static final String PATCH_PATH = BASE_PATH + "apk.patch";

    public static final String URL_PATCH_PATH = "/download/apk.patch";
}


public class MainTest {

    public static void main(String[] args) {
        DnPfDiff.diff(ContantsWin.OLD_APK_PATH, ContantsWin.NEW_APK_PATH, ContantsWin.PATCH_PATH);
    }

}

随便写个servlet,就可以将差分包进行下载了

Eclipse下Demo地址:https://github.com/zhaopingfu/DnLsn11_update_server
VS2013DEMO地址:https://github.com/zhaopingfu/DnPfDiff/tree/master/DnPfDiff

3、Linux下生成差分文件

首先下载一个bsdiff4.3-win32-src.zip解压(最上面有链接):https://github.com/zhaopingfu/DiffPatchToolsAndLinux/tree/master/tools

bsdiff.c中的<bzlib.h>修改为"bzlib.h"
除了bsdiff.c中的main方法外,其他的main方法都改成其他的名字

修改权限 
chmod 777 ./*

生成一个可执行文件
gcc -fPIC blocksort.c decompress.c bsdiff.c  randtable.c  bzip2.c huffman.c compress.c bzlib.c crctable.c -o PfBsDiff

执行可执行文件
./PfBsDiff apkOld.apk apkNew.apk apk.patch

生成一个.so动态库(在服务器的后台可以直接使用,安卓客户端不能直接用,需要用NDK进行交叉编译)
gcc -fPIC -shared blocksort.c decompress.c bsdiff.c  randtable.c  bzip2.c huffman.c compress.c bzlib.c crctable.c -o PfBsDiff.so

合并差分包(客户端完成)

客户端Demo地址:https://github.com/zhaopingfu/DnPfLsn12Bspatch

创建一个Android项目(NDK项目)

首先将bzip下的头文件和源文件和bsdiff中的bspatch.c复制到cpp下(源文件里面的main方法都改名)

配置CMakeLists.txt

写native方法

public class BsPatch {

    public native static int patch(String oldfile, String newfile, String patchfile);

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

生成头文件,也是上面的javah命令,cmd进入java目录,执行javah com.pf.bspatch.BsPatch

bspatch中引入头文件,并实现头文件中的方法

/*
 * Class:     com_pf_bspatch_BsPatch
 * Method:    patch
 * Signature: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I
 */
JNIEXPORT jint JNICALL Java_com_pf_bspatch_BsPatch_patch
        (JNIEnv *env, jclass jcls, jstring old_path_jstr, jstring new_path_jstr,
         jstring patch_path_jstr) {
    int ret = -1;
    LOGI("jni patch begin");
    char *old_path_cstr = (*env)->GetStringUTFChars(env, old_path_jstr, JNI_FALSE);
    char *new_path_cstr = (*env)->GetStringUTFChars(env, new_path_jstr, JNI_FALSE);
    char *patch_path_cstr = (*env)->GetStringUTFChars(env, patch_path_jstr, JNI_FALSE);

    int argc = 4;
    char *argv[4];

    argv[0] = "PfBsPatch";
    argv[1] = old_path_cstr;
    argv[2] = new_path_cstr;
    argv[3] = patch_path_cstr;

    //如果成功ret等于0
    ret = bspatch_main(argc, argv);

    LOGI("jni patch end");

    (*env)->ReleaseStringUTFChars(env, old_path_jstr, old_path_cstr);
    (*env)->ReleaseStringUTFChars(env, new_path_jstr, new_path_cstr);
    (*env)->ReleaseStringUTFChars(env, patch_path_jstr, patch_path_cstr);
    return ret;
}

cmd里查看下打包生成的包的MD5值和合并生成的包的MD5的值是一样的

查看md5 值

certutil -hashfile apkNew.apk MD5
3a68cc74cf9b0a3841419a54922233d1

certutil -hashfile apk_new_merger.apk MD5
3a68cc74cf9b0a3841419a54922233d1

总结下命令

进入DnPfDiff所在路径下

DnPfDiff.exe apkOld.apk apkNew.apk apk.patch

    DnPfDiff.exe:要执行的文件
    apkOld.apk:旧的apk
    apkNew.apk:新的apk
    apk.patch:生成的差分包

///////////////////////////////

进入bspatch所在路径下

bspatch.exe apkOld.apk apkNewMerger.apk apk.patch

    bspatch.exe:要执行的文件
    apkOld.apk:旧的apk包
    apkNewMerger.apk:合并后的文件
    apk.patch:差分包

//////////////////////////////////////

linux下生成一个可执行文件
    gcc -fPIC blocksort.c decompress.c bsdiff.c  randtable.c  bzip2.c huffman.c compress.c bzlib.c crctable.c -o PfBsDiff

执行可执行文件
    ./PfBsDiff apkOld.apk apkNew.apk apk.patch

生成一个.so动态库(在服务器的后台可以直接使用,安卓客户端不能直接用,需要用NDK进行交叉编译)
    gcc -fPIC -shared blocksort.c decompress.c bsdiff.c  randtable.c  bzip2.c huffman.c compress.c bzlib.c crctable.c -o PfBsDiff.so

/////////////////////////////////////////

java中native方法生成头文件

进入java文件所在的根目录

假如是/app/src/main/java/com/pf/bspatch/BsPatch.java的话就进入到java目录下就可以了

在cmd里进入java目录下,执行javah命令(配好JDK之后就可以执行)

    javah com.pf.bspatch.BsPatch

这样就会生成一个头文件

///////////////////////////////////

查看md5 值

    certutil -hashfile apkNew.apk MD5

3a68cc74cf9b0a3841419a54922233d1
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值