前言:之前已经在文章中对Tinker的Dex热更新的源码做了分析,今天接着开始对Tinker的资源热更新做源码的分析,废话就不多啰嗦了直接开始正文啦。
一、资源补丁生成
友情提示:在上篇Dex分析的文章中已经介绍了生成补丁文件的开始流程,因此这里直接从ResDiffDecoder.patch(File oldFile, File newFile)开始分析。如果需要可以回头看一下Dex分析的文章内容。
ResDiffDecoder.patch(File oldFile, File newFile)主要负责资源文件补丁的生成,如果是新增的资源,直接将资源文件拷贝到目标目录;如果是修改的资源文件则使用dealWithModeFile函数处理。
// 如果是新增的资源,直接将资源文件拷贝到目标目录.
if (oldFile == null || !oldFile.exists()) {
if (Utils.checkFileInPattern(config.mResIgnoreChangePattern, name)) {
Logger.e("found add resource: " + name + " ,but it match ignore change pattern, just ignore!");
return false;
}
FileOperation.copyFileUsingStream(newFile, outputFile);
addedSet.add(name);
writeResLog(newFile, oldFile, TypedValue.ADD);
return true;
}
...
// 新旧资源文件的md5一样,表示没有修改.
if (oldMd5 != null && oldMd5.equals(newMd5)) {
return false;
}
...
// 修改的资源文件使用dealWithModeFile函数处理.
dealWithModeFile(name, newMd5, oldFile, newFile, outputFile);
在dealWithModeFile中会对文件大小进行判断,如果大于设定值(默认100Kb),采用bsdiff算法对新旧文件比较生成补丁包,从而降低补丁包的大小;如果小于设定值,则直接将该文件加入修改列表,并直接将该文件拷贝到目标目录。
if (checkLargeModFile(newFile)) { //大文件采用bsdiff算法
if (!outputFile.getParentFile().exists()) {
outputFile.getParentFile().mkdirs();
}
BSDiff.bsdiff(oldFile, newFile, outputFile);
//treat it as normal modify
// 对生成的diff文件大小和newFile进行比较,只有在达到我们的压缩效果后才使用diff文件
if (Utils.checkBsDiffFileSize(outputFile, newFile)) {
LargeModeInfo largeModeInfo = new LargeModeInfo();
largeModeInfo.path = newFile;
largeModeInfo.crc = FileOperation.getFileCrc32(newFile);
largeModeInfo.md5 = newMd5;
largeModifiedSet.add(name);
largeModifiedMap.put(name, largeModeInfo);
writeResLog(newFile, oldFile, TypedValue.LARGE_MOD);
return true;
}
}
modifiedSet.add(name); // 加入修改列表
FileOperation.copyFileUsingStream(newFile, outputFile);
writeResLog(newFile, oldFile, TypedValue.MOD);
return false;
BsDiff属于二进制比较,其具体实现大家感兴趣的可以自行查看相关