热更新Tinker研究(八):res和so的patch文件生成
来源:互联网 发布:剑三dbm数据怎么删除 编辑:程序博客网 时间:2024/05/20 12:46
热更新Tinker研究(一):运行tinker-sample-android
热更新Tinker研究(二):结合源码学习Dex格式
热更新Tinker研究(三):加载补丁
热更新Tinker研究(四):TinkerLoader
热更新Tinker研究(五):Application的隔离
热更新Tinker研究(六):TinkerPatchPlugin
热更新Tinker研究(七):Dex的patch文件生成
热更新Tinker研究(八):res和so的patch文件生成
热更新Tinker研究(九):Dex文件的patch
热更新Tinker研究(十):Res文件的patch
热更新Tinker研究(十一):so文件的patch
热更新Tinker研究(八):res和so的patch文件生成
ResDiffDecoder和BsDiffDecoder分别是负责resource和so文件的patch生成相关的,它们很多地方比较相似,这里放在一起来说明。
一、ResDiffDecoder
ResDiffDecoder是控制resources的patch文件生成的,主要是控制增加、修改和删除的信息,这里对于大文件和小文件也有不同的区分,小文件只需要直接拷贝,大文件需要做差分文件。
public class ResDiffDecoder extends BaseDecoder { private static final String TEST_RESOURCE_NAME = "only_use_to_test_tinker_resource.txt"; private static final String TEST_RESOURCE_ASSETS_PATH = "assets/" + TEST_RESOURCE_NAME; private static final String TEMP_RES_ZIP = "temp_res.zip"; private static final String TEMP_RES_7ZIP = "temp_res_7ZIP.zip"; private final InfoWriter logWriter; private final InfoWriter metaWriter; private ArrayList<String> addedSet; //增加的 private ArrayList<String> modifiedSet; //修改的 private ArrayList<String> largeModifiedSet; ///修改的大文件 private HashMap<String, LargeModeInfo> largeModifiedMap; //修改的大文件map保存 private ArrayList<String> deletedSet; //删除的 ......}
dealWithModeFile()是主要进行区分大小文件处理的方法,
private boolean dealWithModeFile(String name, String newMd5, File oldFile, File newFile, File outputFile) throws IOException { if (checkLargeModFile(newFile)) { //判断是否是大文件 if (!outputFile.getParentFile().exists()) { //确保父目录存在 outputFile.getParentFile().mkdirs(); } BSDiff.bsdiff(oldFile, newFile, outputFile); //生成diff文件 //treat it as normal modify //检查是否需要当做diff文件对待 if (Utils.checkBsDiffFileSize(outputFile, newFile)) { LargeModeInfo largeModeInfo = new LargeModeInfo(); largeModeInfo.path = newFile; largeModeInfo.crc = FileOperation.getFileCrc32(newFile); largeModeInfo.md5 = newMd5; largeModifiedSet.add(name); //加入large信息 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生成diff文件,如果判断diff文件符合要求,就按照大文件进行处理。
对于大文件的判断,
private boolean checkLargeModFile(File file) { long length = file.length(); if (length > config.mLargeModSize * TypedValue.K_BYTES) { return true; } return false; }
对于是否需要按照大文件处理,
public static boolean checkBsDiffFileSize(File bsDiffFile, File newFile) { if (!bsDiffFile.exists()) { throw new TinkerPatchException("can not find the bsDiff file:" + bsDiffFile.getAbsolutePath()); } //check bsDiffFile file size double ratio = bsDiffFile.length() / (double) newFile.length(); if (ratio > TypedValue.BSDIFF_PATCH_MAX_RATIO) { //如果diff比newFile的0.8倍还大,按照普通文件处理 Logger.e("bsDiff patch file:%s, size:%dk, new file:%s, size:%dk. patch file is too large, treat it as newly file to save patch time!", bsDiffFile.getName(), bsDiffFile.length() / 1024, newFile.getName(), newFile.length() / 1024 ); return false; } return true; }
二、BsDiffDecoder
BsDiffDecoder是负责os文件差分的,区别是没有resources那种大小文件的区分,关键性代码如下,
public boolean patch(File oldFile, File newFile) throws IOException, TinkerPatchException { //first of all, we should check input files if (newFile == null || !newFile.exists()) { return false; } //new add file String newMd5 = MD5.getMD5(newFile); File bsDiffFile = getOutputPath(newFile).toFile(); if (oldFile == null || !oldFile.exists()) { FileOperation.copyFileUsingStream(newFile, bsDiffFile); writeLogFiles(newFile, null, null, newMd5); return true; } //both file length is 0 if (oldFile.length() == 0 && newFile.length() == 0) { return false; } if (oldFile.length() == 0 || newFile.length() == 0) { FileOperation.copyFileUsingStream(newFile, bsDiffFile); writeLogFiles(newFile, null, null, newMd5); return true; } //new add file String oldMd5 = MD5.getMD5(oldFile); if (oldMd5.equals(newMd5)) { return false; } if (!bsDiffFile.getParentFile().exists()) { bsDiffFile.getParentFile().mkdirs(); } BSDiff.bsdiff(oldFile, newFile, bsDiffFile); if (Utils.checkBsDiffFileSize(bsDiffFile, newFile)) { writeLogFiles(newFile, oldFile, bsDiffFile, newMd5); } else { FileOperation.copyFileUsingStream(newFile, bsDiffFile); writeLogFiles(newFile, null, null, newMd5); } return true; }
三、bsdiff算法
bsdiff算法的核心思想是构造两个数组,找出公共序列的位置,一个是diff数组,一个是extra数组。diff数组是两个序列之间的差,extra表示new多余old的部分
求公共子串,需要用到后缀数组,这里关于关于后缀数组,做几个基本的名词的解释。
字符串的大小比较: 关于字符串的大小比较,是指通常所说的 “ 字典顺序 ” 比较, 也就是对于两个字符串 u 、v ,令 i 从 1 开始顺次比较 u[i] 和 v[i] ,如果u[i]=v[i] 则令 i 加 1 ,否则若 u[i] < v[i] 则认为 u < v ,u[i] > v[i] 则认为 u > v,比较结束。如果 i > len(u) 或者 i > len(v) 仍比较不出结果,那么若 len(u) < len(v)则认为 u < v , 若 len(u)=len(v) 则 认 为 u=v ,若 len(u) > len(v) 则 u > v 。
注:从字符串的大小比较的定义看,字符串s的所有后缀中任其中一对(u,v)不可能会相等,因为必要条件 len(u) ≠ len(v)不可能满足。所以任一字符串s中有len(s)个互不相同的后缀。我们可以将s的所有后缀排列,利用 后缀数组sa 与 名次数组rank 储存。
后缀数组sa: 将s的n个后缀从小到大排序后将 排序后的后缀的开头位置 顺次放入sa中,则sa[i]储存的是排第i大的后缀的开头位置。简单的记忆就是“排第几的是谁”。
名次数组rank: rank[i]保存的是suffix(i){后缀}在所有后缀中从小到大排列的名次。则 若 sa[i]=j,则 rank[j]=i。简单的记忆就是“你排第几”。
然后再根据公共子串的位置去得到diff和extra数组。这个过程随后会补图说明。
- 热更新Tinker研究(八):res和so的patch文件生成
- 热更新Tinker研究(十):Res文件的patch
- 热更新Tinker研究(十一):so文件的patch
- 热更新Tinker研究(九):Dex文件的patch
- 热更新Tinker研究(七):Dex的patch文件生成
- 热更新Tinker研究(五):Application的隔离
- 热更新Tinker 的研究与集成
- 热更新Tinker研究(四):TinkerLoader
- 热更新Tinker研究(六):TinkerPatchPlugin
- 热更新Tinker研究(一):运行tinker-sample-android
- 热修复tinker 更新.so出现的问题
- 热更新Tinker研究(三):加载补丁
- Android热更新(Tinker)
- tinker热修复--集成tinker patch 详解
- 热更新Tinker的初次集成使用
- 热更新Tinker的集成使用
- 热更新Tinker研究(二):结合源码学习Dex格式
- 集成tinker热更新
- sublime 编辑器如何安装插件
- Unity3D二维码的识别与生成
- 匿名内部类的使用
- Android 常用尺寸转换
- Java的final
- 热更新Tinker研究(八):res和so的patch文件生成
- git命令行
- python-enumerate枚举函数
- 面试中常见的字符串库函数编程
- Android Theme设置背景图片,底部被导航栏遮盖
- js入门(2)-window
- mm_struct
- ViewPager
- 三维点云配准