分析 1.build.gradle
1 classpath 'com.android.boost.easyconfig:easyconfig:2.2.10'
2.easyconfig-2.2.10.pom
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 <?xml version="1.0" encoding="UTF-8" ?> <project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" > <modelVersion>4.0 .0 </modelVersion> <groupId>com.android.boost.easyconfig</groupId> <artifactId>easyconfig</artifactId> <version>2.2 .10 </version> <dependencies> <dependency> <groupId>com.android.boost.dependency</groupId> <artifactId>gradle_plugin</artifactId> <version>3.4 .11 </version> <scope>compile</scope> <exclusions> <exclusion> <artifactId>commons-io</artifactId> <groupId>commons-io</groupId> </exclusion> <exclusion> <artifactId>guava</artifactId> <groupId>com.google.guava</groupId> </exclusion> </exclusions> </dependency> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>19.0 </version> <scope>compile</scope> </dependency> </dependencies> </project>
3.gradle_plugin-3.4.11.jar
4.amap_android/scm/miniapp/ariver.gradle
1 apply plugin: 'com.alipay.apollo.baseline.config'
5.portal task依赖中正好也看到了有MPaaSAARHookerTask
寻找这个task的思路?
反推法,从第五步开始,我们看到了MPaaSAARHookerTask, 如果想知道这个task做了什么,我们应该从项目所有的classpath依赖中去查找,通过简单的分析’paas’,’easy’,’config’ ,再通过所有打印出的所有classpath,估计应该在com.android.boost.easyconfig:easyconfig:2.2.10这个库中,但是打开这个库之后,并没有发现有MPaaSAARHookerTask这个类,于是又在pom文件发现easyconfig依赖gradle_plugin,最终在gradle_plugin中找到了这个Task
task:https://yuque.antfin.com/xiaobao.spf/ad2gcp/rvlk3e classpath: https://yuque.antfin.com/xiaobao.spf/ad2gcp/yizp1w
解析 DSL语法转化为class,反编译后的代码,阅读上比较费劲
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public Object handleAARConfig (Project project, BaseVariant variant) { CallSite[] $getCallSiteArray = $getCallSiteArray(); if (!BytecodeInterface8.isOrigZ() || __$stMC || BytecodeInterface8.disabledStandardMetaClass()) { if (ScriptBytecodeAdapter.compareEqual(project, null ) || ScriptBytecodeAdapter.compareEqual(variant, null )) { return null ; } } else { if (ScriptBytecodeAdapter.compareEqual(project, null ) || ScriptBytecodeAdapter.compareEqual(variant, null )) { return null ; } } Object applicationId = $getCallSiteArray[72 ].callGetProperty(variant); Object packageName = $getCallSiteArray[73 ].callStatic(MPaaSAARPlugin.class, variant); File outputDir = (File) ScriptBytecodeAdapter.castToType($getCallSiteArray[74 ].call(project, new GStringImpl(new Object[]{$getCallSiteArray[75 ].callGetProperty(project), $getCallSiteArray[76 ].callGetProperty(variant)}, new String[]{"" , "/generated/source/aar_hook/" , "" })), File.class); MPaaSAARHookerTask task = (MPaaSAARHookerTask) ScriptBytecodeAdapter.castToType($getCallSiteArray[77 ].call($getCallSiteArray[78 ].callGetProperty(project), new GStringImpl(new Object[]{$getCallSiteArray[79 ].call($getCallSiteArray[80 ].callGetProperty(variant))}, new String[]{"mpaas" , "AARHookerTask" }), MPaaSAARHookerTask.class), MPaaSAARHookerTask.class); $getCallSiteArray[81 ].call(task, applicationId); $getCallSiteArray[82 ].call(task, packageName); $getCallSiteArray[83 ].call(task, $getCallSiteArray[84 ].callGetProperty(outputDir)); return $getCallSiteArray[85 ].call(variant, task, outputDir); }
先找到了MPaaSAARHookerTask,然后查看handleAARConfig的调用,在strArr[70]数组中发现了这个方法
1 2 3 4 5 6 7 strArr[70 ] = "handleAARConfig" ; public Object handleVariant (Project project, Object variant) { CallSite[] $getCallSiteArray = $getCallSiteArray(); $getCallSiteArray[70 ].callCurrent(this , project, variant); return $getCallSiteArray[71 ].callCurrent(this , variant, project); }
继续查找发现handleVariant中又调用了handleAARConfig,再往上查看就是Plugin的apply中了,这里忽略,进行分析MPaaSAARHookerTask,handleAARConfig方法中有很多的getCallSiteArray数组,数组索引为72-85
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 strArr[71 ] = "handleMpaasConfig" ; strArr[72 ] = "applicationId" ; strArr[73 ] = "getPackageName" ; strArr[74 ] = "file" ; strArr[75 ] = "buildDir" ; strArr[76 ] = "dirName" ; strArr[77 ] = "create" ; strArr[78 ] = "tasks" ; strArr[79 ] = "capitalize" ; strArr[80 ] = "name" ; strArr[81 ] = "setApplicationId" ; strArr[82 ] = "setPackageName" ; strArr[83 ] = "setOutputFilePath" ; strArr[84 ] = "absolutePath" ; strArr[85 ] = "registerJavaGeneratingTask" ;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 open fun registerJavaGeneratingTask ( task: Task, generatedSourceFolders: Collection<File> ) { @Suppress("DEPRECATION") taskContainer.sourceGenTask.dependsOn(task) val fileTrees = extraGeneratedSourceFileTrees ?: mutableListOf<ConfigurableFileTree>().also { extraGeneratedSourceFileTrees = it } for (f in generatedSourceFolders) { val fileTree = services.fileTree(f).builtBy(task) fileTrees.add(fileTree) } addJavaSourceFoldersToModel(generatedSourceFolders) }
分析registerJavaGeneratingTask,得出在generatorVariantNameSourcesTask会依赖MPaaSAARHookerTask
MPaaSAARHookerTask
1 2 3 4 5 6 7 8 @TaskAction public void executeTask () { try { new HookerJavaGenerator().generate(this .outputFilePath, this .packageName); } catch (IOException e) { e.printStackTrace(); } }
HookerJavaGenerator
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 public class HookerJavaGenerator { private static final String TAG = HookerJavaGenerator.class.getName(); private final String className = "FinalRInit" ; private final String packageName = "com.mpaas.project.aar.convert.converter" ; public static void main (String[] args) throws IOException { new HookerJavaGenerator().generate("/Users/gezihua/mpaas_code/dependcychecker/java-demo/src/main/java" , "com.alipay.iap.android.webapp" ); } public void generate (String outFilePath, String RJavaPackage) throws IOException { if (StringUtils.isEmpty(outFilePath)) { System.err.println(TAG + "generate outFilePath is null" ); } else if (StringUtils.isEmpty(RJavaPackage)) { System.err.println(TAG + "generate RJavaPackage is null" ); } else { File outFile = Paths.get(outFilePath, "com.mpaas.project.aar.convert.converter" .replaceAll("\\." , "/" ) + "/FinalRInit.java" ).toFile(); if (!outFile.getParentFile().exists()) { outFile.getParentFile().mkdirs(); } if (!outFile.exists()) { outFile.createNewFile(); } System.out.println(outFile.getAbsolutePath()); new JavaWriter(new OutputStreamWriter(new FileOutputStream(outFile))).emitPackage("com.mpaas.project.aar.convert.converter" ).beginType("com.mpaas.project.aar.convert.converter.FinalRInit" , "class" , EnumSet.of(Modifier.PUBLIC, Modifier.FINAL)).emitJavadoc("com.mpaas.project.aar.convert init with your R class" , new Object[0 ]).beginMethod("Class" , "getRClass" , EnumSet.of(Modifier.PUBLIC, Modifier.STATIC), new String[0 ]).emitStatement(String.format("return %s.R.class" , RJavaPackage), new Object[0 ]).endMethod().endType().close(); } } }
通过分析,得知MPaaSAARHookerTask 主要是用于生成一个FinalRInit.java
1 2 3 4 5 6 7 8 public final class FinalRInit { public static Class getRClass () { return com.autonavi.minimap.R.class; } }
调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public class FinalR { ... public static Class invokeFinalRInit () { try { return (Class) Class.forName("com.mpaas.project.aar.convert.converter.FinalRInit" ).getMethod("getRClass" , new Class[0 ]).invoke(null , new Object[0 ]); } catch (Exception e) { e.printStackTrace(); return null ; } } ... public static int invokeRInnerClassIntWithOutException (String className, String valueName) { try { return invokeRInnerClassInt(className, valueName); } catch (Exception e) { e.printStackTrace(); return -1 ; } } ... }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 package com.alibaba.ailabs.tg.sdk.test;import com.alipay.mobile.common.share.widget.ResUtils;import com.alipay.mobile.nebulax.resource.storage.dbbean.AromeRecentAppBean;import com.mpaas.project.aar.convert.converter.FinalR;public final class R { public static final class drawable { public static final int aomp_bg_indicator_default = FinalR.invokeRInnerClassIntWithOutException(ResUtils.DRAWABLE, "aomp_bg_indicator_default" ); public static final int aomp_bg_indicator_selected = FinalR.invokeRInnerClassIntWithOutException(ResUtils.DRAWABLE, "aomp_bg_indicator_selected" ); public static final int aomp_bg_indicator_selector = FinalR.invokeRInnerClassIntWithOutException(ResUtils.DRAWABLE, "aomp_bg_indicator_selector" ); public static final int aomp_btn_bg_cancel = FinalR.invokeRInnerClassIntWithOutException(ResUtils.DRAWABLE, "aomp_btn_bg_cancel" ); public static final int aomp_dialog_bg_auth = FinalR.invokeRInnerClassIntWithOutException(ResUtils.DRAWABLE, "aomp_dialog_bg_auth" ); public static final int aomp_ic_auth_fail = FinalR.invokeRInnerClassIntWithOutException(ResUtils.DRAWABLE, "aomp_ic_auth_fail" ); public static final int aomp_ic_auth_success = FinalR.invokeRInnerClassIntWithOutException(ResUtils.DRAWABLE, "aomp_ic_auth_success" ); } ... }
最终发现是在子项目的 R文件 中通过反射的方式调用 portal(com.autonavi.minimap.R.class) 中 R文件
子项目中引用R文件的类,类中指定了R.class,而非使用高德中的R,所以指定的R文件中需要建立映射到高德中的R文件。