客戶端合并差分文件實現更新(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文件。客戶端的代碼也可以優化,比如一般在后臺服務中下在差分文件,下載差分文件時,應該檢查當前客戶端的版本號,下載對應的差分包。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,846評論 25 708
  • 因為項目需要前兩天研究了下增量更新的,如果項目沒有硬性規定的話,本人推薦使用第三方的SDK. 比如:友盟的增量更新...
    Ten_Minutes閱讀 9,870評論 1 16
  • 1.概述 1.1.什么是應用增量更新 當我們要更新一個應用的時候,以前很多更新的做法是下載一個新版本去覆蓋一個舊版...
    揚靈閱讀 3,227評論 8 19
  • 增量更新在Android開發中是一種很常見的技術。 增量更新的原理 增量更新的原理非常簡單,就是將本地apk與服務...
    re冷星閱讀 1,585評論 3 3
  • 1.上足球課必須穿足球鞋嗎?我不能告訴你必須穿,那樣太專制,而且確實有人光腳丫子踢球。先回答我一個問題吧:晚上睡覺...
    藥師雷子閱讀 701評論 1 6