打包aar并发布到远程_AS 3.1 多library合并打包成aar的正确方式(fat-aar)

姬衡
2023-12-01

/*** 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 */

importcom.android.annotations.NonNullimportcom.android.manifmerger.ManifestMerger2importcom.android.manifmerger.ManifestMerger2.Invokerimportcom.android.manifmerger.ManifestMerger2.MergeTypeimportcom.android.manifmerger.MergingReportimportcom.android.manifmerger.PlaceholderEncoderimportcom.android.manifmerger.XmlDocumentimportcom.android.utils.ILoggerimportcom.google.common.base.Charsetsimportcom.google.common.io.Files/*** Fat AAR Lib generator v 0.2.1

* Target Gradle Version :: 2.2.0

*

* Latest version available athttps://github.com/adwiv/android-fat-aar* Please report issues athttps://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 ! :-)*/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 = newArrayList()//Paths to embedded aar projects//合并aar路径

ext.embeddedAarDirs = newArrayList()//Embedded aar files dependencies//合并aar文件

ext.embeddedAarFiles = new ArrayList()//List of embedded R classes//合并R文件

ext.embeddedRClasses = newArrayList()//Change backslash to forward slash on windows//设置全局参数

ext.build_dir = buildDir.path.replace(File.separator, '/');

ext.root_dir= project.rootDir.absolutePath.replace(File.separator, '/');

ext.exploded_aar_dir= "$build_dir/intermediates/exploded-aar";

ext.classs_release_dir= "$build_dir/intermediates/classes/release";

ext.bundle_release_dir= "$build_dir/intermediates/bundles/release";

ext.manifest_aaapt_dir= "$build_dir/intermediates/manifests/aapt/release";

ext.generated_rsrc_dir= "$build_dir/generated/source/r/release";

ext.base_r2x_dir= "$build_dir/fat-aar/release/";

def gradleVersionStr=GradleVersion.current().getVersion();

ext.gradleApiVersion= gradleVersionStr.substring(0, gradleVersionStr.lastIndexOf(".")).toFloat();

println"Gradle version: " +gradleVersionStr;

afterEvaluate {//the list of dependency must be reversed to use the right overlay order.//获取所有的依赖

def dependencies = newArrayList(configurations.embedded.resolvedConfiguration.firstLevelModuleDependencies)//反向遍历

dependencies.reverseEach {

def aarPath;if (gradleApiVersion >= 2.3f)

aarPath= "${root_dir}/${it.moduleName}/build/outputs/default"

elseaarPath= "${exploded_aar_dir}/${it.moduleGroup}/${it.moduleName}/${it.moduleVersion}"

//遍历每个module

it.moduleArtifacts.each {

artifact->println"ARTIFACT 3 : "println artifact//处理aar

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

def artifactPath =artifact.fileif (!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依赖prepareReleaseDependencies

embedAssets.dependsOn prepareReleaseDependencies//Embed Resources by overwriting the inputResourceSets

packageReleaseResources.dependsOn embedLibraryResources

embedLibraryResources.dependsOn prepareReleaseDependencies//Embed JNI Libraries

bundleRelease.dependsOn embedJniLibsif (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

bundleRelease.dependsOn embedManifests

embedManifests.dependsOn processReleaseManifest//Merge proguard files

embedLibraryResources.dependsOn embedProguard

embedProguard.dependsOn prepareReleaseDependencies//Generate R.java files

compileReleaseJavaWithJavac.dependsOn generateRJava

generateRJava.dependsOn processReleaseResources//Bundle the java classes

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)

}

}privateList 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 = newArrayList(inputResourceSet)

println"getMergedInputResourceSets"println embeddedAarDirs//遍历这个aar路径

embeddedAarDirs.each { aarPath ->

try{

println aarPath

def resnameif (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 endIndexif (startIndex < 1 || endIndex < 1)return;

resname= aarPath.substring(startIndex, endIndex).replace('/', ':')

}elseresname= (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();throwe;

}

}returnnewInputResourceSet

}/*** 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->println"当前的aarPath为:" + aarPath + " $aarPath"

if ("$aarPath".endsWith("library1/build/outputs/default")|| "$aarPath".endsWith("library2/build/outputs/default")|| "$aarPath".endsWith("library3/build/outputs/default")

) {

println"进入了" +aarPath

android.sourceSets.main.assets.srcDirs+= file("$aarPath/assets")

}

}

}/*** Merge proguard.txt files from all library modules

*@authorMarian 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();throwe;

}

}

}

task generateRJava<

println"Running FAT-AAR Task :generateRJava"

//Now generate the R.java file for each embedded dependency

def mainManifestFile =android.sourceSets.main.manifest.srcFile;

def libPackageName= "";if(mainManifestFile.exists()) {

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

embeddedAarDirs.each { aarPath->

//if("$aarPath".endsWith(""))

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

manifestFile= file("./src/main/AndroidManifest.xml");

}if(manifestFile.exists()) {

def aarManifest= newXmlParser().parse(manifestFile);

def aarPackageName= aarManifest.@packageString packagePath= aarPackageName.replace('.', '/')//Generate the R.java file and map to current project's R.java//This will recreate the class file

def rTxt = file("$aarPath/R.txt")

def rMap= newConfigObject()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"}

}

}

task collectRClass<

println"COLLECTRCLASS"delete base_r2x_dir

mkdir base_r2x_dir

copy {

from classs_release_dir

include embeddedRClasses

into base_r2x_dir

}

}

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*/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

def jar_dirif (gradleApiVersion >= 2.3f)

jar_dir= "$aarPath"

elsejar_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

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

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.*/task embedJniLibs<

println"Running FAT-AAR Task :embedJniLibs"embeddedAarDirs.each { aarPath->println"======= Copying JNI from $aarPath"

//Copy JNI Folders

/*if ("$aarPath".endsWith("library3/unspecified")) {

copy {

println "进入library3拿jni中文件"

from fileTree(dir: "$aarPath/jni")

into file("$bundle_release_dir/jni")

}

}*/copy {

println"进入library3拿jni中文件"from fileTree(dir:"$aarPath/jni")

into file("$bundle_release_dir/jni")

}

}

}

task embedManifests<

println"Running FAT-AAR Task :embedManifests"ILogger mLogger= newMiLogger()

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(newFile[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) {caseMergingReport.Result.WARNING:

mergingReport.log(mLogger);//fall through since these are just warnings.

caseMergingReport.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()) {newPlaceholderEncoder().visit(xmlDocument);

save(xmlDocument, aaptManifest);

mLogger.info("Merged aapt safe manifest saved to " +aaptManifest);

}break;caseMergingReport.Result.ERROR:

mergingReport.log(mLogger);throw newRuntimeException(mergingReport.getReportString());default:throw new RuntimeException("Unhandled result type : " +mergingReport.getResult());

}

}catch(RuntimeException e) {//Unacceptable error

e.printStackTrace()throw newRuntimeException(e);

}

}private voidsave(XmlDocument xmlDocument, File out) {try{

Files.write(xmlDocument.prettyPrint(), out, Charsets.UTF_8);

}catch(IOException e) {throw newRuntimeException(e);

}

}class MiLogger implementsILogger {

@Overridevoiderror(

@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)

}

@Overridevoidwarning(@NonNull String msgFormat, Object... args) {

System.err.println(String.format("========== WARNING : " +msgFormat, args))

}

@Overridevoidinfo(@NonNull String msgFormat, Object... args) {

System.out.println(String.format("========== INFO : " +msgFormat, args))

}

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

}

}

 类似资料: