布景
市面上的热修改计划大厂开源的有微信的tinker、美团的Robust、Qzone 的超级补丁、阿里系的Andfix、Sofix;
结束的套路gradle下载套路基本就两种
- 底层替换计划,捆绑多,时效好
- 类加载计划,时效性差,产品营销策划需求重启才收效,可是捆绑少,修改规划比较广
可是这些开源的修改结构都是针对App做修改的,没有依据SDK的处理计划,公司的产品是供应SDK给第三方集成,是含有代码文件以及资源文件的aar包,因而也需求一套能够针对aar 的热修改处理计划。
Robust 的原理
以下是官方原理图:
加载patch.dex ,替换掉要修改的类中的changeRedirect 类,每次调用调用方法的时分都会调用changeQ产品uickRedirect 的i开源是什么意思sSupport 方法,假定该方法回来的是false,则实施原先的旧的方法,假定回来为true,则会走patch类中的p开源节流打一个字atchedMethod。
装备文件中声明晰需求插桩的包名,Robust 在编译的时分会对声明的这个包名中的一切的gradle是什么类中gradle添加java面试题一个ChangeRedirect类,每个方法的前面添加一段代码
PatcgradlehProxyResult var3 = PatchProxy.proxy(new Ojava根底知识点bject[]{postcard, callback}, this, changeQuickRedirect, false, 5447, new Class[]{Postcard.class, InterceptorCallback.class}, Void.TYPE);
if (!var3.isSupported) {
}
接着看下这个PatchProxy做了什么
public static PatchProxyResult proxy(Object[] paramsArray, Objecgradlet current, ChangeQuickRedirect changeQuickRedirect, boolean isStatic, int methodNumber, Class[] paramsClassTypes开源软件, Class returnT开源众包ype) {
P产品批号是生产日期吗atchProxyResult patchProxyResult = new PatchProxyResult();
// 首要的逻辑在于这开源人脸辨认认聚顶科技在线,判别这个方法的是否需求实施patchMethod,假定需求则调accessDispatch方法实施pa产品批号是生产日期吗tchMethod
if (PatchProxy.isSugradle发音pport(paramsArray, current, changeQuickRedirect, isStatic, methodN产品质量法umbejavascriptr, paramsClassTyp开源阅读es, returnType)) {
patchProxygradle homeResult.isSupported = true;
pagradle是什么tchProxyResjava模拟器ult.result = PatchProxy.access产品运营首要做什么Dispatch(paramsArray, current, changeQuickRedirect, isStatic, methodNumber, paramsClassTypes, returnType);
}
return patchProxyResult;
}
这个gradle翻译PatchProxy.proxy 方法毕竟回来了个patchProxyResultJava,Pat开源是什么意思ch.proxy 里gradle打包面首要调了两个方法,PatchProxy.isSupport和PatchProxy.accessDispatch 方法,再往里看下isSupport 的判别逻辑是什么
public static boolean isSupport(Object[] paramsArray, Object current, ChangeQuickRedi开源节流rect chanjava是什么意思geQuickRgradle打包edirect, boolean isStatic, int methodNumber, Class[] paragradle下载慢解决方法msClassjava工作培训班Types, Class returnType) {
//Robust补丁优先实施,其他功用靠后
if (changeQuickRedirect == null) {
//不实施补丁,轮询其他监听者
if (registerExtensionL开源软件ist == null || registerExtensi开源是什么意思onList.isEgradle翻译mpty()) {
return false;
}
for (RobustExte开源人脸辨认认聚顶科技在线nsion robustExtensgradle是什么ion : r产品运营egisterE产品运营xtensionList) {
if (robustExtension.isSupport(new RobustArguments(paramsArray, current, isStatic, methodNumber, paramsClas开源是什么意思sTypes, returngradle下载Type))产品运营首要做什么) {
robustExtensionThreadLocal.set(robustExtension);
return true;
}
}
return false;
}
// 获取方法名,拼接成这样的方法 classMethod = className + ":" +产品运营首要做什么 methodNamegradle教程 + "java是什么意思:" + isStatic + ":" + methodNumber
String classMethod = getClassMethod(isStatic,gradle翻译 methodNumber);
if (TextUtils.isEmpty(cljava根底知识点assMethod)) {
return false;
}
// 获取实施方法所需求的产品司理参数,current 为其时类的实android体系下载例
Objava游戏ject[] objects = getObjects(paramsArray, current, isStat产品运营首要做什么ic);
try {
return changeQuickRedirect.is开源矿工Support(classMethod, objects);
} catch (Throwable t) {
return false;
}
}
这个gradle教程方法里边首要是处理方法名和方法所需求的参数,毕竟再传给changeRedirect类去判别,再看下changeRedirect的结束类里边的判别逻辑
public boolean isSupport(String methodName, Object[] paramArrayOfObject) {
String str = metandroid的drawable类hodName.split(":")[3];
this.methodsId = ":7:";
this.me开源我国thodLongName = "com.feelschaotic.samplesdk.manager.SdkManager.callBug();";
if (RollbackManager产品设计专业.gandroid体系下载etInstanceandroid平板电脑价格().getRollbackandroid什么意思(":7:")) {
return false;
}
return ":7:".cgradle打包ontains(android的drawable类new StringBuffer().append(":").appendandroid的drawable类(str).append(":").toString());
}
Robust 会给每个方法生成一个mandroid体系下载ethodId,getRollBack 是调用方传进去的roll产品设计BackListener,判android体系别该方法的回滚状态。
public Object accessDispatch(String methodName, Object[] paramArrayOfObject产品营销策划) {
SdkManagerPatcandroid/yunosh sdkManagerandroid是什么手机牌子Patcandroid下载安装h;
try {
if (!methodName.split(":")[2].equals("gradle homefalse")) {
s产品质量法dkManagerPatch = new SdkManagerPatch(null);
}gradle else if (keyToValueRelation.get(paramArrayOfObject[paramArrayOfandroid/yunosObject.length - 1]) == null) {
sandroid下载安装dkManagerPatch = new SdkManagerPatch(paramArrayOfObject[paramArrandroid平板电脑价格ayOfObject.length - 1]);
keyToValueRelation.put(paramArrayOfObject[paramArrayOfO开源人脸辨认认聚顶科技在线bject.length - 1], null);
} else {
sdkManagerPatjavascriptch = (SdkManagerPatch) keyToValueRelation.get(paramArrayOfObject[paramArrgradle装备ayOfObject.length - 1]);
}
if ("7".equals(methodName.split(":")[3])) {
sdkManagerPatch.callBug();
}
} catch (Throwable th) {
RollbackManager.getInstance().notifyOnException(this.mjava面试题ethodsId, this.methogradle下载慢解决方法dLongName, th);
th.pandroid体系下载rintStackTrace();
}
return nandroid什么意思uljava根底知识点l;
}
里边首要做了一个static method和 非staticandroid平板电脑价格 method 的gradle是什么差异,后边的批java游戏改方法的实施就交给了sdkManagerpatch,S产品密钥在哪里能找到dkManager 是demoandroid手机 中需求修改的类的称谓,Robust 中生成的patch.jar 都以修改的类名做前缀。
依据Rgradle装备obust开源软件的SDK处理计划
这个计划是 @FeelsChaotic 大佬提出的,感谢大佬,大佬原文链接:juejijava难学吗n.cn/post/684490…java难学吗
Robust 只要在application 方法下才干进行插桩以及生成补丁,apk的文件内容和aar 包的文件内容,因而能够在需求进行热更新的sdk模块在打包的时分设置成application 方法,之后在hook编译的进程,把application 方法下生成的文件打包成aar文件输出。
之后再hook processReleaseResources Task修改资源ID的修饰符
OK,改完一跑没东西输出,本来的资源整合的plugin 中对文开源是什么意思件的途径只适配了一般的debug和release的情况,项目开源众包中假定设置了多个途径的话编译输出的文件途径会在对应的release 文件夹前面多一级途径名的目录。
因而需求在packplugin 中添加对多途径版别打包的android的drawable类适配。
毕竟修改之后的packplugin 如下
impojava怎样读rt java.util.regex.Matcher
impor产品设计专业t java.utilandroid下载安装.regex.Pattern
final String SDK_PACKAGE_DIR = sdkPackageName.replace('.', File.separator)
final String PACK_PREFIX = 'sdk_hotfix'
String JAR_TASK_NAM开源众包E = 'jar_' + PACandroid下载K_PREFIX
String AAR_TASK_NAME = 'aar_' + PACK_PREFIX
String PATH = projectDir.tjavascriptoString() + File.separator + 'robustjar' + File.separator + 'release'
hookBuild(SDKjava面试题_PACKAGE_DIR)
hookAssembleAndCopyRes(PATH, JAR_TASK_NAME, AAR_TASK_NAME)
hookBundle(PATH)
pjava怎样读rivate void hookBuild(sdkPackageDir) {
tasks.whenTaskAdded { task ->
if (!iandroid体系sAppModule.toBoolean()) {
// 不是Applicatio产品营销策划n方法不处理
retgradle教程urn
}
Pattern p = Pattern.compile("^process(.*)ReleaseReso开源软件urces$")
Matcher m = p.matcher(task.name)
if (android是什么手机牌子!m.finjava工作培训班d()) {
return
}
String flavorName = task.name.minus("process").minus("Re产品运营首要做什么leaseResources")
p产品司理rintln '-- hookBuild 监听task:' + task.name + "flavorName: " + fandroid下载安装lavorName
task.doLast {
// hjava怎样读ook所需资源地点的父目gradle录, sdkbuildgenerated
Stgradle是什么ring generatedPath = buildDir.toString() + File.seandroid体系parator + "generated"
// R资源文件的途径,sdkbuildgeneratedrrelease包名R.jaandroid的drawable类vagradle装备
Stringradle发音g rPath = generategradle打包dPath + File.separator + "source" + File.separator + "r" + File.separator + flavorName + File.separatorjava根底知识点 + "release" + File.separator + sdkPackageDir + File.separator + "R.java"
println开源众包 '--R文件途径:开源阅读' + rPath
File file = new File(rPath)
if (file.exists()) {
println '--R文件存在,开始修改修饰符'
ant.replace(
file: rPath,gradle打包
token: 'public static final intjavascript',
value: 'public static int'
) {
fileset(file: rPath)
}
println '--R文件修改结束!'
} else开源是什么意思 {
println '--java难学吗【告警】R文件不存在!'
}
}
}
}
private void hookAssembleAndCopyResandroid下载(path, jarTaskName, aarTgradle发音askName) {
// 项目打release版别apk包的话,必定产品会调用到assemble(途径)Relandroid手机ease的指android/yunos令,所以我们能够用正则匹配来匹配一切途径的打Releajava工作培训班se包进程
Pattern p = Pattern.compile("^assemble(.*)Release$")
// 在javascripttask添加到列表的时分,进行打包task的匹配
tasks.whenTaskAdded { task ->
if (!isAppModuJavale.toBoolean()) {
// 不是Application方法不处理
return
}
// 在任务实施的时分,匹配实施assemble(途径)Release的打APK使产品批号是生产日期吗命
Matcgradle是什么her m = p.matcher(task.name)
if (!m.find()) {
rejava工作培训班turn
}android体系下载
// 打release包task完gradle教程结之后进行资源的整合以及jar包去指定class文件,并且生成aar包
task.doLast {
String flagradle homevorName = task.name.minus("assemble").minus("Release").toLowerCaseandroid下载()
if (flavorName.isEmpty())
return
path = projectDir.toString() + File.separator + 'robustjar'+ File.separator + flavorName + File.separator + 'release'
println '-- hookAssembleAndCopyRes 监听task:' + task.nam产品密钥在哪里能找到e + " flavorName: " + flavorName
delete {
// 删去上次生成的文件目录,目录为 ${path}
delejava怎样读te projectDir.tojava模拟器String() + File.separator + 'robustjar' + File.separator + flavorName + File.separatorandroid/yunos + "release"
}
// 打包所需资源地点javascript的父目录, sdkbuildintermediates
String intermediatesPath = buildDir.android/yunostoString() + File.separa开源节流打一个字tor + "intermediates"
// gradle-3.0.java模拟器0 & robust-0.4开源人脸辨认认聚顶科技在线.71对应的途径为 sdkbjava难学吗uildintermediatestransformsp开源人脸辨认认聚顶科技在线roguardrelease.jar
String jarDirName = (isProguard.toBoolean() ? "proguard" : "robust") + File.separator + flavorName
String robustJ开源节流打一个字arPath = intermediatesPath +gradle是什么 File.separator + "transforms" + File.separator + jagradle打包rDirName + File.separator + "rele开源是什么意思ase" + File.separator + "0.jar"
// gradle-2.3.3 & robust-0.4.7对应的途径为 sdkbuildintermedia产品设计专业testransformsproguardreleas产品营销策划ejars31fmai开源矿工n.jar
// String robustJarPath = intermediatesPath + File.separator + "transforms" + File.separator + "proguard" + File.separator + "release" + File.separator + "jars" + Fi产品批号是生产日期吗le.separator + "3" + File.separator + "1f" + File.separator + "main.ja产品运营首要做什么r"
// 资源文件的途径,sdkbuildintermediatesassetsrelease
S产品设计专业tring assetsPath = intermediatesPath + File.separator + "assets" + File.separator + flavorName + File.separator + "release"
// 依托本地jar包途径,sdkbuigradle homeldintermediatesjniLibsrelease
String libsPath = intermediatesPath + File.separator + "jniLibs" + File.separator + flavorName + File.separator + "release"
// res资源文件的途径,sdkbuildintermediatesresmergedrelease,经测试发现此目录下生成的.9图片会失效,因而放置,换其他方法处理
// String resPath = intermediatesPgradle下载ath + File.s开源软件eparator + "res" + File.separator + "mejava工作培训班rged" + Figradle homele.separator + "release"
// 由于上述问题,直接用项目的res途径 sdksrcmainres ,因而第三方依托的资源文件无法整合,可是我是依据生成只包括自身代码的jar包和资源,其gradle教程他依托宿主其他再依托的计划,所以能够这样处理
String regradle是什么sPath = prgradle教程ojectDir.toString() + File.sep产品运营arator + "src" + File.sejava怎样读parator + "main" + File.separator + "res"
// 资源id途径,sdjava难学吗kbuildintermediatessymbolsrelease
String resIdPath = intermediatesPath + File.separator + "symbols" + File.sandroid手机eparator + flavorName + File.separator + "release"
// 清单文件途径,sdkbuildintermediatesmanifestsfullrelease,由所以生成的application的清产品单文件,因而下面还会做删去组件声明的处理
String man开源人脸辨认认聚顶科技在线ifestPath = intermedi产品运营首要做什么atesPath + File.separator + "manifests" + File.separator + "full" + File.separator + flavorName + File.separator + "release"
// 整合上述文件后的政策途径,${path}origin
String destination = pathjava难学吗 + File.s产品运营eparator + 'origradle是什么gin'
// 貌似aidl的文件夹没啥用,打包会依据例如Ggradle翻译:sms-hotfixSmsParsingForRcs-Librarylibrarygradle版别srcmainaidlcomcmicIgradle装备MyAidlInterface.aidl的界说开源代码生成com.cgradle装备mic.IMyAidlInterface到jar包里边,因而aidl只是是空文件夹
// String aidlPath = buildDir.toString() +android的drawable类 File.separator + "generated" + File.separator + "source" + File.separator + "产品设计aidl" + File.separator + "release"
printlgradle翻译n '-- robujava游戏stJavaJarPath ' + robustJarPath
File file = file(robusAndroidtJarPath)
if (!file.exists()) {
println '--【产品设计专业告警】robust插桩jar包不存在,结束'
return
}
println '--开始仿制robust插桩jar包'
copy {
// 仿制到assets目录
from(assetsPath) {
into 'assets'
}
// .so文件仿制到jnijava工程师目录
f产品运营rom(libsPath) {
into 'jni'
include '**/*/*.so'
}
// 资源文件仿制到r产品es目录
from(resPath) {
// 清扫MainActivity加载的布局文件,由于输出的是jar包,加MainActivity只是是为了能让打apk包任务实施
//exclude '/layout/activity_main.xml'
exclude {
// 清扫空文件夹
it.isDirectory() &&java是什么意思 iandroid手机t.getFile().listFiles().length == 0
}
into 'r产品运营es'
}
// aidl的文件夹没啥用,不处理
// from(aidlPath) {
// into 'aidandroid下载安装l'
// }
// 仿制此目录下资源id文件 R.txt
from res开源人脸辨认认聚顶科技在线IdPath
// 仿制到目录 ${path}origin
into destination
}
// 补丁生成需求的mapping.txt和methodsMap.robust文件
copy {
/android下载/ 混杂mapping文件的途径,sdkbuildoutputsmappgradle版别ingreleasemapping.txt
from(buildDir.toString() + File.separator + 'outputs' + File.separator + 'mapping' + File产品运营首要做什么.separator + flavorName + File.separator +android手机 'release') {
include 'mapping.txt'
}
// 仿制到目录 ${path}
into path
}
copy {
// robust生成的methodsMap文件途径,sdkbuildoutputsrobustmethodsMap.robust
from(buildDir.toString() + File.separator + 'outputs' + File.separator + 'robu开源节流打一个字st') {
incl开源节流ude 'methodsMap.robu开源我国st'
}
// 仿制到目录 ${path}
into path
}
// 若产品运营首要做什么不存在aidl目录,创立aidl空目开源节流录
createDir(destination + File.separator + "aidl")
// 同上
createDir(destination + File.separator + "assets")
// 同上
creandroid的drawable类ateDir(destination + File.separator + "jni")
// 同上
createDir(destination + File.separ开源软件ator +gradle是什么 "libs")
// 同上
createDir(destgradle下载ination + File.separator + "res")
//将清单文件application节点的内容和activity节点的内容替换,将清单文件provandroid是什么手机牌子ider节点的内容和meta-data节点的内容替换
d产品密钥ef oldStr = ["<application[sS]*?>", "<activit开源矿工y[sS]*?</activity>", "<provider[sS]*?(</provider>|/>)", "<meta-data[sS]*?(</meta-data>|/>)android平板电脑价格"]
def newStr = ["<applicjava游戏ationn" + " android:allowBackup="false"n" + " android:supportsRtl="true">", "", "", ""]
tryjava面试题 {
//处理 sdkbuildingradle hometermediatesmanifestsfullreleaseAndroidManifest.xml
String strBuffer = fileRegradle下载慢解决方法ader(manifestPath + File.separator + "AndroidManifest.xml", oldStr, newStr)
//输出至 ${path}originAndandroid下载roidManifestgradle home.xml
fileWrite(destination + File.separator + "AndroidManifest.xml", strBuffer)
} catch (FileNotFoundException e) {
e.printStackTrace()
}
println '--输出robust插桩jar包成功!'
println 'task name : ' + jarTaskName + "_" + flavorName
createJarTask('jar_' + 'sdk_hotfix' + "_" + flavorN产品质量法ame, path, sdkPackageName, flavorjava难学吗Name)
//产品密钥 实施打jar包的task,这里会做原jar包的过滤android体系处理,只保存我们需求的代码
createAarTask(开源'aar_' + 'sdk_hotfix' + "_" + flavorNajavascriptme, path)
//delete project.buildDir
}
}
}
private Task createAarTask(taskName, path) {产品质量法
tasks.create(name: taskName, type: Zip) {
// aar包输出途径为 ${path}aar
File destDir = file(path + File.separator + 'android/yunosaar')
// aar包命名为 library-rel产品运营首要做什么ease.aar产品密钥在哪里能找到
archi产品批号是生产日期吗veName 'library-release.android体系aar'
// 源途径为 ${path}origin
from path + Filandroid手机e.separator + 'origin'
/gradle home/ 设置紧缩后输出的途径
destinationDir destDir
println '--创立紧缩aar包Task结束'
}.execute()
}
private Task createJarTask(taskName开源我国, path, sdkPackageName, flavorName) {
tasks.crea产品批号是生产日期吗te(name: taskName, type: Jar) {
// jar包命名为classes.开源是什么意思jar
bagradle发音seName 'classes'
String intermgradle homeediatesPa开源是什么意思th = buildDir.toString() + File.separator + "intermediategradle翻译s"
// gradle-3.gradle打包0.0 & robust-0.4.71对应的途径为 sdkbuildintermediatestransformsproguardrelease.jar
String jarDi产品运营rNa产品营销策划me = (isProguard.toBoolean() ? "proguar开源矿工d" : "robust") + File.separator + flavorName
String robust开源人脸辨认认聚顶科技在线JarPath = intermediatesPath + File.separator + "android平板电脑价格transforms" + File.separatojava模拟器r + jarDirName + File.separator + "release" + File.separator + "0.jar"
def zipFile = new File(robustJarPath)
// 将jar包解压
FileTree jarTree = zipTree(zipFile)
from jarTree
// jar包输出途径为 ${path}origin
File destDir = fiandroid下载安装le(path + File.separator + 'origin')
// 设置输出途径
s开源etgradle发音Dest开源节流打一个字inationDir degradle打包stDir
include {
// 只打包我们需gradle下载求的类
it.path.startsWith(sdkPacandroid体系ka产品质量法geName)
}
//
/产品密钥/ exclud产品运营首要做什么e {
// // println "实施清扫:" + it.path
/android下载安装/ // 清扫R相关class文件,清扫MainActivity.clasjava是什么意思s文件
// it.patandroid/yunosh.startsWi开源是什么意思th(sdkPackageName + '/R$') ||javascript it.path.startsWith(sdkPackageName + '/R.class') || it.path.startsWith(sdkPackageName + '/MainActivity.class')
// }
println '--创立紧缩jar包Task结束--' + taskName
}.execute()
}
/产品设计/读取文件并替换字符串
static def fileReader(path, oldStr,开源阅读 newStr) {
def readerString = new File(path).getText('UTF-8')
for (int i = 0; i < oldStr.size(); i++) {
randroid体系下载eaderString = readerString.repla产品司理ceFirst(oljava怎样读dStr[i], newStr[i])
}
return readerString
}
//写文件
static def fileWrite(path, stringBuffer) {
new File(path).withWriter('UTF-8'javascript) {
with开源是什么意思in ->
within.append(stringBuffer)
}
}
/java游戏/ 创立目录
static def createDir(String destDirName) {
File dir = new File(destDirName)
if (dir.exists()) {
println '--政策目录已存在!无需创立'
return false
}
if (!destDirName.endsWith(File.separator)) {
destDirNandroid什么意思ajavascriptme = destDirName + File.separator
}
if (dir.mkdiAndroidrs()) {
println '--创立目录成功!' + destDirName
return true
} e开源lse {
pgradle下载慢解决方法rintln '--创立目录失利!android是什么手机牌子'
return false
}
}
//项目uploadArchives时,必定会调用到bundleRelease Task,hook产品设计 bundle* Task 用于在上传maven前把本地打包的aar改为插桩后的aar
private void hookBundle(path) {
tasks.wh产品质量法enTask开源节流打一个字Added { task -开源节流&ggradle下载慢解决方法t;
if (isAppModule.toBoolean()) {
/Android/ 是Appljava模拟器ication方法不处理,由于Application方法没有bundleRelease Task
return
}
if (!'bund开源众包leRelease'.equals(task.name)开源节流) {
retu开源节流是什么意思是什么rn
}
task.doFirst {
println '--hook bundleRelease!'
forEachInputs(it,gradle path)
}
}
}
private void forEachInputs开源节流是什么意思是什么(Task it, String path) {
String jarName = 'classes.jar'
it产品密钥在哪里能找到.inputs.files.each { input ->
if (input.absolutePath.indexOf(jarName) != -1) {
String jarInputPath = input.absolutePath.substring(0, input.absolutePath.lastIndexOf(File.separator) + 1)
copy {
// 源途径为 ${path}origin
from(path + File.separator + 'origin') {
include jarName
}
into jarInputPath
}
}
}
}