上一篇介紹了在Windows平臺上生成diff.zip和diffMD5.txt的生成工具,接下來介紹在移動端如何使用diffMD5.txt和diff.zip來merge資源和bundle文件,從而差量熱更新。
按照慣例,先講一下整體思想:
1、下載MD5文件,與本地MD5文件進行比對,如果相同,不需要下載diff.zip包,如果不同下載diff.zip
這裏下載MD5文件和比對的邏輯就不再贅述。同樣,下載diff.zip的邏輯也不再贅述。
2、將下載出來的diff.zip進行處理(核心邏輯)
(1)、將diff.zip進行解壓
(2)、將目前的bundle文件和資源文件進行備份,爲將來的回滾處理做準備(目前沒有操作)
(3)、合併bundle文件
(4)、合併資源文件
(5)、備份MD5文件
(6)、刪除diff.zip的解壓文件夾
下面將主要介紹(1)、(3)、(4)的核心邏輯代碼:
(1)、將diff.zip解壓縮:解壓縮的時候只需要注意一點,及目錄結構的還原:如壓縮時文件的目錄爲res/drawable-xhdpi/image.png,壓縮後中間文件夾均會消失,同時文件名稱改爲res/drawable-xhdpi/image.png,在解壓縮時需要將文件名重新還原成原來的目錄結構。
public static boolean decompression(String zipFile, String folderPath) throws ZipException, IOException {
ZipFile zfile = new ZipFile(zipFile);
Enumeration zList = zfile.entries();
ZipEntry ze = null;
byte[] buf = new byte[1024];
while (zList.hasMoreElements()) {
ze = (ZipEntry) zList.nextElement();
String zeName = ze.getName();
String basePath = folderPath;
if (zeName.contains("\\")) {
String[] dirsNames = zeName.split("\\\\");
for (int i=0;i<dirsNames.length;i++) {
if (i == dirsNames.length-1) {
zeName = dirsNames[i];
continue;
}
basePath = basePath + File.separator + dirsNames[i];
createDir(basePath);
}
}
OutputStream os = new BufferedOutputStream(
new FileOutputStream(getRealFileName(basePath, zeName)));
InputStream is = new BufferedInputStream(zfile.getInputStream(ze));
int readLen = 0;
while ((readLen = is.read(buf, 0, 1024)) != -1) {
os.write(buf, 0, readLen);
}
is.close();
os.close();
}
zfile.close();
return true;
}
(3)、合併bundle文件:
public void mergeBundle(Context context) {
String currentBundleFilePath = FileUtils.getCurrentBundleFilePath(context);
String diffBundleFilePath = FileUtils.getDiffBundleFilePath(context);
if ("".equals(currentBundleFilePath) || "".equals(diffBundleFilePath)) {
return;
}
BundleDiffMerge.bundleDiffMerge(currentBundleFilePath,diffBundleFilePath,currentBundleFilePath);//合併bundle文件的核心代碼
}
/**
* @param oldBundlePath 爲oldBundle
* @param diffBundlePath 爲diffBundle
* @param outputPath 爲輸出newBundle路徑
*/
public static void bundleDiffMerge(String oldBundlePath,String diffBundlePath,String outputPath) {
String oldPath = oldBundlePath;
String diffPath = diffBundlePath;
diff_match_patch dmp = new diff_match_patch();
//將text diff轉換爲patch
LinkedList<diff_match_patch.Patch> pathes = (LinkedList<diff_match_patch.Patch>) dmp.patch_fromText(DiffUtils.getStringFromPat(diffPath));
//與舊bundle合併 生成新bundle
Object[] bundleArray = dmp.patch_apply(pathes,getJsBundleFromAssets(oldPath));
try {
File outputFile = new File(outputPath);
if (!outputFile.exists()) {
outputFile.createNewFile();
}
Writer writer = new FileWriter(outputPath);
String newBundle = (String) bundleArray[0];
writer.write(newBundle);
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
(4)、合併資源文件
private void mergeRes(Context context) {
String diffResDirPath = FileUtils.getDiffResDirPath(context);
if ("".equals(diffResDirPath)) {
Log.e("------","沒有需要merge的資源");
return;
}
File resFile = new File(diffResDirPath);
if (resFile.isDirectory()) {
for (File file : resFile.listFiles()) {
if (file.isDirectory() && file.getName().contains("drawable")) {
//只copy drawable相關的資源文件
com.gome.work.diff.utils.FileUtils.copyDir(file.getAbsolutePath(),FileUtils.getRootFile(context).getAbsolutePath() + "/" + file.getName());
}
}
}
}