Android使用bsdiff和bspatch實(shí)現(xiàn)增量更新

目錄

前期準(zhǔn)備

1.工具下載

這里我把需要用到的代碼和工具都整理了一下放到了一起:https://www.aliyundrive.com/s/ALCxbGeWY2o


bzip2:是bsdiff依賴的一個(gè)庫(kù),這里我只存放了需要用到的文件,完整版的下載地址為:https://sourceforge.net/projects/bzip2/files/latest/download
bsdiff-win:是編譯好的Windows平臺(tái)下的可執(zhí)行文件,可以在Windows平臺(tái)生成差異文件和合并文件
bsdiff-source:是bsdiff的源碼,它的官網(wǎng)為:http://www.daemonology.net/bsdiff/

2.工具的使用方法

只需要在工具所在的目錄打開命令行窗口



然后輸入命令即可

#生成差異文件命令
bsdiff [舊文件] [新文件] [差異文件]
#合并文件命令
bspatch [舊文件] [新文件] [差異文件]

例如我這創(chuàng)建兩個(gè)文本文件old.txt和new.txt


old.txt
new.txt

然后我可以利用bsdiff命令生成差異文件




這個(gè)時(shí)候我再利用bspatch命令,將old.txt和patch文件合成new2.txt




我們打開new2.txt發(fā)現(xiàn)與new.txt是一樣的
new2.txt

原理講解

實(shí)現(xiàn)原理其實(shí)就是將新APK文件與舊APK文件進(jìn)行對(duì)比,得出一個(gè)差異文件,然后用戶端下載這個(gè)差異文件與手機(jī)上的那個(gè)舊APK文件進(jìn)行合并即可得到與新的APK文件一樣的文件,然后再安裝這個(gè)新APK即可實(shí)現(xiàn)增量更新,如下圖所示


具體實(shí)現(xiàn)

1.集成bspatch到項(xiàng)目

由于Android端只需要合并文件所以我們只需要集成bspatch即可,我們將bsdiff-source/bsdiff-4.3文件夾中的bspatch.c文件拷貝到cpp目錄,然后將bzip2文件夾下的文件拷貝到cpp下的bzip(新建的目錄)目錄下



此外我們還要對(duì)bspatch.c進(jìn)行修改,我們?cè)谖募敳考尤隻zip2的引用

/** 導(dǎo)入bzip2的引用*/
#include "bzip/bzlib.c"
#include "bzip/crctable.c"
#include "bzip/compress.c"
#include "bzip/decompress.c"
#include "bzip/randtable.c"
#include "bzip/blocksort.c"
#include "bzip/huffman.c"

否則的話你運(yùn)行項(xiàng)目的時(shí)候可能會(huì)報(bào)如下錯(cuò)誤



然后我們還需要新建bspatch.h放到bzip文件夾下,這樣做目的是為了可以在native-lib.cpp文件中使用main方法(注意:這里的main方法并不是入口函數(shù),就是一個(gè)執(zhí)行命令的普通函數(shù))



bspatch.h文件如下
#ifndef INCREMENTUPDATEDEMO_BSPATCH_H
#define INCREMENTUPDATEDEMO_BSPATCH_H
int main(int argc,char * argv[]);
#endif //INCREMENTUPDATEDEMO_BSPATCH_H

然后在bspatch.c中引入bspatch.h頭文件



接下來我們需要配置下CMakeLists.txt文件將bzip下的c文件和.h頭文件鏈接到項(xiàng)目

cmake_minimum_required(VERSION 3.10.2)

project("incrementupdatedemo")
#定義一個(gè)全局變量包含了所有要編譯的C文件
file(GLOB BZIP bzip/*.c)
#導(dǎo)入頭文件
include_directories(bzip)
add_library( # Sets the name of the library.
             native-lib
             SHARED
             native-lib.cpp
             #將bzip下的.c文件添加到library
             BZIP)
find_library( # Sets the name of the path variable.
              log-lib
              log )
target_link_libraries( # Specifies the target library.
                       native-lib
                       ${log-lib} )
2.創(chuàng)建JNI方法

創(chuàng)建PatchUtil工具類,創(chuàng)建合并文件的JNI方法

public class PatchUtil {
    static {
        System.loadLibrary("native-lib");
    }
    /**
     * 合并APK文件
     * @param oldApkFile 舊APK文件路徑
     * @param newApkFile 新APK文件路徑(存儲(chǔ)生成的APK的路徑)
     * @param patchFile 差異文件
     */
    public native static void patchAPK(String oldApkFile,String newApkFile,String patchFile);
}

C++實(shí)現(xiàn)JNI方法

#include <jni.h>
#include <string>
#include "bspatch.h"
extern "C"
JNIEXPORT void JNICALL
Java_com_itfitness_incrementupdatedemo_PatchUtil_patchAPK(JNIEnv *env, jclass clazz,
                                                          jstring old_apk_file,
                                                          jstring new_apk_file,
                                                          jstring patch_file) {
    int argc = 4;
    char * argv[argc];
    argv[0] = "bspatch";
    argv[1] = (char*) (env->GetStringUTFChars(old_apk_file, 0));
    argv[2] = (char*) (env->GetStringUTFChars(new_apk_file, 0));
    argv[3] = (char*) (env->GetStringUTFChars(patch_file, 0));

    //調(diào)用合并的方法
    main(argc, argv);

    env->ReleaseStringUTFChars(old_apk_file, argv[1]);
    env->ReleaseStringUTFChars(new_apk_file, argv[2]);
    env->ReleaseStringUTFChars(patch_file, argv[3]);
}
3.Activity中增加合成的調(diào)用
public class MainActivity extends AppCompatActivity {
    private TextView tv_version;
    private Button bt_update;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv_version = findViewById(R.id.tv_version);
        bt_update = findViewById(R.id.bt_update);
        tv_version.setText("1.0");
        bt_update.setOnClickListener(v->{
            new Thread(() -> {
                File oldApkFile = new File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "old.apk");
                File newApkFile = new File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "new.apk");
                File patchFile = new File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "patch");
                PatchUtil.patchAPK(oldApkFile.getAbsolutePath(),newApkFile.getAbsolutePath(),patchFile.getAbsolutePath());
                //安裝APK
                AppUtils.installApp(newApkFile);
            }).start();
        });
    }
}
4.編譯生成舊APK

這里我們?cè)?.0版本(舊版本)中展示當(dāng)前應(yīng)用的版本號(hào),如下所示



然后我們?nèi)〕鼍幾g生成的APK命名為old.apk


5.編譯生成新APK

然后我們將版本號(hào)改為2.0并且在按鈕下增加一張圖片



我們將其命名為new.apk


6.使用bsdiff生成差異文件

使用bsdiff生成差異文件



7.使用bspatch合并文件

接下來我們裝回舊版然后將old.apk和patch放到SD卡中,當(dāng)然真實(shí)環(huán)境的patch文件是通過網(wǎng)絡(luò)下載得到的,這里我們模擬已經(jīng)下載完畢了



點(diǎn)擊按鈕,會(huì)發(fā)現(xiàn)Download文件夾下出現(xiàn)了一個(gè)new.apk文件



然后我們通過代碼將new.apk安裝到手機(jī)上

案例源碼

https://gitee.com/itfitness/increment-update

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容