客户端合并差分文件实现更新(Android环境下)

客户端合并差分文件实现更新(Android环境下)

1. 下载差分文件

编写下载文件工具类DownloadUtils

package com.skyward.increment_update.util;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

import android.os.Environment;

public class DownloadUtils {

    /**
     * 下载差分文件
     * @param url
     * @return
     * @throws Exception
     */
    public static File download(String url){
        File file = null;
        InputStream is = null;
        FileOutputStream os = null;
        try {
            file = new File(Environment.getExternalStorageDirectory(),Constants.PATCH_FILE);
            if (file.exists()) {
                file.delete();
            }
            HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
            conn.setDoInput(true);
            is = conn.getInputStream();
            os = new FileOutputStream(file);
            byte[] buffer = new byte[1024];
            int len = 0;
            while((len = is.read(buffer)) != -1){
                os.write(buffer, 0, len);
            }
        } catch(Exception e){
            e.printStackTrace();
        }finally{
            try {
                os.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return file;
    }
    
}

2.将旧版本的apk文件和差分文件合并生成新版本的apk文件

  1. 添加本地支持,右击项目,点击Android Tools-> Add Native Support


    NDK开发配置
  2. 对Android项目进行NDK开发所需的相关配置


    NDK开发配置
  3. 编写Java本地方法

package com.skyward.increment_update.util;

public class BsPatch {

    /**
     * 合并差分文件
     * 
     * @param oldfile
     * @param newfile
     * @param patchfile
     */
    public native static void patch(String oldfile, String newfile, String patchfile);

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

4.使用javah命令生成头文件,并将其拷贝至项目的jni目录下。


javah命令生成头文件

5.去bsdiff/bspatch官网下载源码,bsdiff/bspatch源码下载地址。下载完成后,解压,将bspatch.c文件拷贝至项目的jni目录下。
6.进入bsdiff4.3-win32-src目录,用Visual Studio打开bspatch.dsp文件。

bspatch项目目录结构

7.在项目的jni目录下新建一个bzip2目录,将该bspatch项目所有的头文件和源文件(除bspatch.cpp外)拷贝至该目录下。
Java项目目录结构

8.修改bspatch.c文件,将其中的main函数修改为bspatch_main。用C语言实现Java本地方法调用bspatch_main方法。

#include "com_skyward_increment_update_util_BsPatch.h"
//可以将bzip2目录下所有的源文件都引入进来,也可以在Android.mk文件中编译所有源文件
//#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"

#include "bzip2/bzlib.h"
#include "bzip2/bzlib_private.h"
JNIEXPORT void JNICALL Java_com_skyward_increment_1update_util_BsPatch_patch
  (JNIEnv *env, jclass jcls, jstring oldfile_jstr, jstring newfile_jstr, jstring patchfile_jstr){
    int argc = 4;
    char* oldfile = (char*)(*env)->GetStringUTFChars(env,oldfile_jstr, NULL);
    char* newfile = (char*)(*env)->GetStringUTFChars(env,newfile_jstr, NULL);
    char* patchfile = (char*)(*env)->GetStringUTFChars(env,patchfile_jstr, NULL);

    char *argv[4];
    argv[0] = "bspatch";
    argv[1] = oldfile;
    argv[2] = newfile;
    argv[3] = patchfile;

    bspatch_main(argc,argv);

    (*env)->ReleaseStringUTFChars(env,oldfile_jstr, oldfile);
    (*env)->ReleaseStringUTFChars(env,newfile_jstr, newfile);
    (*env)->ReleaseStringUTFChars(env,patchfile_jstr, patchfile);
}

9.编写Android.mk文件

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := bspatch
LOCAL_SRC_FILES := bspatch.c bzip2/blocksort.c bzip2/bzlib.c bzip2/compress.c bzip2/crctable.c bzip2/decompress.c bzip2/huffman.c bzip2/randtable.c

include $(BUILD_SHARED_LIBRARY)

10.编写AndroidManifest.xml

 <uses-permission android:name="android.permission.INTERNET" />
 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
 <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />

3.安装新版本的apk文件

package com.skyward.increment_update;

import java.io.File;

import com.skyward.increment_update.util.ApkUtils;
import com.skyward.increment_update.util.BsPatch;
import com.skyward.increment_update.util.Constants;
import com.skyward.increment_update.util.DownloadUtils;

import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        new ApkUpdateTask().execute();
    }
    
    class ApkUpdateTask extends AsyncTask<Void, Void, Boolean> {

        @Override
        protected Boolean doInBackground(Void... params) {
            try {
                
                // 1. 下载差分文件
                File patch_file = DownloadUtils.download(Constants.URL_PATCH_DOWNLOAD_WINDOWS);
                Log.d("skyward", "下载差分文件");
                // 2. 合并差分文件
                String oldfile = ApkUtils.getSourceApkPath(MainActivity.this, getPackageName());
                BsPatch.patch(oldfile, Constants.NEW_APK_PATH, patch_file.getAbsolutePath());
                Log.d("skyward", "合并差分文件");
                return true;
            } catch (Exception e) {
                return false;
            }
            
        }
        
        protected void onPostExecute(Boolean result) {
            // 3. 安装apk
            if(result){
                Toast.makeText(MainActivity.this, "您正在进行无流量更新", Toast.LENGTH_SHORT).show();
                ApkUtils.installApk(MainActivity.this, Constants.NEW_APK_PATH);
            }
        };
    }
}

测试

至于测试在这里就不再赘述。简述一下步骤:

  1. 运行服务端的程序,生成差分文件
  2. 将生成的差分文件部署到服务端,供客户端下载
  3. 在手机端安装旧版本的apk文件


    安装新版本

    新版本apk

要注意:新旧版本的apk包名要一致

总结

本文只是简单介绍了一下增量更新的基本原理和步骤,代码还有很多地方可以完善的,比如服务端应该对各个apk版本进行版本控制,生成各个不同版本之间的apk文件。客户端的代码也可以优化,比如一般在后台服务中下在差分文件,下载差分文件时,应该检查当前客户端的版本号,下载对应的差分包。

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

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,244评论 25 707
  • 因为项目需要前两天研究了下增量更新的,如果项目没有硬性规定的话,本人推荐使用第三方的SDK. 比如:友盟的增量更新...
    Ten_Minutes阅读 9,836评论 1 16
  • 1.概述 1.1.什么是应用增量更新 当我们要更新一个应用的时候,以前很多更新的做法是下载一个新版本去覆盖一个旧版...
    揚灵阅读 3,142评论 8 19
  • 增量更新在Android开发中是一种很常见的技术。 增量更新的原理 增量更新的原理非常简单,就是将本地apk与服务...
    re冷星阅读 1,557评论 3 3
  • 1.上足球课必须穿足球鞋吗?我不能告诉你必须穿,那样太专制,而且确实有人光脚丫子踢球。先回答我一个问题吧:晚上睡觉...
    药师雷子阅读 680评论 1 6