1. 程式人生 > >Android 生成差分包

Android 生成差分包

原部落格地址:http://blog.csdn.net/u013705351/article/details/22722499

如果沒用增量升級,我們的升級流程是這樣的:

1、打包好apk上傳到伺服器,設定apk版本

2、客戶端發現伺服器端有高版本apk。

3、直接下載最新版本apk提示安裝

這個過程中,在伺服器端只是儲存一個歷史版本的記錄,這樣的確也簡單。

但是直接下載apk,發現有個問題就是apk很大的時候,下載的時間比較長,所以才會有了查分升級

如果採用查分升級,我們的升級流程就變成這樣了:

         1、打包好apk上傳至伺服器,設定版本號。

         2、對所有舊版本都生成對應的patch(差分)檔案,如果上傳之前已經有n個版本,要對這n個版本都要生成差分包

         3、客戶端發現服務端有高版本apk。

         4、客戶端通過當前版本找到對應的patch檔案下載。

         5、客戶端對patch檔案和舊的apk進行合併。

 6、合併之後提示安裝

package redis;

import java.io.BufferedOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.security.MessageDigest;

import com.nothome.delta.Delta;
import com.nothome.delta.DiffWriter;
import com.nothome.delta.GDiffPatcher;
import com.nothome.delta.GDiffWriter;

public class DiffTool {

    private final static char[] hexChar = { '0', '1', '2', '3', '4', '5', '6',
            '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };

    private static String toHexString(byte[] b) {
        StringBuilder sb = new StringBuilder(b.length * 2);
        for (int i = 0; i < b.length; i++) {
            sb.append(hexChar[((b[i] & 0xF0) >>> 4)]);
            sb.append(hexChar[(b[i] & 0xF)]);
        }
        return sb.toString();
    }

    public static String getMD5(File file) {
        InputStream fis = null;
        String str = null;
        try {
            fis = new FileInputStream(file);
            byte[] buffer = new byte[1024];
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            int numRead = 0;
            while ((numRead = fis.read(buffer)) > 0) {
                md5.update(buffer, 0, numRead);
            }

            str = toHexString(md5.digest());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (Exception e) {

                }
            }
        }

        return str;
    }

    private static File mergeFile(final String source, final String patch,
            String target) throws Exception {
        GDiffPatcher patcher = new GDiffPatcher();
        File deffFile = new File(patch);
        File updatedFile = new File(target);
        patcher.patch(new File(source), deffFile, updatedFile);
        return updatedFile;
    }

    public static File mergeApk(final String source, final String patch,
            final String target, String newApkMd5) throws Exception {
        File updateFile = mergeFile(source, patch, target);
        String ufpMd5 = getMD5(updateFile);
        System.out
                .println("服務端下發的md5:" + newApkMd5 + ",新合併後的apk MD5:" + ufpMd5);
        if (ufpMd5 == null || !newApkMd5.equalsIgnoreCase(ufpMd5)) {
            if (updateFile.exists()) {
                updateFile.delete();
            }
            throw new Exception("MD5錯誤,不能成功合併!");
        }

        return updateFile;
    }

    /**
     * 生成差分包:old_new.patch = diff(old.apk, old.apk)
     * 
     * */
    private static void createPatch(String oldApkName, String newApkName,
            String patchName) {
        System.out.println("開始生成差分包");
        long start = System.currentTimeMillis();
        try {
            File newApk = new File("Max1.0.1040.apk");
            File oldApk = new File("Max1.0.0000.apk");
            File patchFile = new File("old_new.patch");
            DiffWriter output = null;
            output = new GDiffWriter(new DataOutputStream(
                    new BufferedOutputStream(new FileOutputStream(patchFile))));

            if (oldApk.length() > Integer.MAX_VALUE
                    || newApk.length() > Integer.MAX_VALUE) {
                System.err
                        .println("source or target is too large, max length is "
                                + Integer.MAX_VALUE);
                System.err.println("aborting..");

            }

            Delta d = new Delta();
            d.compute(oldApk, newApk, output);
            System.out.println("差分包生成完成,完成耗時:"
                    + (System.currentTimeMillis() - start) + "ms");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String args[]) throws Exception {
        String newApkName = "Max1.0.1040.apk";
        String oldApkName = "Max1.0.0000.apk";
        String patchName = "old_new.patch";
        String targetApkName = "new.apk";
        try {
            createPatch(oldApkName, newApkName, patchName);
            String newApkMd5 = getMD5(new File(newApkName));
            mergeApk(oldApkName, patchName, targetApkName, newApkMd5);

        } catch (Exception ioe) { // gls031504a
            System.err.println("error while patching: " + ioe);
        }

    }

}