文章目录

  • Task24 transformClassesWithDexBuilderForDebug
    • 1.input/ouput
    • 2. 核心类(DexArchiveBuilderTransform,TransformTask)
      • 2.1 processJarInput
      • 2.2. convertToDexArchive
      • 2.3 launchProcessing
    • 3. 梳理下总体调用链路
  • Task25 transformClassesWithMultidexlistForDebug
    • 1. input/ouput
    • 2. 核心类(D8MainDexListTransform)
  • Task26 transformDexArchiveWithDexMergerForDebug
    • 1. input/ouput
    • 2. 核心类(DexMergerTransform)
  • Task 27 mergeDebugJniLibFolders
    • 1. input/output
    • 2. 核心类(MergeJniLibFoldersConfigAction, MergeSourceSetFolders)
  • Task28 transformNativeLibsWithMergeJniLibsForDebug
    • 1. input/output
    • 2. 核心类(MergeJavaResourcesTransform)
    • 3. transform

Task24 transformClassesWithDexBuilderForDebug

1.input/ouput

taskName:transformClassesWithDexBuilderForDebug
input:/Users/apple/.gradle/caches/transforms-1/files-1.1/adapters-3.2.0.aar/49b3d7e4ab68d92f056ea8f56b33e9fb/jars/classes.jar
input:/Users/apple/.gradle/caches/transforms-1/files-1.1/library-3.2.0.aar/818ffb3fe5dc5eeb6b4e51c93615b7fb/jars/classes.jar
input:/Users/apple/.gradle/caches/modules-2/files-2.1/com.android.databinding/baseLibrary/3.2.0/fb5f8492c36231104cd86feaefa723291504c0a6/baseLibrary-3.2.0.jar
input:/Users/apple/.gradle/caches/transforms-1/files-1.1/appcompat-v7-26.1.0.aar/2774ea4f1cf1e83a6ad8e8d3c8b463b6/jars/classes.jar
input:/Users/apple/.gradle/caches/transforms-1/files-1.1/constraint-layout-1.1.3.aar/f43c0ba95b6494825ed940fc4f04662b/jars/classes.jar
input:/Users/apple/.gradle/caches/transforms-1/files-1.1/support-v4-26.1.0.aar/9ac5f97e8ccb24c52b7cbb6202c12ad0/jars/classes.jar
input:/Users/apple/.gradle/caches/transforms-1/files-1.1/support-fragment-26.1.0.aar/7e6a4ce6591d722d47aafc36d980f8b4/jars/classes.jar
input:/Users/apple/.gradle/caches/transforms-1/files-1.1/support-core-utils-26.1.0.aar/4c474caa9ac1f01c4936bd96905ecacd/jars/classes.jar
input:/Users/apple/.gradle/caches/transforms-1/files-1.1/animated-vector-drawable-26.1.0.aar/559112320064089dfaf6780e71d5b44f/jars/classes.jar
input:/Users/apple/.gradle/caches/transforms-1/files-1.1/support-vector-drawable-26.1.0.aar/c2c3ad4abfd49316f6769b8238b0f010/jars/classes.jar
input:/Users/apple/.gradle/caches/transforms-1/files-1.1/support-media-compat-26.1.0.aar/53ab5ad72634f3497309a8788f3ca200/jars/classes.jar
input:/Users/apple/.gradle/caches/transforms-1/files-1.1/support-core-ui-26.1.0.aar/868eaa7e0c620cd85d72ad4f340e8bb1/jars/classes.jar
input:/Users/apple/.gradle/caches/transforms-1/files-1.1/support-compat-26.1.0.aar/4ec3c1c46e5bad9ac3b91f45a2afec3e/jars/classes.jar
input:/Users/apple/.gradle/caches/transforms-1/files-1.1/runtime-1.0.3.aar/5765c0929bc6bc40d70d6fc25f402f42/jars/classes.jar
input:/Users/apple/.gradle/caches/modules-2/files-2.1/android.arch.lifecycle/common/1.0.3/7d7f60c4783872861222166f6164215f8951c7b1/common-1.0.3.jar
input:/Users/apple/.gradle/caches/modules-2/files-2.1/android.arch.core/common/1.0.0/a2d487452376193fc8c103dd2b9bd5f2b1b44563/common-1.0.0.jar
input:/Users/apple/.gradle/caches/modules-2/files-2.1/com.android.support/support-annotations/26.1.0/814258103cf26a15fcc26ecce35f5b7d24b73f8/support-annotations-26.1.0.jar
input:/Users/apple/.gradle/caches/modules-2/files-2.1/com.android.support.constraint/constraint-layout-solver/1.1.3/bde0667d7414c16ed62d3cfe993cff7f9d732373/constraint-layout-solver-1.1.3.jar
input:/Users/apple/work/project/AndroidGradleTaskDemo/app/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/android/support/coreutils/R.class
input:/Users/apple/work/project/AndroidGradleTaskDemo/app/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/android/support/coreutils/R$bool.class
input:/Users/apple/work/project/AndroidGradleTaskDemo/app/build/intermediates/javac/debug/compileDebugJavaWithJavac/cl/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/android/databinding/layouts/DataBindingInfo.class
input:/Users/apple/work/project/AndroidGradleTaskDemo/app/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/android/databinding/DataBindingComponent.class
input:/Users/apple/work/project/AndroidGradleTaskDemo/app/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/gradle/task/demo/R.class
input:/Users/apple/work/project/AndroidGradleTaskDemo/app/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/gradle/task/demo/MainActivity.class
input:/Users/apple/work/project/AndroidGradleTaskDemo/app/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/gradle/task/demo/R$bool.class
input:/Users/apple/work/project/AndroidGradleTaskDemo/app/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/gradle/task/demo/R$id.class
input:/Users/apple/work/project/AndroidGradleTaskDemo/app/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/gradle/task/demo/IHelloAidlInterface$Stub.class
input:/Users/apple/work/project/AndroidGradleTaskDemo/app/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/gradle/task/demo/R$mipmap.class
input:/Users/apple/work/project/AndroidGradleTaskDemo/app/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/gradle/task/demo/DataBinderMapperImpl.class
input:/Users/apple/work/project/AndroidGradleTaskDemo/app/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/gradle/task/demo/DataBinderMapperImpl$InnerBrLookup.class
省略...
=========================================================
output:/Users/apple/work/project/AndroidGradleTaskDemo/app/build/intermediates/transforms/dexBuilder/debug

从日志不难发现,输入数据格式包含二类**.jar和javac编译后.class**文件,该任务主要做了二件事情

  1. 将每个class文件通过D8编译器(AS3.0新增的D8默认开启)编译成dex文件
  2. 对于jar,则将其中的class编译成dex再打包成jar
    关于D8功效果描述参加官方描述https://developer.android.com/studio/command-line/d8?hl=zh-cn

2. 核心类(DexArchiveBuilderTransform,TransformTask)

/*** Transform that converts CLASS files to dex archives, {@link* com.android.builder.dexing.DexArchive}. This will consume {@link TransformManager#CONTENT_CLASS},* and for each of the inputs, corresponding dex archive will be produced.** <p>This transform is incremental, only changed streams will be converted again. Additionally, if* an input stream is able to provide a list of individual files that were changed, only those files* will be processed. Their corresponding dex archives will be updated.*/
public class DexArchiveBuilderTransform extends Transform {@Overridepublic void transform(@NonNull TransformInvocation transformInvocation)throws TransformException, IOException, InterruptedException {List<DexArchiveBuilderCacheHandler.CacheableItem> cacheableItems = new ArrayList<>();....for (TransformInput input : transformInvocation.getInputs()) {for (DirectoryInput dirInput : input.getDirectoryInputs()) {logger.verbose("Dir input %s", dirInput.getFile().toString());// 1. 扫描Dir目录对该目录下的所有class文件进行D8编译处理生产dex文件convertToDexArchive(transformInvocation.getContext(),dirInput,outputProvider,isIncremental,bootclasspathServiceKey,classpathServiceKey,additionalPaths);}for (JarInput jarInput : input.getJarInputs()) {logger.verbose("Jar input %s", jarInput.getFile().toString());// 2. 对项目中依赖的jar进行处理D8DesugaringCacheInfo cacheInfo =getD8DesugaringCacheInfo(desugarIncrementalTransformHelper,bootclasspath,classpath,jarInput);List<File> dexArchives =processJarInput(transformInvocation.getContext(),isIncremental,jarInput,outputProvider,bootclasspathServiceKey,classpathServiceKey,additionalPaths,cacheInfo);if (cacheInfo != D8DesugaringCacheInfo.DONT_CACHE && !dexArchives.isEmpty()) {cacheableItems.add(new DexArchiveBuilderCacheHandler.CacheableItem(jarInput,dexArchives,cacheInfo.orderedD8DesugaringDependencies));}}}// all work items have been submitted, now wait for completion.if (useGradleWorkers) {transformInvocation.getContext().getWorkerExecutor().await();} else {executor.waitForTasksWithQuickFail(true);}// if we are in incremental mode, delete all removed files.if (transformInvocation.isIncremental()) {for (TransformInput transformInput : transformInvocation.getInputs()) {removeDeletedEntries(outputProvider, transformInput);}}// 缓存对jar进行dex后的文件,存储到用户级别(/Users/${username}/.android/build-cache/{gradle_plugin_version})// 方便后续直接复用// and finally populate the caches.if (!cacheableItems.isEmpty()) {cacheHandler.populateCache(cacheableItems);}}
}

先看jar;如果是jar会调用processJarInput方法

2.1 processJarInput

@NonNull
private List<File> processJarInput(@NonNull Context context,boolean isIncremental,@NonNull JarInput jarInput,@NonNull TransformOutputProvider transformOutputProvider,@NonNull ClasspathServiceKey bootclasspath,@NonNull ClasspathServiceKey classpath,@NonNull Set<File> additionalPaths,@NonNull D8DesugaringCacheInfo cacheInfo)throws Exception {if (!isIncremental || additionalPaths.contains(jarInput.getFile())) {Preconditions.checkState(jarInput.getFile().exists(),"File %s does not exist, yet it is reported as input. Try \n"+ "cleaning the build directory.",jarInput.getFile().toString());return convertJarToDexArchive(context,jarInput,transformOutputProvider,bootclasspath,classpath,cacheInfo);} else if (jarInput.getStatus() != Status.NOTCHANGED) {// 处理增量流程,可以先忽略// delete all preDex jars if they exists....}return ImmutableList.of();
}private List<File> convertJarToDexArchive(@NonNull Context context,@NonNull JarInput toConvert,@NonNull TransformOutputProvider transformOutputProvider,@NonNull ClasspathServiceKey bootclasspath,@NonNull ClasspathServiceKey classpath,@NonNull D8DesugaringCacheInfo cacheInfo)throws Exception {if (cacheInfo != D8DesugaringCacheInfo.DONT_CACHE) {File cachedVersion =cacheHandler.getCachedVersionIfPresent(toConvert, cacheInfo.orderedD8DesugaringDependencies);// 1. 判断本地缓存(用户级别)是否有jar,如果有直接copy,复用if (cachedVersion != null) {File outputFile = getOutputForJar(transformOutputProvider, toConvert, null);Files.copy(cachedVersion.toPath(),outputFile.toPath(),StandardCopyOption.REPLACE_EXISTING);// no need to try to cache an already cached version.return ImmutableList.of();}}// 2. 没有缓存走该方法return convertToDexArchive(context,toConvert,transformOutputProvider,false,bootclasspath,classpath,ImmutableSet.of());}

可以看到无论是jar还是class他们最终都会调用同一个方法convertToDexArchive,我们看看它到底做了什么

2.2. convertToDexArchive

private List<File> convertToDexArchive(@NonNull Context context,@NonNull QualifiedContent input,@NonNull TransformOutputProvider outputProvider,boolean isIncremental,@NonNull ClasspathServiceKey bootClasspath,@NonNull ClasspathServiceKey classpath,@NonNull Set<File> additionalPaths) {logger.verbose("Dexing %s", input.getFile().getAbsolutePath());ImmutableList.Builder<File> dexArchives = ImmutableList.builder();for (int bucketId = 0; bucketId < numberOfBuckets; bucketId++) {File preDexOutputFile;//1. 如果是输入为dir,也即是javac编译保存class文件目录;生成存储dex目录if (input instanceof DirectoryInput) {preDexOutputFile =getOutputForDir(outputProvider, (DirectoryInput) input, bucketId);FileUtils.mkdirs(preDexOutputFile);} else {//2. 否则是jar,则构建一个输出${INT}.jar文件preDexOutputFile = getOutputForJar(outputProvider, (JarInput) input, bucketId);}dexArchives.add(preDexOutputFile);DexConversionParameters parameters =new DexConversionParameters(input,bootClasspath,classpath,preDexOutputFile,numberOfBuckets,bucketId,minSdkVersion,dexOptions.getAdditionalParameters(),inBufferSize,outBufferSize,dexer,isDebuggable,isIncremental,java8LangSupportType,additionalPaths,new SerializableMessageReceiver(messageReceiver),isInstantRun);if (useGradleWorkers) {context.getWorkerExecutor().submit(DexConversionWorkAction.class,configuration -> {configuration.setIsolationMode(IsolationMode.NONE);configuration.setParams(parameters);});} else {executor.execute(() -> {ProcessOutputHandler outputHandler =new ParsingProcessOutputHandler(new ToolOutputParser(new DexParser(), Message.Kind.ERROR, logger),new ToolOutputParser(new DexParser(), logger),messageReceiver);ProcessOutput output = null;try (Closeable ignored = output = outputHandler.createOutput()) {// 无论是jar还是class最终都会走该方法launchProcessing(parameters,output.getStandardOutput(),output.getErrorOutput(),messageReceiver);} finally {if (output != null) {try {outputHandler.handleOutput(output);} catch (ProcessException e) {// ignore this one}}}return null;});}}return dexArchives.build();}

可以看到无论是class还是jar最后都会执行launchProcessing方法,关键部分如下

2.3 launchProcessing

private static void launchProcessing(@NonNull DexConversionParameters dexConversionParameters,@NonNull OutputStream outStream,@NonNull OutputStream errStream,@NonNull MessageReceiver receiver)throws IOException, URISyntaxException {...logger.verbose("Dexing '" + inputPath + "' to '" + dexConversionParameters.output + "'");// 1, 此处根据inputPath判断,如果是jar返回JarClassFileInput类型,否则视为DirectoryBasedClassFileInputtry (ClassFileInput input = ClassFileInputs.fromPath(inputPath);Stream<ClassFileEntry> entries = input.entries(bucketFilter)) {// 2. 核心代码,此处调用D8DexArchiveBuilder类将jar或class文件进行编译dexArchiveBuilder.convert(entries,Paths.get(new URI(dexConversionParameters.output)),dexConversionParameters.isDirectoryBased());} catch (DexArchiveBuilderException ex) {throw new DexArchiveBuilderException("Failed to process " + inputPath.toString(), ex);}}
// D8DexArchiveBuilder.java
public void convert(@NonNull Stream<ClassFileEntry> input, @NonNull Path output, boolean isIncremental)throws DexArchiveBuilderException {D8DiagnosticsHandler d8DiagnosticsHandler = new InterceptingDiagnosticsHandler();try {D8Command.Builder builder = D8Command.builder(d8DiagnosticsHandler);AtomicInteger entryCount = new AtomicInteger();input.forEach(entry -> {//1. 读取每个class文件存储到builder,为后续D8编译器服务builder.addClassProgramData(readAllBytes(entry), D8DiagnosticsHandler.getOrigin(entry));entryCount.incrementAndGet();});if (entryCount.get() == 0) {// nothing to do here, just returnreturn;}OutputMode outputMode =isIncremental ? OutputMode.DexFilePerClassFile : OutputMode.DexIndexed;builder.setMode(compilationMode).setMinApiLevel(minSdkVersion).setIntermediate(true).setOutput(output, outputMode);if (desugaring) {builder.addLibraryResourceProvider(bootClasspath.getOrderedProvider());builder.addClasspathResourceProvider(classpath.getOrderedProvider());} else {builder.setDisableDesugaring(true);}// 2. D8编译器进行编译处理D8.run(builder.build(), MoreExecutors.newDirectExecutorService());} catch (Throwable e) {throw getExceptionToRethrow(e, d8DiagnosticsHandler);}}

3. 梳理下总体调用链路

#mermaid-svg-nSq3ktPapsVygrng .label{font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family);fill:#333;color:#333}#mermaid-svg-nSq3ktPapsVygrng .label text{fill:#333}#mermaid-svg-nSq3ktPapsVygrng .node rect,#mermaid-svg-nSq3ktPapsVygrng .node circle,#mermaid-svg-nSq3ktPapsVygrng .node ellipse,#mermaid-svg-nSq3ktPapsVygrng .node polygon,#mermaid-svg-nSq3ktPapsVygrng .node path{fill:#ECECFF;stroke:#9370db;stroke-width:1px}#mermaid-svg-nSq3ktPapsVygrng .node .label{text-align:center;fill:#333}#mermaid-svg-nSq3ktPapsVygrng .node.clickable{cursor:pointer}#mermaid-svg-nSq3ktPapsVygrng .arrowheadPath{fill:#333}#mermaid-svg-nSq3ktPapsVygrng .edgePath .path{stroke:#333;stroke-width:1.5px}#mermaid-svg-nSq3ktPapsVygrng .flowchart-link{stroke:#333;fill:none}#mermaid-svg-nSq3ktPapsVygrng .edgeLabel{background-color:#e8e8e8;text-align:center}#mermaid-svg-nSq3ktPapsVygrng .edgeLabel rect{opacity:0.9}#mermaid-svg-nSq3ktPapsVygrng .edgeLabel span{color:#333}#mermaid-svg-nSq3ktPapsVygrng .cluster rect{fill:#ffffde;stroke:#aa3;stroke-width:1px}#mermaid-svg-nSq3ktPapsVygrng .cluster text{fill:#333}#mermaid-svg-nSq3ktPapsVygrng div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family);font-size:12px;background:#ffffde;border:1px solid #aa3;border-radius:2px;pointer-events:none;z-index:100}#mermaid-svg-nSq3ktPapsVygrng .actor{stroke:#ccf;fill:#ECECFF}#mermaid-svg-nSq3ktPapsVygrng text.actor>tspan{fill:#000;stroke:none}#mermaid-svg-nSq3ktPapsVygrng .actor-line{stroke:grey}#mermaid-svg-nSq3ktPapsVygrng .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333}#mermaid-svg-nSq3ktPapsVygrng .messageLine1{stroke-width:1.5;stroke-dasharray:2, 2;stroke:#333}#mermaid-svg-nSq3ktPapsVygrng #arrowhead path{fill:#333;stroke:#333}#mermaid-svg-nSq3ktPapsVygrng .sequenceNumber{fill:#fff}#mermaid-svg-nSq3ktPapsVygrng #sequencenumber{fill:#333}#mermaid-svg-nSq3ktPapsVygrng #crosshead path{fill:#333;stroke:#333}#mermaid-svg-nSq3ktPapsVygrng .messageText{fill:#333;stroke:#333}#mermaid-svg-nSq3ktPapsVygrng .labelBox{stroke:#ccf;fill:#ECECFF}#mermaid-svg-nSq3ktPapsVygrng .labelText,#mermaid-svg-nSq3ktPapsVygrng .labelText>tspan{fill:#000;stroke:none}#mermaid-svg-nSq3ktPapsVygrng .loopText,#mermaid-svg-nSq3ktPapsVygrng .loopText>tspan{fill:#000;stroke:none}#mermaid-svg-nSq3ktPapsVygrng .loopLine{stroke-width:2px;stroke-dasharray:2, 2;stroke:#ccf;fill:#ccf}#mermaid-svg-nSq3ktPapsVygrng .note{stroke:#aa3;fill:#fff5ad}#mermaid-svg-nSq3ktPapsVygrng .noteText,#mermaid-svg-nSq3ktPapsVygrng .noteText>tspan{fill:#000;stroke:none}#mermaid-svg-nSq3ktPapsVygrng .activation0{fill:#f4f4f4;stroke:#666}#mermaid-svg-nSq3ktPapsVygrng .activation1{fill:#f4f4f4;stroke:#666}#mermaid-svg-nSq3ktPapsVygrng .activation2{fill:#f4f4f4;stroke:#666}#mermaid-svg-nSq3ktPapsVygrng .mermaid-main-font{font-family:"trebuchet ms", verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-nSq3ktPapsVygrng .section{stroke:none;opacity:0.2}#mermaid-svg-nSq3ktPapsVygrng .section0{fill:rgba(102,102,255,0.49)}#mermaid-svg-nSq3ktPapsVygrng .section2{fill:#fff400}#mermaid-svg-nSq3ktPapsVygrng .section1,#mermaid-svg-nSq3ktPapsVygrng .section3{fill:#fff;opacity:0.2}#mermaid-svg-nSq3ktPapsVygrng .sectionTitle0{fill:#333}#mermaid-svg-nSq3ktPapsVygrng .sectionTitle1{fill:#333}#mermaid-svg-nSq3ktPapsVygrng .sectionTitle2{fill:#333}#mermaid-svg-nSq3ktPapsVygrng .sectionTitle3{fill:#333}#mermaid-svg-nSq3ktPapsVygrng .sectionTitle{text-anchor:start;font-size:11px;text-height:14px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-nSq3ktPapsVygrng .grid .tick{stroke:#d3d3d3;opacity:0.8;shape-rendering:crispEdges}#mermaid-svg-nSq3ktPapsVygrng .grid .tick text{font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-nSq3ktPapsVygrng .grid path{stroke-width:0}#mermaid-svg-nSq3ktPapsVygrng .today{fill:none;stroke:red;stroke-width:2px}#mermaid-svg-nSq3ktPapsVygrng .task{stroke-width:2}#mermaid-svg-nSq3ktPapsVygrng .taskText{text-anchor:middle;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-nSq3ktPapsVygrng .taskText:not([font-size]){font-size:11px}#mermaid-svg-nSq3ktPapsVygrng .taskTextOutsideRight{fill:#000;text-anchor:start;font-size:11px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-nSq3ktPapsVygrng .taskTextOutsideLeft{fill:#000;text-anchor:end;font-size:11px}#mermaid-svg-nSq3ktPapsVygrng .task.clickable{cursor:pointer}#mermaid-svg-nSq3ktPapsVygrng .taskText.clickable{cursor:pointer;fill:#003163 !important;font-weight:bold}#mermaid-svg-nSq3ktPapsVygrng .taskTextOutsideLeft.clickable{cursor:pointer;fill:#003163 !important;font-weight:bold}#mermaid-svg-nSq3ktPapsVygrng .taskTextOutsideRight.clickable{cursor:pointer;fill:#003163 !important;font-weight:bold}#mermaid-svg-nSq3ktPapsVygrng .taskText0,#mermaid-svg-nSq3ktPapsVygrng .taskText1,#mermaid-svg-nSq3ktPapsVygrng .taskText2,#mermaid-svg-nSq3ktPapsVygrng .taskText3{fill:#fff}#mermaid-svg-nSq3ktPapsVygrng .task0,#mermaid-svg-nSq3ktPapsVygrng .task1,#mermaid-svg-nSq3ktPapsVygrng .task2,#mermaid-svg-nSq3ktPapsVygrng .task3{fill:#8a90dd;stroke:#534fbc}#mermaid-svg-nSq3ktPapsVygrng .taskTextOutside0,#mermaid-svg-nSq3ktPapsVygrng .taskTextOutside2{fill:#000}#mermaid-svg-nSq3ktPapsVygrng .taskTextOutside1,#mermaid-svg-nSq3ktPapsVygrng .taskTextOutside3{fill:#000}#mermaid-svg-nSq3ktPapsVygrng .active0,#mermaid-svg-nSq3ktPapsVygrng .active1,#mermaid-svg-nSq3ktPapsVygrng .active2,#mermaid-svg-nSq3ktPapsVygrng .active3{fill:#bfc7ff;stroke:#534fbc}#mermaid-svg-nSq3ktPapsVygrng .activeText0,#mermaid-svg-nSq3ktPapsVygrng .activeText1,#mermaid-svg-nSq3ktPapsVygrng .activeText2,#mermaid-svg-nSq3ktPapsVygrng .activeText3{fill:#000 !important}#mermaid-svg-nSq3ktPapsVygrng .done0,#mermaid-svg-nSq3ktPapsVygrng .done1,#mermaid-svg-nSq3ktPapsVygrng .done2,#mermaid-svg-nSq3ktPapsVygrng .done3{stroke:grey;fill:#d3d3d3;stroke-width:2}#mermaid-svg-nSq3ktPapsVygrng .doneText0,#mermaid-svg-nSq3ktPapsVygrng .doneText1,#mermaid-svg-nSq3ktPapsVygrng .doneText2,#mermaid-svg-nSq3ktPapsVygrng .doneText3{fill:#000 !important}#mermaid-svg-nSq3ktPapsVygrng .crit0,#mermaid-svg-nSq3ktPapsVygrng .crit1,#mermaid-svg-nSq3ktPapsVygrng .crit2,#mermaid-svg-nSq3ktPapsVygrng .crit3{stroke:#f88;fill:red;stroke-width:2}#mermaid-svg-nSq3ktPapsVygrng .activeCrit0,#mermaid-svg-nSq3ktPapsVygrng .activeCrit1,#mermaid-svg-nSq3ktPapsVygrng .activeCrit2,#mermaid-svg-nSq3ktPapsVygrng .activeCrit3{stroke:#f88;fill:#bfc7ff;stroke-width:2}#mermaid-svg-nSq3ktPapsVygrng .doneCrit0,#mermaid-svg-nSq3ktPapsVygrng .doneCrit1,#mermaid-svg-nSq3ktPapsVygrng .doneCrit2,#mermaid-svg-nSq3ktPapsVygrng .doneCrit3{stroke:#f88;fill:#d3d3d3;stroke-width:2;cursor:pointer;shape-rendering:crispEdges}#mermaid-svg-nSq3ktPapsVygrng .milestone{transform:rotate(45deg) scale(0.8, 0.8)}#mermaid-svg-nSq3ktPapsVygrng .milestoneText{font-style:italic}#mermaid-svg-nSq3ktPapsVygrng .doneCritText0,#mermaid-svg-nSq3ktPapsVygrng .doneCritText1,#mermaid-svg-nSq3ktPapsVygrng .doneCritText2,#mermaid-svg-nSq3ktPapsVygrng .doneCritText3{fill:#000 !important}#mermaid-svg-nSq3ktPapsVygrng .activeCritText0,#mermaid-svg-nSq3ktPapsVygrng .activeCritText1,#mermaid-svg-nSq3ktPapsVygrng .activeCritText2,#mermaid-svg-nSq3ktPapsVygrng .activeCritText3{fill:#000 !important}#mermaid-svg-nSq3ktPapsVygrng .titleText{text-anchor:middle;font-size:18px;fill:#000;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-nSq3ktPapsVygrng g.classGroup text{fill:#9370db;stroke:none;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family);font-size:10px}#mermaid-svg-nSq3ktPapsVygrng g.classGroup text .title{font-weight:bolder}#mermaid-svg-nSq3ktPapsVygrng g.clickable{cursor:pointer}#mermaid-svg-nSq3ktPapsVygrng g.classGroup rect{fill:#ECECFF;stroke:#9370db}#mermaid-svg-nSq3ktPapsVygrng g.classGroup line{stroke:#9370db;stroke-width:1}#mermaid-svg-nSq3ktPapsVygrng .classLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5}#mermaid-svg-nSq3ktPapsVygrng .classLabel .label{fill:#9370db;font-size:10px}#mermaid-svg-nSq3ktPapsVygrng .relation{stroke:#9370db;stroke-width:1;fill:none}#mermaid-svg-nSq3ktPapsVygrng .dashed-line{stroke-dasharray:3}#mermaid-svg-nSq3ktPapsVygrng #compositionStart{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-nSq3ktPapsVygrng #compositionEnd{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-nSq3ktPapsVygrng #aggregationStart{fill:#ECECFF;stroke:#9370db;stroke-width:1}#mermaid-svg-nSq3ktPapsVygrng #aggregationEnd{fill:#ECECFF;stroke:#9370db;stroke-width:1}#mermaid-svg-nSq3ktPapsVygrng #dependencyStart{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-nSq3ktPapsVygrng #dependencyEnd{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-nSq3ktPapsVygrng #extensionStart{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-nSq3ktPapsVygrng #extensionEnd{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-nSq3ktPapsVygrng .commit-id,#mermaid-svg-nSq3ktPapsVygrng .commit-msg,#mermaid-svg-nSq3ktPapsVygrng .branch-label{fill:lightgrey;color:lightgrey;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-nSq3ktPapsVygrng .pieTitleText{text-anchor:middle;font-size:25px;fill:#000;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-nSq3ktPapsVygrng .slice{font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-nSq3ktPapsVygrng g.stateGroup text{fill:#9370db;stroke:none;font-size:10px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-nSq3ktPapsVygrng g.stateGroup text{fill:#9370db;fill:#333;stroke:none;font-size:10px}#mermaid-svg-nSq3ktPapsVygrng g.statediagram-cluster .cluster-label text{fill:#333}#mermaid-svg-nSq3ktPapsVygrng g.stateGroup .state-title{font-weight:bolder;fill:#000}#mermaid-svg-nSq3ktPapsVygrng g.stateGroup rect{fill:#ECECFF;stroke:#9370db}#mermaid-svg-nSq3ktPapsVygrng g.stateGroup line{stroke:#9370db;stroke-width:1}#mermaid-svg-nSq3ktPapsVygrng .transition{stroke:#9370db;stroke-width:1;fill:none}#mermaid-svg-nSq3ktPapsVygrng .stateGroup .composit{fill:white;border-bottom:1px}#mermaid-svg-nSq3ktPapsVygrng .stateGroup .alt-composit{fill:#e0e0e0;border-bottom:1px}#mermaid-svg-nSq3ktPapsVygrng .state-note{stroke:#aa3;fill:#fff5ad}#mermaid-svg-nSq3ktPapsVygrng .state-note text{fill:black;stroke:none;font-size:10px}#mermaid-svg-nSq3ktPapsVygrng .stateLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.7}#mermaid-svg-nSq3ktPapsVygrng .edgeLabel text{fill:#333}#mermaid-svg-nSq3ktPapsVygrng .stateLabel text{fill:#000;font-size:10px;font-weight:bold;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-nSq3ktPapsVygrng .node circle.state-start{fill:black;stroke:black}#mermaid-svg-nSq3ktPapsVygrng .node circle.state-end{fill:black;stroke:white;stroke-width:1.5}#mermaid-svg-nSq3ktPapsVygrng #statediagram-barbEnd{fill:#9370db}#mermaid-svg-nSq3ktPapsVygrng .statediagram-cluster rect{fill:#ECECFF;stroke:#9370db;stroke-width:1px}#mermaid-svg-nSq3ktPapsVygrng .statediagram-cluster rect.outer{rx:5px;ry:5px}#mermaid-svg-nSq3ktPapsVygrng .statediagram-state .divider{stroke:#9370db}#mermaid-svg-nSq3ktPapsVygrng .statediagram-state .title-state{rx:5px;ry:5px}#mermaid-svg-nSq3ktPapsVygrng .statediagram-cluster.statediagram-cluster .inner{fill:white}#mermaid-svg-nSq3ktPapsVygrng .statediagram-cluster.statediagram-cluster-alt .inner{fill:#e0e0e0}#mermaid-svg-nSq3ktPapsVygrng .statediagram-cluster .inner{rx:0;ry:0}#mermaid-svg-nSq3ktPapsVygrng .statediagram-state rect.basic{rx:5px;ry:5px}#mermaid-svg-nSq3ktPapsVygrng .statediagram-state rect.divider{stroke-dasharray:10,10;fill:#efefef}#mermaid-svg-nSq3ktPapsVygrng .note-edge{stroke-dasharray:5}#mermaid-svg-nSq3ktPapsVygrng .statediagram-note rect{fill:#fff5ad;stroke:#aa3;stroke-width:1px;rx:0;ry:0}:root{--mermaid-font-family: '"trebuchet ms", verdana, arial';--mermaid-font-family: "Comic Sans MS", "Comic Sans", cursive}#mermaid-svg-nSq3ktPapsVygrng .error-icon{fill:#522}#mermaid-svg-nSq3ktPapsVygrng .error-text{fill:#522;stroke:#522}#mermaid-svg-nSq3ktPapsVygrng .edge-thickness-normal{stroke-width:2px}#mermaid-svg-nSq3ktPapsVygrng .edge-thickness-thick{stroke-width:3.5px}#mermaid-svg-nSq3ktPapsVygrng .edge-pattern-solid{stroke-dasharray:0}#mermaid-svg-nSq3ktPapsVygrng .edge-pattern-dashed{stroke-dasharray:3}#mermaid-svg-nSq3ktPapsVygrng .edge-pattern-dotted{stroke-dasharray:2}#mermaid-svg-nSq3ktPapsVygrng .marker{fill:#333}#mermaid-svg-nSq3ktPapsVygrng .marker.cross{stroke:#333}:root { --mermaid-font-family: "trebuchet ms", verdana, arial;}#mermaid-svg-nSq3ktPapsVygrng {color: rgba(0, 0, 0, 0.75);font: ;}

.class
.jar
haveCache
noCache
DexArchiveBuilderTransform.transform
convertToDexArchive
launchProcessing
processJarInput
convertJarToDexArchive
copyToOutPut
备份缓存文件只针对jar缓存
END

对于AGP为什么选择只选择缓存jar,从AGP中DexArchiveBuilderCacheHandler部分注释可以找到答案,注释如下

 // Don't cache libraries depending on class files in folders:// Folders content is expected to change often so probably not worth paying the cache cost// if we frequently need to rebuild anyway.// Supporting dependency to class files would also require special care to respect order.

大意认为class文件通常是经常发生变化的,缓存没有多大意义;而jar则被认为是稳定的所以做了缓存处理,缓存相关类参见DexArchiveBuilderCacheHandler,有兴趣大家自己瞅瞅

Task25 transformClassesWithMultidexlistForDebug

1. input/ouput

预备操作,build.gradle中添加

defaultConfig {multiDexEnabled truemultiDexKeepFile file('maindexlist.txt')}

先在maindexlist.txt中添加MainActivity路径让其进入主dex

askName:transformClassesWithMultidexlistForDebug
input:/Users/apple/work/project/AndroidGradleTaskDemo/app/build/intermediates/legacy_multidex_aapt_derived_proguard_rules/debug/processDebugResources/manifest_keep.txt
input:/Users/apple/work/project/AndroidGradleTaskDemo/app/maindexlist.txt
input:/Users/apple/.gradle/caches/transforms-1/files-1.1/adapters-3.2.0.aar/49b3d7e4ab68d92f056ea8f56b33e9fb/jars/classes.jar
input:/Users/apple/.gradle/caches/transforms-1/files-1.1/library-3.2.0.aar/818ffb3fe5dc5eeb6b4e51c93615b7fb/jars/classes.jar
input:/Users/apple/.gradle/caches/modules-2/files-2.1/com.android.databinding/baseLibrary/3.2.0/fb5f8492c36231104cd86feaefa723291504c0a6/baseLibrary-3.2.0.jar
input:/Users/apple/.gradle/caches/transforms-1/files-1.1/multidex-1.0.2.aar/36d8b7d496f603cd6f98051792b0414c/jars/classes.jar
input:/Users/apple/.gradle/caches/transforms-1/files-1.1/appcompat-v7-26.1.0.aar/2774ea4f1cf1e83a6ad8e8d3c8b463b6/jars/classes.jar
input:/Users/apple/.gradle/caches/transforms-1/files-1.1/constraint-layout-1.1.3.aar/f43c0ba95b6494825ed940fc4f04662b/jars/classes.jar
input:/Users/apple/.gradle/caches/transforms-1/files-1.1/support-v4-26.1.0.aar/9ac5f97e8ccb24c52b7cbb6202c12ad0/jars/classes.jar
input:/Users/apple/.gradle/caches/transforms-1/files-1.1/support-fragment-26.1.0.aar/7e6a4ce6591d722d47aafc36d980f8b4/jars/classes.jar
input:/Users/apple/.gradle/caches/transforms-1/files-1.1/support-core-utils-26.1.0.aar/4c474caa9ac1f01c4936bd96905ecacd/jars/classes.jar
input:/Users/apple/.gradle/caches/transforms-1/files-1.1/animated-vector-drawable-26.1.0.aar/559112320064089dfaf6780e71d5b44f/jars/classes.jar
input:/Users/apple/.gradle/caches/transforms-1/files-1.1/support-vector-drawable-26.1.0.aar/c2c3ad4abfd49316f6769b8238b0f010/jars/classes.jar
input:/Users/apple/.gradle/caches/transforms-1/files-1.1/support-media-compat-26.1.0.aar/53ab5ad72634f3497309a8788f3ca200/jars/classes.jar
input:/Users/apple/.gradle/caches/transforms-1/files-1.1/support-core-ui-26.1.0.aar/868eaa7e0c620cd85d72ad4f340e8bb1/jars/classes.jar
input:/Users/apple/.gradle/caches/transforms-1/files-1.1/support-compat-26.1.0.aar/4ec3c1c46e5bad9ac3b91f45a2afec3e/jars/classes.jar
input:/Users/apple/.gradle/caches/transforms-1/files-1.1/runtime-1.0.3.aar/5765c0929bc6bc40d70d6fc25f402f42/jars/classes.jar
input:/Users/apple/.gradle/caches/modules-2/files-2.1/android.arch.lifecycle/common/1.0.3/7d7f60c4783872861222166f6164215f8951c7b1/common-1.0.3.jar
input:/Users/apple/.gradle/caches/modules-2/files-2.1/android.arch.core/common/1.0.0/a2d487452376193fc8c103dd2b9bd5f2b1b44563/common-1.0.0.jar
input:/Users/apple/.gradle/caches/modules-2/files-2.1/com.android.support/support-annotations/26.1.0/814258103cf26a15fcc26ecce35f5b7d24b73f8/support-annotations-26.1.0.jar
input:/Users/apple/.gradle/caches/modules-2/files-2.1/com.android.support.constraint/constraint-layout-solver/1.1.3/bde0667d7414c16ed62d3cfe993cff7f9d732373/constraint-layout-solver-1.1.3.jar
input:/Users/apple/work/project/AndroidGradleTaskDemo/app/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/android/support/coreutils/R.class
...
=========================================================
output:/Users/apple/work/project/AndroidGradleTaskDemo/app/build/intermediates/legacy_multidex_main_dex_list/debug/transformClassesWithMultidexlistForDebug/mainDexList.txt

其实该任务就是我们通常说的Android分包机制
从控制台可以看出该任务接受manifest_keep.txt、gradle中配置的multiDexKeepFile属性以及APP依赖的jar,class文件最终进行处理生成mainDexList.txt该文件就是主dex中需要包含的类的集合,流程图如下

2. 核心类(D8MainDexListTransform)

/*** Calculate the main dex list using D8.*/
class D8MainDexListTransform(private val manifestProguardRules: BuildableArtifact,private val userProguardRules: Path? = null,private val userClasses: Path? = null,private val includeDynamicFeatures: Boolean = false,private val bootClasspath: Supplier<List<Path>>) : Transform(), MainDexListWriter {private val logger = LoggerWrapper.getLogger(D8MainDexListTransform::class.java)private lateinit var outputMainDexList: Path@JvmOverloadsconstructor(variantScope: VariantScope, includeDynamicFeatures: Boolean = false) :this(variantScope.artifacts.getFinalArtifactFiles(InternalArtifactType.LEGACY_MULTIDEX_AAPT_DERIVED_PROGUARD_RULES),variantScope.variantConfiguration.multiDexKeepProguard?.toPath(),variantScope.variantConfiguration.multiDexKeepFile?.toPath(),includeDynamicFeatures,Supplier {variantScope.globalScope.androidBuilder.getBootClasspath(true).map { it.toPath() }})...override fun transform(invocation: TransformInvocation) {logger.verbose("Generating the main dex list using D8.")try {val inputs = MainDexListTransform.getByInputType(invocation)val programFiles = inputs[INPUT_JAR]!!.map { it.toPath() }val libraryFiles = inputs[LIBRARY_JAR]!!.map { it.toPath() } + bootClasspath.get()logger.verbose("Program files: %s", programFiles.joinToString())logger.verbose("Library files: %s", libraryFiles.joinToString())logger.verbose("Proguard rule files: %s",listOfNotNull(manifestProguardRules, userProguardRules).joinToString())// 1.读取混淆规则文件val proguardRules =listOfNotNull(manifestProguardRules.singleFile().toPath(), userProguardRules)// 2.构建主dex集合    val mainDexClasses = mutableSetOf<String>()// 3. 获取系统平台的keep配置文件(参见												

Android构建流程——篇七相关推荐

  1. Android构建流程——篇二

    文章目录 预操作 任务列表 如何查看一个task类 Task1: checkDebugClasspath 1. input/output 2. 如何找到任务实现类 3. 核心类(AppClasspat ...

  2. Android构建流程——篇一

    Android构建流程 前言 APK 构建流程 AGP(3.2.0)任务列表总览图 参考文献 前言 大家平时开发Android项目时一般都是点击AS run按钮,这样apk会自动安装到手机上,这整个过 ...

  3. Android构建流程——篇四

    文章目录 Task9 generateDebugResValues 1. input/ouput 2. 核心类(GenerateResValues) Task10 generateDebugResou ...

  4. Android构建流程——篇六

    文章目录 Task17: javaPreCompileDebug 1. input/ouput 2. 验证 3. 核心类(JavaPreCompileTask) Task18:compileDebug ...

  5. Android构建流程——篇五

    文章目录 Task13: processDebugManifest 1. input/ouput 2. 整体流程 3. 调用链路 4. 核心类(MergeManifests) 5. AndroidBu ...

  6. Android构建流程——篇三

    文章目录 Task5 checkDebugManifest 1. input/ouput 2. 核心类(CheckManifest) Task6 generateDebugBuildConfig 1. ...

  7. Android构建流程——篇八

    文章目录 Task29 checkDebugLibraries 1. inut/ouput 2. 核心类(CheckMultiApkLibrariesTask) Task30 processDebug ...

  8. Android汽车服务篇(七) CarPowerManagementService

    一. 前言 电源管理是AAOS上又一个比较特殊的部分.  由于车辆的使用场景的特殊性和复杂性, 同时需要和其他ECU(Electronic Control Unit)电子控制单元的配合, 都增加了车载 ...

  9. 优酷 Android 构建速度优化实践

    作者:苏彦郊(木磊) Android 项目一般使用 gradle 作为构建打包工具,gradle 简洁.动态的功能特性为人津津乐道,同样,构建执行速度缓慢的缺陷也一直为人诟病. 近年来,随着优酷功能特 ...

最新文章

  1. MYSQL 使用自定义表变量
  2. ABB 机器人 IRBP系列转台的一段代码注释
  3. vue element menu侧边导航栏 数据渲染
  4. LeetCode刷题(22)
  5. python二维向量运算_python中二维数组的Elementwise与or或运算
  6. windows过滤中设备绑定的内核API之一
  7. 我是如何写作一本软件+哲学式的书籍的(上)
  8. 怎么用xmind整理我们获取的杂乱的信息
  9. 图书管理系统数据库设计
  10. 【Uniapp】Uniapp 实现 App 版本自动升级
  11. choco 使用详解
  12. 使用注册表清理右键新建菜单
  13. 玩转基因组浏览器之IGV展示bam文件
  14. ACdream 之ACfun 题解
  15. linux单片机用什么数据库,基于ARM-Linux的SQLite嵌入式数据库的研究 -单片机-电子工程世界网...
  16. 19、android面试题整理(自己给自己充充电吧)
  17. C++实现类似QT中的计时器QTime类(CQTime)
  18. 淘宝/天猫关键词搜索最新接口
  19. 燕教授使用体验,从漱口水到牙膏
  20. c++调用win32API控制打印机打印

热门文章

  1. python必刷面试_Python面试必刷题系列(5)
  2. kaggle机器学习作业(房价预测)
  3. AAAI 2022 | 条件局部图卷积网络用以气象预测
  4. EMNLP 2021 | 正则表达式与神经网络的深度融合(续)
  5. 生物岛实验室闵明玮课题组诚聘副研究员/博士后/科研助理/实习生
  6. 基于Conditional Layer Normalization的条件文本生成
  7. 细水长flow之f-VAEs:Glow与VAEs的联姻
  8. HDU1599 find the mincost route Floyd算法求最小环
  9. HDU1045 Fire Net 递归回溯
  10. python pip gpl_一文了解Python的pip工具