美文网首页android
Android gradle打包涉及task源码解析(六)

Android gradle打包涉及task源码解析(六)

作者: 枫吹一痕 | 来源:发表于2018-12-16 21:11 被阅读0次

    文章序号

    此篇文章将分析如下7个task。

    :app:mergeDebugJniLibFolders
    :app:transformNativeLibsWithMergeJniLibsForDebug
    :app:processDebugJavaRes NO-SOURCE
    :app:transformResourcesWithMergeJavaResForDebug
    :app:validateSigningDebug
    :app:packageDebug
    :app:assembleDebug
    

    mergeDebugJniLibFolders

    执行命令:./gradlew mergeDebugJniLibFolders

    • inputs&outputs
    input file:/Users/chao.zheng/sunday/OpenSpace/TasksPro/app/src/debug/jniLibs
    input file:/Users/chao.zheng/sunday/OpenSpace/TasksPro/app/src/main/jniLibs
    ---------------------------------------------------
    output file:/Users/chao.zheng/sunday/OpenSpace/TasksPro/app/build/intermediates/incremental/mergeDebugJniLibFolders
    output file:/Users/chao.zheng/sunday/OpenSpace/TasksPro/app/build/intermediates/jniLibs/debug
    

    输入文件也就是我们项目的jniLibs目录。

    输出分为两种:

    增量编译的目录(intermediates/incremental/mergeDebugJniLibFolders),暂不分析;

    jniLibs目录(intermediates/jniLibs/debug)。

    通过输入输出基本能判断mergeDebugJniLibFolders任务就是把项目的jniLibs目录合到intermediates/jniLibs/debug下面。

    • 源码

    https://android.googlesource.com/platform/tools/base/+/gradle_3.0.0/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/MergeSourceSetFolders.java

    • 主要代码逻辑

    看到MergeSourceSetFolders这个类是不是很熟悉?在介绍mergeDebugAssetstask时,有分析到这个类,这里就不在具体分析了,实际干的事情类似,就是将相应的目录下的文件merge到一个指定的目录下。

    transformNativeLibsWithMergeJniLibsForDebug

    执行命令:./gradlew transformNativeLibsWithMergeJniLibsForDebug

    • inputs&outputs
    input file:/Users/chao.zheng/.gradle/caches/transforms-1/files-1.1/appcompat-v7-26.1.0.aar/6b443e96f1af9aa241aaa70576c67a57/jars/classes.jar
    input file:/Users/chao.zheng/.gradle/caches/transforms-1/files-1.1/constraint-layout-1.1.3.aar/f44da5c361a1f52801511229596f72e7/jars/classes.jar
    input file:/Users/chao.zheng/.gradle/caches/transforms-1/files-1.1/butterknife-8.5.1.aar/9d5de52440cb778daab09db33955642f/jars/classes.jar
    input file:/Users/chao.zheng/.gradle/caches/transforms-1/files-1.1/animated-vector-drawable-26.1.0.aar/9c804d63d6f065a8f9945f9ad94fee0e/jars/classes.jar
    input file:/Users/chao.zheng/.gradle/caches/transforms-1/files-1.1/support-vector-drawable-26.1.0.aar/4e56cc34abf77378e2b8d16ee237c82d/jars/classes.jar
    input file:/Users/chao.zheng/.gradle/caches/modules-2/files-2.1/com.jakewharton/butterknife-annotations/8.5.1/bb67dad90bab7cd77a8f7f1b8442b47e3a2326bc/butterknife-annotations-8.5.1.jar
    input file:/Users/chao.zheng/.gradle/caches/transforms-1/files-1.1/support-v4-26.1.0.aar/3bf8586900bd31e222ef8b68bfd6e744/jars/classes.jar
    input file:/Users/chao.zheng/.gradle/caches/transforms-1/files-1.1/support-media-compat-26.1.0.aar/267524a16ca7128dd9cef3c19f394439/jars/classes.jar
    input file:/Users/chao.zheng/.gradle/caches/transforms-1/files-1.1/support-fragment-26.1.0.aar/77cf518e9868987a283f04cec221fefa/jars/classes.jar
    input file:/Users/chao.zheng/.gradle/caches/transforms-1/files-1.1/support-core-utils-26.1.0.aar/8634ab1afa6a5a1a947a7bd163aba14f/jars/classes.jar
    input file:/Users/chao.zheng/.gradle/caches/transforms-1/files-1.1/support-core-ui-26.1.0.aar/8902e2a864b44d47c26fbc80fdafe175/jars/classes.jar
    input file:/Users/chao.zheng/.gradle/caches/transforms-1/files-1.1/support-compat-26.1.0.aar/3e4c87483eacfb4c962d7380a59a114d/jars/classes.jar
    input file:/Users/chao.zheng/.gradle/caches/modules-2/files-2.1/com.android.support/support-annotations/26.1.0/814258103cf26a15fcc26ecce35f5b7d24b73f8/support-annotations-26.1.0.jar
    input file:/Users/chao.zheng/.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 file:/Users/chao.zheng/.gradle/caches/transforms-1/files-1.1/runtime-1.0.0.aar/ed085e7b9476f7a9fef4ffbb323166ba/jars/classes.jar
    input file:/Users/chao.zheng/.gradle/caches/modules-2/files-2.1/android.arch.lifecycle/common/1.0.0/e414a4cb28434e25c4f6aa71426eb20cf4874ae9/common-1.0.0.jar
    input file:/Users/chao.zheng/.gradle/caches/modules-2/files-2.1/android.arch.core/common/1.0.0/a2d487452376193fc8c103dd2b9bd5f2b1b44563/common-1.0.0.jar
    input file:/Users/chao.zheng/sunday/OpenSpace/TasksPro/app/build/intermediates/jniLibs/debug/armeabi-v7a/libcommon-jni.so
    input file:/Users/chao.zheng/sunday/OpenSpace/TasksPro/app/build/intermediates/jniLibs/debug/armeabi/libcommon-jni.so
    input file:/Users/chao.zheng/sunday/OpenSpace/TasksPro/app/build/intermediates/jniLibs/debug/GDTActionSDK.min.1.2.0.jar
    ---------------------------------------------------
    output file:/Users/chao.zheng/sunday/OpenSpace/TasksPro/app/build/intermediates/incremental/debug-mergeJniLibs/zip-cache
    output file:/Users/chao.zheng/sunday/OpenSpace/TasksPro/app/build/intermediates/transforms/mergeJniLibs/debug
    

    查看输入文件,会发现输入文件类型分为两种:

    1、依赖的库的jar文件;

    2、mergeDebugJniLibFolders任务的输出。

    输出目录也很简单,一个是增量编译的目录,一个是真正的merge输出目录。

    • 源码

    https://android.googlesource.com/platform/tools/base/+/gradle_3.0.0/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/transforms/MergeJavaResourcesTransform.java

    • 主要代码逻辑
    public void transform(@NonNull TransformInvocation invocation)
                throws IOException, TransformException {
            
            ...
            // 输入inputs、output执行merge操作
            state = IncrementalFileMerger.merge(ImmutableList.copyOf(inputs), output, state);
            saveMergeState(state);
    
            cacheUpdates.forEach(Runnable::run);
        }
    

    通过代码可以很清晰的知道这个任务就是对输入进行一个merge操作,merge的逻辑在IncrementalFileMerger类里面,这里不在具体分析。MergeJavaResourcesTransform这个类实际上负责多种类型的merge操作,通过类型区分,代码如下:

        if (mergedType == QualifiedContent.DefaultContentType.RESOURCES) {
            acceptedPathsPredicate =
                    path -> !path.endsWith(SdkConstants.DOT_CLASS)
                            && !path.endsWith(SdkConstants.DOT_NATIVE_LIBS);
        } else if (mergedType == ExtendedContentType.NATIVE_LIBS) {
    

    transformResourcesWithMergeJavaResForDebug

    执行命令:./gradlew transformResourcesWithMergeJavaResForDebug

    • inputs&outputs
    input file:/Users/chao.zheng/.gradle/caches/transforms-1/files-1.1/appcompat-v7-26.1.0.aar/6b443e96f1af9aa241aaa70576c67a57/jars/classes.jar
    input file:/Users/chao.zheng/.gradle/caches/transforms-1/files-1.1/constraint-layout-1.1.3.aar/f44da5c361a1f52801511229596f72e7/jars/classes.jar
    input file:/Users/chao.zheng/.gradle/caches/transforms-1/files-1.1/butterknife-8.5.1.aar/9d5de52440cb778daab09db33955642f/jars/classes.jar
    input file:/Users/chao.zheng/.gradle/caches/modules-2/files-2.1/com.squareup.okhttp3/okhttp/3.11.0/75966e05a49046ca2ae734e5626f28837a8d1e82/okhttp-3.11.0.jar
    input file:/Users/chao.zheng/.gradle/caches/transforms-1/files-1.1/animated-vector-drawable-26.1.0.aar/9c804d63d6f065a8f9945f9ad94fee0e/jars/classes.jar
    input file:/Users/chao.zheng/.gradle/caches/transforms-1/files-1.1/support-vector-drawable-26.1.0.aar/4e56cc34abf77378e2b8d16ee237c82d/jars/classes.jar
    input file:/Users/chao.zheng/.gradle/caches/modules-2/files-2.1/com.jakewharton/butterknife-annotations/8.5.1/bb67dad90bab7cd77a8f7f1b8442b47e3a2326bc/butterknife-annotations-8.5.1.jar
    input file:/Users/chao.zheng/.gradle/caches/transforms-1/files-1.1/support-v4-26.1.0.aar/3bf8586900bd31e222ef8b68bfd6e744/jars/classes.jar
    input file:/Users/chao.zheng/.gradle/caches/transforms-1/files-1.1/support-media-compat-26.1.0.aar/267524a16ca7128dd9cef3c19f394439/jars/classes.jar
    input file:/Users/chao.zheng/.gradle/caches/transforms-1/files-1.1/support-fragment-26.1.0.aar/77cf518e9868987a283f04cec221fefa/jars/classes.jar
    input file:/Users/chao.zheng/.gradle/caches/transforms-1/files-1.1/support-core-utils-26.1.0.aar/8634ab1afa6a5a1a947a7bd163aba14f/jars/classes.jar
    input file:/Users/chao.zheng/.gradle/caches/transforms-1/files-1.1/support-core-ui-26.1.0.aar/8902e2a864b44d47c26fbc80fdafe175/jars/classes.jar
    input file:/Users/chao.zheng/.gradle/caches/transforms-1/files-1.1/support-compat-26.1.0.aar/3e4c87483eacfb4c962d7380a59a114d/jars/classes.jar
    input file:/Users/chao.zheng/.gradle/caches/modules-2/files-2.1/com.android.support/support-annotations/26.1.0/814258103cf26a15fcc26ecce35f5b7d24b73f8/support-annotations-26.1.0.jar
    input file:/Users/chao.zheng/.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 file:/Users/chao.zheng/.gradle/caches/modules-2/files-2.1/com.squareup.okio/okio/1.14.0/102d7be47241d781ef95f1581d414b0943053130/okio-1.14.0.jar
    input file:/Users/chao.zheng/.gradle/caches/transforms-1/files-1.1/runtime-1.0.0.aar/ed085e7b9476f7a9fef4ffbb323166ba/jars/classes.jar
    input file:/Users/chao.zheng/.gradle/caches/modules-2/files-2.1/android.arch.lifecycle/common/1.0.0/e414a4cb28434e25c4f6aa71426eb20cf4874ae9/common-1.0.0.jar
    input file:/Users/chao.zheng/.gradle/caches/modules-2/files-2.1/android.arch.core/common/1.0.0/a2d487452376193fc8c103dd2b9bd5f2b1b44563/common-1.0.0.jar
    ---------------------------------------------------
    output file:/Users/chao.zheng/sunday/OpenSpace/TasksPro/app/build/intermediates/incremental/debug-mergeJavaRes/zip-cache
    output file:/Users/chao.zheng/sunday/OpenSpace/TasksPro/app/build/intermediates/transforms/mergeJavaRes/debug
    
    • 源码

    https://android.googlesource.com/platform/tools/base/+/gradle_3.0.0/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/transforms/MergeJavaResourcesTransform.java

    • 主要代码逻辑

    实际上和前一个task transformNativeLibsWithMergeJniLibsForDebug复用的是一套逻辑,只不过在merge的时候一个是lib类型,一个是resource类型。这个task就是将相应依赖的jar里面的resource合并到intermediates/transforms/mergeJavaRes/debug目录。但是有一点需要注意,merge java resource时会有些文件时默认不会执行merge操作的,如下:

    public PackagingOptions() {
            // ATTENTION - keep this in sync with JavaDoc above.
            exclude("/META-INF/LICENSE");
            exclude("/META-INF/LICENSE.txt");
            exclude("/META-INF/MANIFEST.MF");
            exclude("/META-INF/NOTICE");
            exclude("/META-INF/NOTICE.txt");
            exclude("/META-INF/*.DSA");
            exclude("/META-INF/*.EC");
            exclude("/META-INF/*.SF");
            exclude("/META-INF/*.RSA");
            exclude("/META-INF/maven/**");
            exclude("/NOTICE");
            exclude("/NOTICE.txt");
            exclude("/LICENSE.txt");
            exclude("/LICENSE");
            // Exclude version control folders.
            exclude("**/.svn/**");
            exclude("**/CVS/**");
            exclude("**/SCCS/**");
            // Exclude hidden and backup files.
            exclude("**/.*/**");
            exclude("**/.*");
            exclude("**/*~");
            // Exclude index files
            exclude("**/thumbs.db");
            exclude("**/picasa.ini");
            // Exclude javadoc files
            exclude("**/about.html");
            exclude("**/package.html");
            exclude("**/overview.html");
            // Exclude stuff for unknown reasons
            exclude("**/_*");
            exclude("**/_*/**");
            // Merge services
            merge("/META-INF/services/**");
        }
    

    以上的配置是默认不会执行merge操作的。当然这里gradle也提供了一些其他的配置如:

    packagingOptions {
        merge ""
        exclude ""
        pickFirsts ""
    }
    

    validateSigningDebug

    • 源码

    https://android.googlesource.com/platform/tools/base/+/gradle_3.0.0/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/tasks/ValidateSigningTask.java

    • 主要代码逻辑

    看下这个类的注视

    /**
     * A validate task that creates the debug keystore if it's missing. It only creates it if it's in
     * the default debug keystore location.
     *
     * It's linked to a given SigningConfig
     */
    

    通过注视可以很明确的知道,这个task就是在没有keystore时创建一个keystore,也就是在debug的时候,会使用默认的keystore,这也是为什么在debug模式下,没有配置keystore时,apk仍然能够安装使用。

    packageDebug

    胜利在望,接下来分析最后一个task.

    执行命令:./gradlew packageDebug

    • inputs&outputs
    input file:/Users/chao.zheng/sunday/OpenSpace/TasksPro/app/build/intermediates/assets/debug
    input file:/Users/chao.zheng/sunday/OpenSpace/TasksPro/app/build/intermediates/transforms/dexMerger/debug/0
    input file:/Users/chao.zheng/sunday/OpenSpace/TasksPro/app/build/intermediates/transforms/mergeJavaRes/debug/0.jar
    input file:/Users/chao.zheng/sunday/OpenSpace/TasksPro/app/build/intermediates/transforms/mergeJniLibs/debug/0
    input file:/Users/chao.zheng/sunday/OpenSpace/TasksPro/app/build/intermediates/manifests/full/debug
    input file:/Users/chao.zheng/sunday/OpenSpace/TasksPro/app/build/intermediates/res/debug
    input file:/Users/chao.zheng/.android/debug.keystore
    ---------------------------------------------------
    output file:/Users/chao.zheng/sunday/OpenSpace/TasksPro/app/build/intermediates/incremental/packageDebug
    output file:/Users/chao.zheng/sunday/OpenSpace/TasksPro/app/build/outputs/apk/debug
    

    分析下输入目录:

    1、assets/debugassets目录下的文件;

    2、dexMerger/debug/0dex 文件;

    3、mergeJavaRes/debug/0.jar java resource 文件;

    4、mergeJniLibs/debug/0 so文件;

    5、manifests/full/debugmanifest文件;

    6、res/debugresources 文件;

    7、debug.keystore keystore 文件;

    输出文件即为apk文件。

    所以packageDebug任务就是打apk包的。

    • 源码

    https://android.googlesource.com/platform/tools/base/+/gradle_3.0.0/build-system/gradle-core/src/main/java/com/android/build/gradle/tasks/PackageAndroidArtifact.java

    • 主要代码逻辑
        /**
         * Packages the application incrementally. In case of instant run packaging, this is not a
         * perfectly incremental task as some files are always rewritten even if no change has occurred.
         *
         * @param apkData the split being built
         * @param outputFile expected output package file
         * @param changedDex incremental dex packaging data
         * @param changedJavaResources incremental java resources
         * @param changedAssets incremental assets
         * @param changedAndroidResources incremental Android resource
         * @param changedNLibs incremental native libraries changed
         * @throws IOException failed to package the APK
         */
        private void doTask(
                @NonNull ApkData apkData,
                @NonNull File incrementalDirForSplit,
                @NonNull File outputFile,
                @NonNull FileCacheByPath cacheByPath,
                @NonNull Collection<BuildOutput> manifestOutputs,
                @NonNull ImmutableMap<RelativeFile, FileStatus> changedDex,
                @NonNull ImmutableMap<RelativeFile, FileStatus> changedJavaResources,
                @NonNull ImmutableMap<RelativeFile, FileStatus> changedAssets,
                @NonNull ImmutableMap<RelativeFile, FileStatus> changedAndroidResources,
                @NonNull ImmutableMap<RelativeFile, FileStatus> changedNLibs)
                throws IOException {
    
            ImmutableMap.Builder<RelativeFile, FileStatus> javaResourcesForApk =
                    ImmutableMap.builder();
            javaResourcesForApk.putAll(changedJavaResources);
    
            
            final ImmutableMap<RelativeFile, FileStatus> dexFilesToPackage = changedDex;
    
            ...
    
            // 1、创建packager 对象
            try (IncrementalPackager packager =
                    new IncrementalPackagerBuilder()
                            .withOutputFile(outputFile)
                            .withSigning(signingConfig)
                            .withCreatedBy(getBuilder().getCreatedBy())
                            .withMinSdk(getMinSdkVersion())
                            // TODO: allow extra metadata to be saved in the split scope to avoid
                            // reparsing
                            // these manifest files.
                            .withNativeLibraryPackagingMode(
                                    PackagingUtils.getNativeLibrariesLibrariesPackagingMode(
                                            manifestForSplit.getOutputFile()))
                            .withNoCompressPredicate(
                                    PackagingUtils.getNoCompressPredicate(
                                            aaptOptionsNoCompress, manifestForSplit.getOutputFile()))
                            .withIntermediateDir(incrementalDirForSplit)
                            .withProject(getProject())
                            .withDebuggableBuild(getDebugBuild())
                            .withAcceptedAbis(
                                    abiFilter == null ? abiFilters : ImmutableSet.of(abiFilter))
                            .withJniDebuggableBuild(getJniDebugBuild())
                            .build()) {
                // 2、更新package相应的内容
                packager.updateDex(dexFilesToPackage);
                packager.updateJavaResources(changedJavaResources);
                packager.updateAssets(changedAssets);
                packager.updateAndroidResources(changedAndroidResources);
                packager.updateNativeLibraries(changedNLibs);
                ...
        }
    

    代码也很简单就是创建IncrementalPackager 对象packager,然后对dex、javares、assets、AndroidResources、NativeLib执行更新操作,也就是写入操作。执行这些update操作,最终都是调用了IncrementalPackager种的update()方法。代码如下:

        /**
         * Updates files in the archive.
         *
         * @param updates the updates to perform
         * @throws IOException failed to update the archive
         */
        private void updateFiles(@NonNull Set<PackagedFileUpdate> updates) throws IOException {
            ...
    
            for (File arch : Sets.newHashSet(archives)) {
                mApkCreator.writeZip(arch, pathNameMap::get, name -> !names.contains(name));
            }
        }
    

    看最后一句mApkCreator.writeZip(),上面的update操作,都通过mAplCreator写入了Apk包中。

    至此在debug模式下生成apk的所有tasks都已经分析完毕。对系列文章能看到这里来的,我相信对这个android的编译过程基本有了比较清晰的认识了。
    基本的编译过程分析完了,后续将再此系列文章基础上再出两个主体:1、《Gradle tool 3.0 增量编译》;2、《MutilDex拆分过程详细解析》。

    相关文章

      网友评论

        本文标题:Android gradle打包涉及task源码解析(六)

        本文链接:https://www.haomeiwen.com/subject/ictfkqtx.html