Android构建流程——篇七

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 {
   

	@Override
    public 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);
                                    
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值