增量更新

一、定义

增量更新是指在进行更新操作时,只更新需要改变的地方,不需要更新或者已经更新过的地方则不会重复更新,增量更新与完全更新相对。对于我们app来说,一般对于用户来说用户的流量是很宝贵的,如果我们只改变了app中的一个变量,比如i。那么我们就需要重新发版,供用户下载更新整个app,而增量更新就不需要这样的操作了,虽然最终也是需要用户来安装的,但是用户下载的只是我们更改的部分。并且这个技术已经很完善。

二、使用

打成差分包过程windows和linux平台是有差异的

1、windows环境

下载bsdiff windows工具,可以自行百度下载。下载完成以后,进入目录,可以看到有两个工具bsdiff.exe和bspatch.exe.其中bsdiff是做差分包使用的,bspatch是用作合成新的app。

2、linux环境

3、配置android环境

(1)首先需要下载bispatch.c文件。下载地址bsdiff

(2)得到bispatch.c文件拷贝到项目的cpp目录下,发现需要bzlib.h,由于它不是系统文件,那么需要从外部引入

(3)下载bzip,它是可以实现压缩解压的过程,在合成差分包的过程用它进行压缩,那么在服务器下载的patch包就需要通过它进行解压。从它里面能够拿到bzlib.h相关代码文件,下载地址,bzip

(4)根据bzip提供的makeFile配置只保留以下文件,放入到cpp/bzip目录下

(5)此时编译发现还是提示找不到bzlib.h。因为我们上引入的方式是不正确,<>是只能引入系统文件,如果要引入外部文件,可以使用以下方式。重新编译成功了

#include "bzip/bzlib.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <err.h>
#include <unistd.h>
#include <fcntl.h>

(6)定义native层修复文件bspatcher.cpp,代码如下:

#include <jni.h>

// extern 声明在 bspatch.c
extern "C" {
extern int p_main(int argc, const char *argv[]);
}

extern "C"
JNIEXPORT void JNICALL
Java_com_cxz_bspatchlib_BsPatcher_bsPatch(JNIEnv *env, jobject instance, jstring oldApk_,
                                          jstring patch_, jstring output_) {
    // 将Java字符串转为C/C++的字符串,转换为UTF-8格式的char指针
    const char *oldApk = env->GetStringUTFChars(oldApk_, 0);
    const char *patch = env->GetStringUTFChars(patch_, 0);
    const char *output = env->GetStringUTFChars(output_, 0);

    // bspatch, oldfile, newfile, patchfile
    const char *argv[] = {"", oldApk, output, patch};
    p_main(4, argv);

    // 释放指向Unicode格式的char指针
    env->ReleaseStringUTFChars(oldApk_, oldApk);
    env->ReleaseStringUTFChars(patch_, patch);
    env->ReleaseStringUTFChars(output_, output);
}

其中会调用bspatch.c中的p_main方法。传递两个参数,第一个参数固定为4,第二个参数传递的是指针数组,分别为olkApk(旧的apk),patch(差分包)和output(合成新的apk)

(7)将上述文件加入到CMakeLists.txt编译

cmake_minimum_required(VERSION 3.4.1)

# 查找文件系统中制定模式的路径,如:/*是匹配根目录下的所有文件
file(GLOB bzip_source ${CMAKE_SOURCE_DIR}/src/main/cpp/bzip/*.c)

# 设置本地动态库,编译生成动态库
add_library(
        bspatcher # 模块名

        SHARED # 动态库、分享库

        src/main/cpp/native-lib.cpp
        src/main/cpp/bspatch.c
        ${bzip_source}) # 源文件

# 查找系统库,日志输出库Log
find_library(
        log-lib

        log)

# 需要链接或者编译的库
target_link_libraries(
        bspatcher

        ${log-lib})

 

(8)java层加载jni方法,定义一个工具类,代码如下

public class BsPatcher {

    // 用于在应用程序启动时,加载本地的lib库
    static {
        System.loadLibrary("bspatcher");
    }

    /**
     * 合成安装包
     *
     * @param oldApk 旧版本安装包,如1.1.1版本
     * @param patch  差分包,Patch文件
     * @param output 合成后新版本apk的输出路径
     */
    public static native void bsPatch(String oldApk, String patch, String output);

}

(9)模拟activity调用update()方法如下:

public void update() {
        // 从服务器下载 patch 到用户手机, SDCard 里面
        new AsyncTask<Void, Void, File>() {
            @Override
            protected File doInBackground(Void... voids) {
                // 获取旧版本路径(正在运行的apk路径)
                String oldApk = getApplicationInfo().sourceDir;
                //差分包路径,服务器下载到本地路径
                String patch = new File(Environment.getExternalStorageDirectory(), "patch").getAbsolutePath();
                //合成的新的apk保存路径
                String output = createNewApk().getAbsolutePath();
                if (!new File(patch).exists()) {
                    return null;
                }
                //开始合成,是一个耗时任务
                BsPatcher.bsPatch(oldApk, patch, output);
                //合成成功,重新安装apk
                return new File(output);
            }

            @Override
            protected void onPostExecute(File file) {
                super.onPostExecute(file);
                // 已经合成了,调用该方法,安装新版本apk
                if (file != null) {
                    if (!file.exists()) return;
                    Intent intent = new Intent(Intent.ACTION_VIEW);
                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
                    //7.0及以上安装apk有差异,需要兼容
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                        Uri fileUri = FileProvider.getUriForFile(MainActivity.this, MainActivity.this.getApplicationInfo().packageName + ".fileprovider", file);
                        intent.setDataAndType(fileUri, "application/vnd.android.package-archive");
                    } else {
                        intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
                    }
                    //重启apk
                    MainActivity.this.startActivity(intent);
                } else {
                    Toast.makeText(MainActivity.this, "差分包不存在!", Toast.LENGTH_LONG).show();
                }
            }
        }.execute();
    }

    /**
     * 创建合成后的新版本apk文件
     *
     * @return
     */
    private File createNewApk() {
        File newApk = new File(Environment.getExternalStorageDirectory(), "bsdiff.apk");
        if (!newApk.exists()) {
            try {
                newApk.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return newApk;
    }

注意:比如之前已经发不过1.0、2.0、3.0等版本。那么就需要根据用户的版本来合成不同的差分包。如果是1.0版本就需要针对1.0版本生成差分包供用户下载,依次类推。所以实际项目中,就需要在后台配置shell脚本,根据接口传递的版本号,生成差分包

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值