android fat-aar.gradle中文注释

版权声明:本文为博主原创文章,未经博主允许不得转载,请尊重知识产权 https://blog.csdn.net/yishichangan1/article/details/78416193
/**
 * This is free and unencumbered software released into the public domain.
 Anyone is free to copy, modify, publish, use, compile, sell, or
 distribute this software, either in source code form or as a compiled
 binary, for any purpose, commercial or non-commercial, and by any
 means.
 In jurisdictions that recognize copyright laws, the author or authors
 of this software dedicate any and all copyright interest in the
 software to the public domain. We make this dedication for the benefit
 of the public at large and to the detriment of our heirs and
 successors. We intend this dedication to be an overt act of
 relinquishment in perpetuity of all present and future rights to this
 software under copyright law.
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 OTHER DEALINGS IN THE SOFTWARE.
 For more information, please refer to <http://unlicense.org/>
 */
译文:
/** 
    这是发布到公共领域的可自由支配的软件。
    任何人都可以以源代码形式或作为编译的二进制文件,以任何目的,商业或非商业性的方式,以任何方式,复制,修改,发布,使用,编译,销售或分发本软件。
    在承认版权法的司法管辖区,本软件的作者将软件的任何版权利益全部归属于公有。 我们为了广大公众的利益而作出这种奉献,损害了我们的继承人。 我们打算将这一奉献作为本软件根据版权法永久放弃现有和未来版权的声明。
    该软件“按原样”提供,不附带明示或暗示的任何形式的保证,包括但不限于适销性,适用于特定用途和不侵权的保证。 在任何情况下下,作者都不承担任何责任,包括任何索赔,损坏或其他,不管是合同,侵权或其他原因,使用中或使用后其他交易软件中。
    有关更多信息,请参阅<http://unlicense.org/>
 */

代码内容:

import com.android.annotations.NonNull
import com.android.manifmerger.ManifestMerger2
import com.android.manifmerger.ManifestMerger2.Invoker
import com.android.manifmerger.ManifestMerger2.MergeType
import com.android.manifmerger.MergingReport
import com.android.manifmerger.PlaceholderEncoder
import com.android.manifmerger.XmlDocument
import com.android.utils.ILogger
import com.google.common.base.Charsets
import com.google.common.io.Files
/**
 * Fat AAR Lib generator v 0.2.1
 * Target Gradle Version :: 2.2.0
 *
 * Latest version available at https://github.com/adwiv/android-fat-aar
 * Please report issues at https://github.com/adwiv/android-fat-aar/issues
 *
 * This code is in public domain.
 *
 * Use at your own risk and only if you understand what it does. You have been warned ! :-)
 */
译文:
/**
    fat-aar库v0.2.1版本
    目标gradle版本:2.2.0
    最新版本可以到https://github.com/adwiv/android-fat-aar下载
    报告问题请到https://github.com/adwiv/android-fat-aar/issues
    此代码是公开的。
    最后提醒一下,风险自行承担[(* ̄︶ ̄)]。
 */
buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:manifest-merger:25.3.2'
    }
}

configurations {
    embedded
}

dependencies {
    compile configurations.embedded
}
// Paths to embedded jar files
//需要打包的jar文件的路径
ext.embeddedJars = new ArrayList()
// Paths to embedded aar projects
//需要打包aar的工程路径
ext.embeddedAarDirs = new ArrayList()
// Embedded aar files dependencies
//需要打包的aar的文件依赖
ext.embeddedAarFiles = new ArrayList<ResolvedArtifact>()
// List of embedded R classes
//R类的列表
ext.embeddedRClasses = new ArrayList()
// Change backslash to forward slash on windows
//如果要在windows上运行需要改变反斜杠\
ext.build_dir = buildDir.path.replace(File.separator, '/');
//扩展的build目录=当前build目录
ext.root_dir = project.rootDir.absolutePath.replace(File.separator, '/');
//扩展的根目录=当前工程的根目录的绝对路径
ext.exploded_aar_dir = "$build_dir/intermediates/exploded-aar";
//扩展的aar所在目录=build目录/intermediates/exploded-aar
ext.classs_release_dir = "$build_dir/intermediates/classes/release";
//扩展的类所在目录=build目录/intermediates/classes/release
ext.bundle_release_dir = "$build_dir/intermediates/bundles/release";
//扩展的bundle所在目录=build目录/intermediates/bundles/release
ext.manifest_aaapt_dir = "$build_dir/intermediates/manifests/aapt/release";
//扩展的manifest所在目录=build目录/intermediates/manifests/aapt/release
ext.generated_rsrc_dir = "$build_dir/generated/source/r/release";
//生成的资源文件目录=build目录/generated/source/r/release
ext.base_r2x_dir = "$build_dir/fat-aar/release/";
//基本的r2x目录=build目录/fat-aar/release

这里写图片描述

//获取gradle版本信息
def gradleVersionStr = GradleVersion.current().getVersion();
ext.gradleApiVersion = gradleVersionStr.substring(0, gradleVersionStr.lastIndexOf(".")).toFloat();
//打印Gradle的版本信息
println "Gradle version: " + gradleVersionStr;

afterEvaluate {
    // the list of dependency must be reversed to use the right overlay order.
    //依赖关系列表必须逆序才能使用正确的覆盖顺序。
    def dependencies = new ArrayList(configurations.embedded.resolvedConfiguration.firstLevelModuleDependencies)
    //开始逆序
    dependencies.reverseEach {

        def aarPath;
        if (gradleApiVersion >= 2.3f)
            aarPath = "${root_dir}/${it.moduleName}/build/intermediates/bundles/default"
        else
            aarPath = "${exploded_aar_dir}/${it.moduleGroup}/${it.moduleName}/${it.moduleVersion}"
//如果编译版本高于2.3 aar目录=根目录/模块名/build/intermediates/bundles/default
//否则 aar目录=上面的扩展aar目录/模块组/模块名/模块版本
        it.moduleArtifacts.each {
            artifact ->

                println "ARTIFACT 3 : "
                println artifact
//如果组件类型是aar文件,如果上面的需要打包的aar文件列表中没有,就直接加入,如果aar文件夹下没有,如果是个文件就从Zip包中直接复制到aarpath中,最后将aarpath加入文件夹路径中
                if (artifact.type == 'aar') {
                    if (!embeddedAarFiles.contains(artifact)) {
                        embeddedAarFiles.add(artifact)
                    }
                    if (!embeddedAarDirs.contains(aarPath)) {
                        if( artifact.file.isFile() ){
                            println artifact.file
                            println aarPath

                            copy {
                                from zipTree( artifact.file )
                                into aarPath
                            }
                        }
                        embeddedAarDirs.add(aarPath)
                    }
                } else if (artifact.type == 'jar') {
//如果是jar类型,如果jar文件列表中没有,直接加入
//如果既不是aar也不是jar类型就抛出异常“不能处理该种文件类型”
                    def artifactPath = artifact.file
                    if (!embeddedJars.contains(artifactPath))
                        embeddedJars.add(artifactPath)
                } else {
                    throw new Exception("Unhandled Artifact of type ${artifact.type}")
                }
        }
    }
    if (dependencies.size() > 0) {
        // Merge Assets归并目录
        generateReleaseAssets.dependsOn embedAssets
        embedAssets.dependsOn prepareReleaseDependencies

        // Embed Resources by overwriting the inputResourceSets覆盖输入资源集合来嵌入资源文件
        packageReleaseResources.dependsOn embedLibraryResources
        embedLibraryResources.dependsOn prepareReleaseDependencies

        // Embed JNI Libraries嵌入jni库
        bundleRelease.dependsOn embedJniLibs

        if(gradleApiVersion >= 2.3f) {

            embedJniLibs.dependsOn transformNativeLibsWithSyncJniLibsForRelease
            ext.bundle_release_dir = "$build_dir/intermediates/bundles/default"
        }else{
            embedJniLibs.dependsOn transformNative_libsWithSyncJniLibsForRelease
            ext.bundle_release_dir = "$build_dir/intermediates/bundles/release";
        }

        // Merge Embedded Manifests归并嵌入的manifest文件
        bundleRelease.dependsOn embedManifests
        embedManifests.dependsOn processReleaseManifest

        // Merge proguard files归并混淆文件
        embedLibraryResources.dependsOn embedProguard
        embedProguard.dependsOn prepareReleaseDependencies

        // Generate R.java files生成R.java文件
        compileReleaseJavaWithJavac.dependsOn generateRJava
        generateRJava.dependsOn processReleaseResources

        // Bundle the java classes继承Java类文件
        bundleRelease.dependsOn embedJavaJars
        embedJavaJars.dependsOn compileReleaseJavaWithJavac

        // If proguard is enabled, run the tasks that bundleRelease should depend on before proguard如果需要使用混淆,那么应该在混淆之前运行依赖项
        if (tasks.findByPath('proguardRelease') != null) {
            proguardRelease.dependsOn embedJavaJars
        } else if (tasks.findByPath('transformClassesAndResourcesWithProguardForRelease') != null) {
            transformClassesAndResourcesWithProguardForRelease.dependsOn embedJavaJars
        }
    }
}
//嵌入库文件资源
task embedLibraryResources << {
    println "Running FAT-AAR Task :embedLibraryResources"

    def oldInputResourceSet = packageReleaseResources.inputResourceSets
    packageReleaseResources.conventionMapping.map("inputResourceSets") {
        getMergedInputResourceSets(oldInputResourceSet)
    }
}

private List getMergedInputResourceSets(List inputResourceSet) {
    //We need to do this trickery here since the class declared here and that used by the runtime
    //are different and results in class cast error因为类的声明和运行时使用的类是不同的,可能会产生一个强制转换异常,所以需要在这里做一个类欺骗
    def ResourceSetClass = inputResourceSet.get(0).class

    List newInputResourceSet = new ArrayList(inputResourceSet)

    println "getMergedInputResourceSets"

    println embeddedAarDirs
    embeddedAarDirs.each { aarPath ->
        try {
            println aarPath
            def resname
            if (gradleApiVersion >= 2.3f) {
                def parentProject = project.rootProject.name.toString()
                println "parent: "
                println parentProject

                def startIndex = aarPath.indexOf('/' + parentProject)
                def endIndex = aarPath.indexOf('/build/')

                println "start"
                println startIndex
                println "end"
                println endIndex
                if (startIndex < 1 || endIndex < 1)
                    return;
                resname = aarPath.substring(startIndex, endIndex).replace('/', ':')
            }
            else
                resname = (aarPath.split(exploded_aar_dir)[1]).replace('/', ':');
            def rs = ResourceSetClass.newInstance([resname, true] as Object[])
            rs.addSource(file("$aarPath/res"))
            println "ResourceSet is " + rs
            println resname
            newInputResourceSet += rs
        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        }
    }

    return newInputResourceSet
}

/**
 * Assets are simple files, so just adding them to source set seems to work.
 * 目录就是简单的文件,所以只要把他们加入资源文件工作就行了
 */
task embedAssets << {
    println "Running FAT-AAR Task :embedAssets"
    embeddedAarDirs.each { aarPath ->
        // Merge Assets归并目录
        android.sourceSets.main.assets.srcDirs += file("$aarPath/assets")
    }
}

/**
 * Merge proguard.txt files from all library modules
 * 从所有的库模块中归并混淆文件
 * @author Marian Klühspies
 */
task embedProguard << {
    println "Running FAT-AAR Task :embedProguard"

    def proguardRelease = file("$bundle_release_dir/proguard.txt")
    embeddedAarDirs.each { aarPath ->
        try {
            def proguardLibFile = file("$aarPath/proguard.txt")
            if (proguardLibFile.exists())
                proguardRelease.append("\n" + proguardLibFile.text)
        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        }
    }
}


task generateRJava << {
    println "Running FAT-AAR Task :generateRJava"

    // Now generate the R.java file for each embedded dependency为每个嵌入的依赖生成R.java文件
    def mainManifestFile = android.sourceSets.main.manifest.srcFile;
    def libPackageName = "";

    if(mainManifestFile.exists()) {

        libPackageName = new XmlParser().parse(mainManifestFile).@package
    }

    embeddedAarDirs.each { aarPath ->

        def manifestFile = file("$aarPath/AndroidManifest.xml");
        if(!manifestFile.exists()) {
            manifestFile = file("./src/main/AndroidManifest.xml");
        }

        if(manifestFile.exists()) {
            def aarManifest = new XmlParser().parse(manifestFile);
            def aarPackageName = aarManifest.@package

            String packagePath = aarPackageName.replace('.', '/')

            // Generate the R.java file and map to current project's R.java
            // This will recreate the class file生成R.java文件然后映射到现在工程的R.java文件中,这个操作会重新生成类文件
            def rTxt = file("$aarPath/R.txt")
            def rMap = new ConfigObject()

            if (rTxt.exists()) {
                rTxt.eachLine {
                    line ->
                        //noinspection GroovyUnusedAssignment
                        def (type, subclass, name, value) = line.tokenize(' ')
                        rMap[subclass].putAt(name, type)
                }
            }

            def sb = "package $aarPackageName;" << '\n' << '\n'
            sb << 'public final class R {' << '\n'

            rMap.each {
                subclass, values ->
                    sb << "  public static final class $subclass {" << '\n'
                    values.each {
                        name, type ->
                            sb << "    public static $type $name = ${libPackageName}.R.${subclass}.${name};" << '\n'
                    }
                    sb << "    }" << '\n'
            }

            sb << '}' << '\n'

            mkdir("$generated_rsrc_dir/$packagePath")
            file("$generated_rsrc_dir/$packagePath/R.java").write(sb.toString())

            embeddedRClasses += "$packagePath/R.class"
            embeddedRClasses += "$packagePath/R\$*.class"
        }

    }
}
//收集R.class文件
task collectRClass << {
    println "COLLECTRCLASS"
    delete base_r2x_dir
    mkdir base_r2x_dir

    copy {
        from classs_release_dir
        include embeddedRClasses
        into base_r2x_dir
    }
}
//嵌入R.class
task embedRClass(type: org.gradle.jvm.tasks.Jar, dependsOn: collectRClass) {
    println "EMBED R CLASS"

    destinationDir file("$bundle_release_dir/libs/")
    println destinationDir
    from base_r2x_dir
    println base_r2x_dir
}

/**
 * To embed the class files, we need to change the R.class to X.class, so we explode it in another
 * location, proguard it to modify R to X, and then finally copy it to build location
 * 为了嵌入类文件,我们需要改变R.class到X.class,所以我们把它解压在另外一二位置,混淆它并且修改R为X,最后把它拷贝到build位置
 */
task embedJavaJars(dependsOn: embedRClass) << {
    println "Running FAT-AAR Task :embedJavaJars"

    embeddedAarDirs.each { aarPath ->

        // Explode all classes.jar files to classes so that they can be proguarded解压所有class.jar文件,这样就能混淆了
        def jar_dir
        if (gradleApiVersion >= 2.3f)
            jar_dir = "$aarPath"
        else
            jar_dir = "$aarPath/jars"

        if(embeddedAarFiles.size() > 0){

            embeddedAarFiles.each {
                artifact ->
                    FileTree aarFileTree = zipTree(artifact.file.getAbsolutePath());

                    def aarFile = aarFileTree.files.find { it.name.contains("classes.jar") }

                    copy {
                        from zipTree(aarFile)
                        into classs_release_dir
                    }
            }

        }else{

            println jar_dir
            println classs_release_dir
            println bundle_release_dir
            println embeddedJars

            copy {
                from zipTree(jar_dir + "/classes.jar")
                into classs_release_dir
            }
        }

        // Copy all additional jar files to bundle lib复制所有的额外jar文件到bundle lib目录
        FileTree jars = fileTree(dir: jar_dir, include: '*.jar', exclude: 'classes.jar')
        jars += fileTree(dir: jar_dir + "/libs", include: '*.jar')
        jars += fileTree(dir: "$aarPath/libs", include: '*.jar')

        copy {
            from jars
            into file("$bundle_release_dir/libs")
        }

        // Copy all embedded jar files to bundle lib复制所有的嵌入的jar文件到bundle lib
        copy {
            from embeddedJars
            into file("$bundle_release_dir/libs")
        }
    }
}

/**
 * For some reason, adding to the jniLibs source set does not work. So we simply copy all files.
 * 因为某些原因,添加到jni lib的资源不起作用,所以我们只能简单地拷贝进去
 */
task embedJniLibs << {
    println "Running FAT-AAR Task :embedJniLibs"

    embeddedAarDirs.each { aarPath ->
        println "======= Copying JNI from $aarPath/jni"
        // Copy JNI Folders
        copy {
            from fileTree(dir: "$aarPath/jni")
            into file("$bundle_release_dir/jni")
        }
    }
}
//合并嵌入manifest文件
task embedManifests << {
    println "Running FAT-AAR Task :embedManifests"

    ILogger mLogger = new MiLogger()
    List libraryManifests = new ArrayList<>()

    embeddedAarDirs.each { aarPath ->
        File dependencyManifest = file("$aarPath/AndroidManifest.xml")

        if (!libraryManifests.contains(aarPath) && dependencyManifest.exists()) {
            libraryManifests.add(dependencyManifest)
        }
    }

    File reportFile = file("${build_dir}/embedManifestReport.txt")

    File origManifest = file("$bundle_release_dir/AndroidManifest.xml")
    File copyManifest = file("$bundle_release_dir/AndroidManifest.orig.xml")
    File aaptManifest = file("$manifest_aaapt_dir/AndroidManifest.xml")

    if(!origManifest.exists()) {
        origManifest = file("./src/main/AndroidManifest.xml")
    }

    if(!origManifest.exists()) {
        return;
    }

    copy {
        from origManifest.parentFile
        into copyManifest.parentFile
        include origManifest.name
        rename(origManifest.name, copyManifest.name)
    }

    try {
        Invoker manifestMergerInvoker = ManifestMerger2.newMerger(copyManifest, mLogger, MergeType.APPLICATION)

        manifestMergerInvoker.addLibraryManifests(libraryManifests.toArray(new File[libraryManifests.size()]))

        // manifestMergerInvoker.setPlaceHolderValues(placeHolders)
        manifestMergerInvoker.setMergeReportFile(reportFile);

        MergingReport mergingReport = manifestMergerInvoker.merge();

        mLogger.info("Merging result:" + mergingReport.getResult());
        MergingReport.Result result = mergingReport.getResult();
        switch (result) {
            case MergingReport.Result.WARNING:
                mergingReport.log(mLogger);
        // fall through since these are just warnings.
            case MergingReport.Result.SUCCESS:
                XmlDocument xmlDocument = mergingReport.getMergedXmlDocument(MergingReport.MergedManifestKind.MERGED);
                try {
                    String annotatedDocument = mergingReport.getActions().blame(xmlDocument);
                    mLogger.verbose(annotatedDocument);
                } catch (Exception e) {
                    mLogger.error(e, "cannot print resulting xml");
                }
                save(xmlDocument, origManifest);
                mLogger.info("Merged manifest saved to " + origManifest);
                if (aaptManifest.exists()) {
                    new PlaceholderEncoder().visit(xmlDocument);
                    save(xmlDocument, aaptManifest);
                    mLogger.info("Merged aapt safe manifest saved to " + aaptManifest);
                }
                break;
            case MergingReport.Result.ERROR:
                mergingReport.log(mLogger);
                throw new RuntimeException(mergingReport.getReportString());
            default:
                throw new RuntimeException("Unhandled result type : " + mergingReport.getResult());
        }
    } catch (RuntimeException e) {
        // Unacceptable error
        e.printStackTrace()
        throw new RuntimeException(e);
    }
}

private void save(XmlDocument xmlDocument, File out) {
    try {
        Files.write(xmlDocument.prettyPrint(), out, Charsets.UTF_8);
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}

class MiLogger implements ILogger {

    @Override
    void error(
            @com.android.annotations.Nullable Throwable t,
            @com.android.annotations.Nullable String msgFormat, Object... args) {
        System.err.println(String.format("========== ERROR : " + msgFormat, args))
        if (t) t.printStackTrace(System.err)
    }

    @Override
    void warning(@NonNull String msgFormat, Object... args) {
        System.err.println(String.format("========== WARNING : " + msgFormat, args))
    }

    @Override
    void info(@NonNull String msgFormat, Object... args) {
        System.out.println(String.format("========== INFO : " + msgFormat, args))
    }

    @Override
    void verbose(@NonNull String msgFormat, Object... args) {
        // System.out.println(String.format("========== DEBUG : " + msgFormat, args))
    }
}

猜你喜欢

转载自blog.csdn.net/yishichangan1/article/details/78416193