NDK开发基础④增量更新之客户端合并差分包

接续上篇NDK开发基础③增量更新之服务器端生成差分包

前情提要

增量更新原理就是在服务器端使用bsdiff进行文件内容比较,再使用了bzip2进行文件压缩 , 在下载APP时可以减少用户流量 。在客户端 , 则是将下载好的拆分包与现有的APK进行文件合并 , 得出新的APK, 再进行安装 。

生产资源及工具

bsdiff --- bsdiff 生成差分包及合并差分包库 , 使用bspatch.c文件
bzip2 --- bzip2 bsdiff 依赖
服务器 --- Tomcat 7.0 (模拟网络环境)放置差分包 , 供APP下载
开发工具 --- Android Studio 2.2RC2 NDK开发

一 , 合并差分包

Ⅰ 提取bzip2中的源文件

bzip2

Ⅱ 将bzip2加入到Android Studio项目中

首先将工程切换到Project模式 , 将bzip2文件夹复制到cpp目录下 。因为最新的Android Studio采用的是CMake构建工具 , 所有需要在bzip2目录下,创建一个CMakeLists.txt文件:

bzip2 cmake

Ⅲ 将bspatch.c复制到cpp目录下 , 并将自动生成的CMakeList.txt文件拖拽到cpp目录下 , 并添加子目录参与编译 。

bspatch cmake

修改了CMakeLists.txt文件的路径之后 , 需要在build.gradle中修改一下配置了:

build.gradle

并且配置一下build环境

build

Ⅳ 编写JNI

public class BspatchJNI {

    /**
     * 合并增量文件
     * @param oldFilePath 当前APK路径
     * @param newFilePath 合成后的新的APK路径
     * @param patchFilePath 增量文件路径
     */
    public static native void bspatchJNI(String oldFilePath,String newFilePath,String patchFilePath) ;

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

Ⅴ 编写C函数 , 怎样找执行函数 , 上一篇已经说了 , 套路都是一样的 。

/*合并APK*/
JNIEXPORT void JNICALL
Java_com_zeno_incrementupdate_ndk_BspatchJNI_bspatchJNI(JNIEnv *env, jclass type,
                                                        jstring oldFilePath_, jstring newFilePath_,
                                                        jstring patchFilePath_) {
    const char *oldFilePath = (*env)->GetStringUTFChars(env, oldFilePath_, 0);
    const char *newFilePath = (*env)->GetStringUTFChars(env, newFilePath_, 0);
    const char *patchFilePath = (*env)->GetStringUTFChars(env, patchFilePath_, 0);


    // if(argc!=4) errx(1,"usage: %s oldfile newfile patchfile\n",argv[0]);

    int argc = 4 ;
    char* argv[4] ;
    argv[0] = "bspatch";
    argv[1] = oldFilePath;
    argv[2] = newFilePath;
    argv[3] = patchFilePath;

    bspatch_main(argc,argv);

    LOGE("MainActivity","%s","合并APK完成");

    (*env)->ReleaseStringUTFChars(env, oldFilePath_, oldFilePath);
    (*env)->ReleaseStringUTFChars(env, newFilePath_, newFilePath);
    (*env)->ReleaseStringUTFChars(env, patchFilePath_, patchFilePath);
}

需要注意的时 , 在bspatch.c中是需要引入bzip2的 , 所有需要在文件头部, 引入bzip2 :

// bzip2
#include "bzip2/bzlib.c"
#include "bzip2/crctable.c"
#include "bzip2/compress.c"
#include "bzip2/decompress.c"
#include "bzip2/randtable.c"
#include "bzip2/blocksort.c"
#include "bzip2/huffman.c"

#define LOGE(TAG,FORMAT,...) __android_log_print(ANDROID_LOG_ERROR,TAG,FORMAT,__VA_ARGS__)

Ⅵ 使用

 class ApkUpdateTask extends AsyncTask<Void, Void, Boolean> {

        @Override
        protected Boolean doInBackground(Void... params) {
            try {
                //1.下载差分包
                Log.e(TAG, "doInBackground: 正在下载。。。。" );
                File patchFile = DownloadUtils.download(Constants.URL_PATCH_DOWNLOAD);

                //获取当前应用的apk文件/data/app/app
                String oldFile = APKUtils.getSourceApkPath(MainActivity.this, getPackageName());
                //2.合并得到最新版本的APK文件
                String newApkPath = Constants.NEW_APK_PATH;
                String patchFileAbsolutePath = patchFile.getAbsolutePath();
                BspatchJNI.bspatchJNI(oldFile, newApkPath, patchFileAbsolutePath);

                Log.d(TAG, "oldfile:"+oldFile);
                Log.d(TAG, "newfile:"+newApkPath);
                Log.d(TAG, "patchfile:"+patchFileAbsolutePath);
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }

            return true;
        }

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            progressDialog = new ProgressDialog(MainActivity.this);
            progressDialog.setTitle("正在下载...");
            progressDialog.show();
        }

        @Override
        protected void onPostExecute(Boolean result) {
            super.onPostExecute(result);
            progressDialog.dismiss();
            //3.安装
            if(result){
                Toast.makeText(MainActivity.this, "您正在进行无流量更新", Toast.LENGTH_SHORT).show();
                APKUtils.installApk(MainActivity.this, Constants.NEW_APK_PATH);
            }
        }

    }

使用起来都比较简单 , 这里就不将代码贴全了,篇末会给出github地址。

Ⅶ 打包

因为Android Studio使用了instant run技术 , 所以使用Android Studio生成APK最好是打正式包 , 并且包中内容要有差异性 , 然后再生成差分包 , 直接放置在WEB项目的WebContent根目录下即可 。

结语

增量更新 , 从服务器端到客户端实现 , 要写的代码其实不多 , 关键在于使用第三方C/C++源码的套路 , 使用JNI技术调用C/C++函数 , 其关键点就是找执行函数,通常为main函数 。NDK开发基础 , 这一篇算是结尾 , 新版的Android Studio的NDK支持比较完善 , 使用了CMake进行项目构建 ,语法高亮以及语法提示 , 都做得相当的好了 。开始下一个系列 , C++开发 。

源码

IncrementUpdate

参考

CMake Practice 百度网盘 密码: 58a3

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容