升级方案,Android增量升级的方法和原理详细介绍

总结:
笔者们利用delta编码算法收缩Android应用晋级程序的轻重。大家因而bsdiff和bspatch工具在android上落到实处delta编码算法。服务器软件和android应用已经布署。当前,我们可以减弱Android晋级流量的四分之二,假如大度的结构,那将会减少网络的压力。

@[增量更新,差分包,bsdiff/patch]

进步机制:
咱俩筹算采取delta编码的patch晋级Android应用。新的升官体制可以描述如下:

背景

乘机Android
app的不唯有迭代晋级,功效进一层多,apk体量也越加大,即便眼前活动互联网遇到较N年前有光辉进步,但流量资费依旧不平价,由此老是揭橥新版时顾客升高并非很积极,自从Android4.1最初,谷歌引进了应用程序的Smart App Update,即增量更新,增量更新提供了三个更好的法子将立异推送到设备,相对于全量更新来说前面一个只供给将转移的有些推送出去,那有利于客户更加快的下载更新、节省设备电量消耗,最重大的是立见成效裁减了动用晋级时开销的网络流量,国内中兴、360行使市场早就使用了该更新机制推出了省流量更新作用。


1、  在服务器上生成一个patch。
2、  下载patch到手提式无线话机中。
3、  通过补丁获取三个已设置使用的新的安装apk。
4、  安装使用的新本子并删掉旧的本子和patch。

合法证实

Smart app updates is a new feature of Google Play that introduces a
better way of delivering app updates to devices. When developers
publish an update, Google Play now delivers only the bits that have
changed to devices, rather than the entire APK. This makes the updates
much lighter-weight in most cases, so they are faster to download,
save the device’s battery, and conserve bandwidth usage on users’
mobile data plan. On average, a smart app update is about 1/3 the
sizeof a full APK update.
http://developer.android.com/about/versions/jelly-bean.html


总括数据:
我们当下正在商量利用怎么样在android中升高。这一个研讨结果将允许大家在新的晋级机制下节约多量的流量。大家创造了三个android应用用来搜聚计算数据(或许会用来今后的钻研)。
运用会采撷以下数据:
1、  应用的名字,版本,大小和各类应用最终升任的光阴。
2、  总计Wifi和3G的链接状态。

实现原理

增量更新规律其实比较轻巧,正是通过差分算法将新旧版本扩充对照将有异样的地点抽出出来生成更新补丁patch,也称为差分包。顾客端在检查测量检验到创新的时候,只须要将差分包下载到本地,然后经过合成算法将差分包与近些日子使用合併,生成最新安装包,在文书校验通过后施行安装就能够。方今主流的差分相比较算法是bsdiff/patch,来自http://www.daemonology.net/bsdiff/
,该算法是开源的,可依照平台的不及在对应平台运用源代码实行编写翻译集成。


谷歌(Google卡塔尔(英语:State of Qatar)增量晋级本事:

编码达成

在谷歌(Google卡塔尔(英语:State of Qatar)二零一一 I/O大会上颁发谷歌 Play
Stroe的增量进级手艺。它始于2月首旬。他们运用跟大家相通的进级机制。相比超多个利用的差异,并将patch铺排在终点上。

筹算工具

  • bsdiff/patch源码(点击下载)
  • 是因为bsdiff/patch信任bzip2库,因而还索要下载bzip2。(点击下载)
  • Android studio配置NDK环境
  1. 开拓Tools->Android->SDK Manager->SDK
    Tools选中LLDB和NDK,点击确认,软件会自行安装NDK。见下图:
![](https://upload-images.jianshu.io/upload_images/6986042-94d57ad188425add)

enter image description here
  1. 布署情状变量,点击File->Project Structure展开设置页面,点击SDK
    Location选项卡设置NDK路线。
![](https://upload-images.jianshu.io/upload_images/6986042-8a2a5bc5acefb84c.png)

image.png

凭借大家的总计,patch文件的平分大小为运用的34%。

生成差分包

  • 编写翻译bsdiff/patch,Mac情状编写翻译方法如下:
  1. 解压下载的bsdiff-4.3.tar.gz
    tar -zxvf bsdiff-4.3.tar.gz
  2. 进去bsdiff-4.3目录,在极限下实践创设
    cd bsdiff-4.3
    make
    Window/linux平台可参照那篇小说
    增量更新:bsdiff工具的装置和行使
  • bsdiff命令:
  1. 生成差分包:
    命令:bsdiff old.file new.file add.patch
    ,即old.file是旧的公文,new.file是新改动变化的文件,add.patch是那五个公文的差距文件(即差分包).
    生成差分包要求非常多的内部存款和储蓄器和岁月,所幸这么些操作只要求在服务器后端履行。
  2. 旧文件和差分包合成新文件:
    指令:bspatch old.file createNew.file add.patch
    个中createNew.file是联合后的新文件

用到的软件:
为了成功在服务器上安顿patch软件和在手提式无线电电话机上配置patch和晋级使用。在劳动器端大家采取bsdiff工具。在android,我们运用bspatch工具。

联合差分包

  • 创建Native方法类

 public class PatchUtils {

    static PatchUtils instance;

    public static PatchUtils getInstance() {
        if (instance == null)
            instance = new PatchUtils();
        return instance;
    }

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

    /**
     * native方法 使用路径为oldApkPath的apk与路径为patchPath的补丁包,合成新的apk,并存储于newApkPath
     * 
     * 返回:0,说明操作成功
     * 
     * @param oldApkPath
     *            示例:/sdcard/old.apk
     * @param newApkPath
     *            示例:/sdcard/new.apk
     * @param patchPath
     *            示例:/sdcard/xx.patch
     * @return
     */
    public native int patch(String oldApkPath, String newApkPath, String patchPath);
}

编写翻译之后在工程build/intermediates/classes对应路线下生成PatchUtils.class文件,张开终端切换成该目录,输入命令行javah com.yyh.lib.bsdiff.PatchDroid(包名.类名),生成头文件com_yyh_lib_bsdiff_PatchUtils.h

  • 实现Native方法
    将上八个步骤生成的头文件拷贝到工程jni目录下,同时解压bzip2包和bspatch源码到该目录下,将bspatch.c重命名字为com_yyh_lib_bsdiff_PatchUtils.c(注意命名方式为包名.类名),并在中间贯彻Java_com_yyh_lib_bsdiff_PatchUtils_patch方法,注意方法名必定要含有Native方法类所在的包名相对路线,包名能够自定义。

JNIEXPORT jint JNICALL Java_com_yyh_lib_bsdiff_PatchUtils_patch
  (JNIEnv *env, jclass cls,
            jstring old, jstring new, jstring patch){
    int argc = 4;
    char * argv[argc];
    argv[0] = "bspatch";
    argv[1] = (char*) ((*env)->GetStringUTFChars(env, old, 0));
    argv[2] = (char*) ((*env)->GetStringUTFChars(env, new, 0));
    argv[3] = (char*) ((*env)->GetStringUTFChars(env, patch, 0));

    printf("old apk = %s \n", argv[1]);
    printf("patch = %s \n", argv[3]);
    printf("new apk = %s \n", argv[2]);

    int ret = applypatch(argc, argv);

    printf("patch result = %d ", ret);

    (*env)->ReleaseStringUTFChars(env, old, argv[1]);
    (*env)->ReleaseStringUTFChars(env, new, argv[2]);
    (*env)->ReleaseStringUTFChars(env, patch, argv[3]);
    return ret;
}

你恐怕感兴趣的稿子:

  • 基于Android
    SQLite的晋升安详严整
  • android达成程序自动进级到安装示例分享(下载android程序安装包卡塔尔国
  • Android完毕创立或进级数据库时实行语句
  • c#采用xamarin编写拨打电话程序
  • Android编制程序完结自动物检疫查评定版本及活动晋级的点子
  • Android将Xamarin For
    VS升级为4.1.0.530版教程

编译SO模块

在jni目录下开创Android.mk文本,写入以下代码,当中LOCAL_MODULE代表SO模块名称,LOCAL_SRC_FILES代表源文件路线,用相对路线就能够,不必写绝对路线,具体语法可参看:http://www.cnblogs.com/wainiwann/p/3837936.html,这里断定要留意加上那句代码APP_PLATFORM:=android-14,当中android-14与您工程的minSDKVersion后生可畏致即可,不然运营在少数低版本设备上会现身java.lang.UnsatisfiedLinkError错误。

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := ApkPatchLibrary
LOCAL_LDFLAGS := -Wl,--build-id
LOCAL_SRC_FILES := \
    /Users/xiayang075/Documents/项目/IncrementallyUpdate/app/src/main/jni/com_yyh_lib_bsdiff_DiffUtils.c \
    /Users/xiayang075/Documents/项目/IncrementallyUpdate/app/src/main/jni/com_yyh_lib_bsdiff_PatchUtils.c \
    /Users/xiayang075/Documents/项目/IncrementallyUpdate/app/src/main/jni/bzip2/blocksort.c \
    /Users/xiayang075/Documents/项目/IncrementallyUpdate/app/src/main/jni/bzip2/bzip2.c \
    /Users/xiayang075/Documents/项目/IncrementallyUpdate/app/src/main/jni/bzip2/bzip2recover.c \
    /Users/xiayang075/Documents/项目/IncrementallyUpdate/app/src/main/jni/bzip2/bzlib.c \
    /Users/xiayang075/Documents/项目/IncrementallyUpdate/app/src/main/jni/bzip2/compress.c \
    /Users/xiayang075/Documents/项目/IncrementallyUpdate/app/src/main/jni/bzip2/crctable.c \
    /Users/xiayang075/Documents/项目/IncrementallyUpdate/app/src/main/jni/bzip2/decompress.c \
    /Users/xiayang075/Documents/项目/IncrementallyUpdate/app/src/main/jni/bzip2/huffman.c \
    /Users/xiayang075/Documents/项目/IncrementallyUpdate/app/src/main/jni/bzip2/randtable.c \
    /Users/xiayang075/Documents/项目/IncrementallyUpdate/app/src/main/jni/bzip2/readMe.txt \

LOCAL_C_INCLUDES += /Users/xiayang075/Documents/项目/IncrementallyUpdate/app/src/main/jni
LOCAL_C_INCLUDES += /Users/xiayang075/Documents/项目/IncrementallyUpdate/app/src/debug/jni

include $(BUILD_SHARED_LIBRARY)
APP_PLATFORM:=android-14

在jni目录下创办Application.mk文件,复制以下代码:

APP_MODULES := libApkPatchLibrary (lib+so文件名)
APP_ABI := all

修改app module下的build.gradle文件,如下:

    ndk{
        moduleName "ApkPatchLibrary"
    }
    sourceSets {
        main {
            jni.srcDirs = [] //禁用gradle编译jni
            jniLibs.srcDirs = ['libs'] // libs为so文件所在包路径
        }
    }

引入仿照效法以下小说编写翻译NDK,拔尖轻松的Android Studio jni
实现(无需命令行卡塔尔国

将差分包与眼下采用合成新包,注意临蓐上要静心对差分包、本地包以致改动后的新包做MD5文件校验,幸免文件被歪曲,确定保障最终身成新包的MD5值与全量包一致。

    private class PatchTask extends AsyncTask<String, Void, Integer> {

        @Override
        protected Integer doInBackground(String... params) {

            try {

                int result = PatchUtils.getInstance().patch(srcDir, destDir2, patchDir);
                if (result == 0) {
                    handler.obtainMessage(4).sendToTarget();
                    return WHAT_SUCCESS;
                } else {
                    handler.obtainMessage(5).sendToTarget();
                    return WHAT_FAIL_PATCH;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return WHAT_FAIL_PATCH;
        }

        @Override
        protected void onPostExecute(Integer integer) {
            super.onPostExecute(integer);
            loadding.setVisibility(View.GONE);
        }
    }

安装新包

在乎运用chmod命令校订权限,不然在高版本Android系统上或许会报错。

    private void install(String dir) {
        String command = "chmod 777 " + dir;
        Runtime runtime = Runtime.getRuntime();
        try {
            runtime.exec(command); // 可执行权限
        } catch (IOException e) {
            e.printStackTrace();
        }

        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.setDataAndType(Uri.parse("file://" + dir), "application/vnd.android.package-archive");
        startActivity(intent);
    }

结语:

使用增量更新办法得以缓和陈年使用全量更新时安装包过大的主题素材,但其本身还会有以下不足:

  • 多版本运行冗杂,当线上存在多少个本午时,要给每一个版本分别生成差分包;
  • 行使多路子包时,要针对种种渠道包分别生成差分包,产生差分包比很多,难以维护;
  • patch信任地方版本安装包完整性,要是当半夏件损坏恐怕被曲解,就不可能增量进级,只好下载全量包进行进级;
  • 使用bs diff/patch算法生成的差分包体量依旧相当的大,以同学会为例,新老包大小约为15M左右,修正一点点代码并生成差分包体量到达了5M左右,与合法表明的差量包体量约为全量包体量的45%相似,但上述差分算法还应该有待优化的空中,借使急需对差分算法举行改过可参看HDiffPatch
    和 rsync rolling等。

参考:

  • Android完结选择的增量更新\升级
  • IncrementallyUpdate
  • 增量更新:bsdiff工具的设置和利用
  • 精品简单的Android Studio jni
    实现(没有必要命令行卡塔尔
  • 同胞开源的HDiffPatch差分算法
  • crsync-基于rsync
    rolling算法的文书增量更新.md

Post Author: admin

发表评论

电子邮件地址不会被公开。 必填项已用*标注