Android應用增量更新

增量概述

之前在創業公司,人手不夠,業務人員也要參與功能測試。有一段時間,應用的版本迭代非常快,基本上兩天一版,測試時要重新下版本。當時,就有參與測試的人員抱怨說:測得這麼頻繁,能不能出個補丁啊,就不用整個下了。我那時候的回答的:這和遊戲不一樣,都是重新下載的。後來才發現,增量更新也是能夠實現的。現在我帶大家來了解下增量更新的條件與步驟。

增量更新的重點在於生成增量文件並且和老文件合併:
1. 獲取老的apk(如果手機上存在老版本應用的話)
2. 生成增量文件(對比老apk)
3. 增量文件和老apk合併

增量文件的生成都是通過工具做二進制的一個diff和patch了。
工具的下載地址:
http://www.daemonology.net/bsdiff/bsdiff-4.3.tar.gz
解壓後執行一下步驟
1.解壓文件裏面有個文件:Makefile,以文本的形式打開,將install:下面的if,endif添加一個縮進。
添加後文件如下所示:

CFLAGS      +=  -O3 -lbz2

PREFIX      ?=  /usr/local
INSTALL_PROGRAM ?=  ${INSTALL} -c -s -m 555
INSTALL_MAN ?=  ${INSTALL} -c -m 444

all:        bsdiff bspatch
bsdiff:     bsdiff.c
bspatch:    bspatch.c

install:
    ${INSTALL_PROGRAM} bsdiff bspatch ${PREFIX}/bin
    .ifndef WITHOUT_MAN
    ${INSTALL_MAN} bsdiff.1 bspatch.1 ${PREFIX}/man/man1
    .endif

2.生成的bspatch和bsdiff只需要用到bsdiff,bsdiff用於服務端生成的增量文件,bspatch用於合併old.apk和增量文件肯定,在應用內部做

在拿到bsdiff和bspatch以後,可以愉快的使用他們的:修改應用代碼生成老的和心的apk

生成增量文件

./bsdiff old.apk new.apk old-to-new.patch

這樣就生成了一個增量文件old-to-new.patch

增量文件和old.apk合併成新的apk

./bspatch old.apk new2.apk old-to-new.patch

至此我們已經在測試中完成的增量文件的生成和合並,但在實際中合併的過程是在客戶端實現的:提取原來的apk,與增量文件合併

客戶端操作

1.提取當前apk

public class ApkExtract {
    public static String extract(Context context) {
        context = context.getApplicationContext();
        ApplicationInfo applicationInfo = context.getApplicationInfo();
        String apkPath = applicationInfo.sourceDir;
        Log.d("hongyang", apkPath);
        return apkPath;
    }
}

2.製作bspatch so
這裏需要一些ndk的知識
首先聲明一個類,寫個native方法,如下:

public class BsPatch {

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

    public static native int bspatch(String oldApk, String newApk, String patch);

}

三個參數已經很明確了;

同時別忘了在module的build.gradle下面:

defaultConfig {
    ndk {
        moduleName = 'bsdiff'
    }
}

接下來就是去完成c的代碼的編寫了;

首先在app/main目錄下新建一個文件夾jni,把之前下載的bsdiff中的bspatch.c拷貝進去;

然後按照jni的規則,在裏面新建一個方法:

JNIEXPORT jint JNICALL Java_com_zhy_utils_BsPatch_bspatch
        (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));


    int ret = patchMethod(argc, argv);

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

上面的操作完成後,最後一步就簡單了,首先準備兩個apk:

old.apk new.apk
1
1
然後製作一個patch,下面代碼中的PATCH.patch;

將old.apk安裝,然後將new.apk以及PATCH.patch放置到存儲卡;

最後在Activity中觸發

private void doBspatch() {
    final File destApk = new File(Environment.getExternalStorageDirectory(), "dest.apk");
    final File patch = new File(Environment.getExternalStorageDirectory(), "PATCH.patch");

    //一定要檢查文件都存在

    BsPatch.bspatch(ApkExtract.extract(this),
            destApk.getAbsolutePath(),
            patch.getAbsolutePath());

    if (destApk.exists())
        ApkExtract.install(this, destApk.getAbsolutePath());
    }//啓讀寫SDCard權限,記得在代碼中校驗需要的文件都存在。

install實際就是通過Intent去安裝了:

 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);
    }

以上來自於弘洋的博客,相關工具已經封裝好了,原地址
http://blog.csdn.net/lmj623565791/article/details/52761658

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章