基于bsDiff拆分模式所做的资源包的热部署热更新

项目场景:

`最近项目中 有一个新的需求 本来我开发的app一些基于webview所作的网页静态资源 需要本地化到系统中 这样可以少消耗网络带宽以及流量 基于这个场景 引出了资源包的更新机制问题 emmm更新这玩意贼麻烦 因为你所持有的资源包 什么资源都有 接口的返回json文件 图片啊 视频啊 什么什么的 贼烦。那么有没有一种可以囊括所有文件格式 并做到更新的方式呢 有那就是基于二进制算法的bsdiff拆分形式。

原理

二进制这个东西 相信大家都不陌生 我们接触的所有文件格式 其实在计算机内部 都是二进制的编码 比如图片 就是在开头定义了图片的宽高 如果你用记事本的形式打开图片 然后删除前面一些部分 图片是不是打不开了 还真是 但是呢 你如果删除的是后半部分 那么你的图片还是能打开的 只是只会展示一半 应该大概也许不止我一个人这么干过吧虾h(~ ̄▽ ̄)~ 一前闲着无聊 咳咳廉颇老矣啊( *︾▽︾)

准备

需要的开源文件

这里我把需要用到的代码和工具都整理了一下放到了一起:https://www.aliyundrive.com/s/ALCxbGeWY2o在这里插入图片描述
bzip2:是bsdiff依赖的一个库,这里我只存放了需要用到的文件,完整版的下载地址为:https://sourceforge.net/projects/bzip2/files/latest/download
bsdiff-win:是编译好的Windows平台下的可执行文件,可以在Windows平台生成差异文件和合并文件
bsdiff-source:是bsdiff的源码,它的官网为:http://www.daemonology.net/bsdiff/

工具的使用方式

只需要在工具所在的目录打开命令行窗口
在这里插入图片描述

然后输入命令即可

#生成差异文件命令
bsdiff [旧文件] [新文件] [差异文件]
#合并文件命令
bspatch [旧文件] [新文件] [差异文件]
#生成差异文件命令
bsdiff [旧文件] [新文件] [差异文件]
#合并文件命令
bspatch [旧文件] [新文件] [差异文件]

例如我这创建两个文本文件old.txt和new.txt
old.txt
new.txt


在这里插入图片描述
在这里插入图片描述

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

在这里插入图片描述
然后你就会看到我们生成出来的拆分包
在这里插入图片描述

这个时候我再利用bspatch命令,将old.txt和patch文件合成new2.txt。咳咳忽略俺打错的字
在这里插入图片描述
然后这个是时候 你看看 是不是就会有两个最新的文件一个new.txz/new2.txt
在这里插入图片描述
我们打开new2.txt发现与new.txt是一样的,瞅瞅是不是一毛一样
new2.txt

在这里插入图片描述

代码:

好 相信看到这里 大家也懂这个东西是干嘛的了 又怎么用的了吧 相对于这些 大家肯定还是想看的如何使用代码来进行这些操作!

集成

1.集成bspatch到项目
由于Android端只需要合并文件所以我们只需要集成bspatch即可,我们将bsdiff-source/bsdiff-4.3文件夹中的bspatch.c文件拷贝到cpp目录,然后将bzip2文件夹下的文件拷贝到cpp下的bzip(新建的目录)目录下
在这里插入图片描述
此外我们还要对bspatch.c进行修改,我们在文件顶部加入bzip2的引用

/** 导入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"

在这里插入图片描述

否则的话你运行项目的时候可能会报如下错误
在这里插入图片描述
然后我们还需要新建bspatch.h放到bzip文件夹下,这样做目的是为了可以在native-lib.cpp文件中使用main方法(注意:这里的main方法并不是入口函数,就是一个执行命令的普通函数)
在这里插入图片描述
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头文件链接到项目

2.创建JNI方法
创建PatchUtil工具类,创建合并文件的JNI方法

public class PatchUtil {
    
    
    static {
    
    
        System.loadLibrary("native-lib");
    }
    /**
     * 合并APK文件
     * @param oldApkFile 旧APK文件路径
     * @param newApkFile 新APK文件路径(存储生成的APK的路径)
     * @param patchFile 差异文件
     */
    public native static void patchAPK(String oldApkFile,String newApkFile,String patchFile);
}

C++实现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));

    //调用合并的方法
    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中增加合成的调用

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

好了 看到这里 基本照着上面的步骤 你就可以搞定了
但是但是但是::: 说三遍才能表达我说的比较重要 !!!有些同学应该发现了问题 没有返回值 这要是我tm合包错误 那是不是 我的资源包就GG 。唉 在这里我还是要很负责任的告诉你 还真的就是会GG 没有返回值 如果合抱发生错误 会直接导致你的app崩溃 c底层报错 你就只能通过 emmm好像好像 有返回值也会导致crash哦 哈哈哈算了 有返回值总比没有返回值的好
在这里插入图片描述
看一下源码 你就会知道 失败是会返回1的 那么没有失败是不是就自定一个就可以了 这个就很简单了
在这里插入图片描述
来整个有返回值得方法 然后其实就是上面那个没有返回值得方法capy一份 然后添加上
在这里插入图片描述
这三行代码 三行代码 让老板给我工资五十万 !! 今天我就教给你!! 最后 上面这些你可以以model的形式弄一个 然后打成aar的形式 让主项目调用 或者说 直接通过主项目 建立model的形式进行代码的调用!!!! 好了 今天的小点课堂下课了 。 不定时更新项目中的实用技术 基于项目做最深层次的理解与分析 让每一个程序员都保持秀发 好男人就是我 我就是笨小点 !! 咋们下次见。

猜你喜欢

转载自blog.csdn.net/weixin_47143458/article/details/124171483
今日推荐