上一篇介绍了在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());
}
}
}
}