gradle脚本合并libs ,manifest, jnilibs, assets , dependicies

最近在合并modules或者aar , jar等工作上遇到了一些问题。查找各种文章,最后找到一些解决思路和办法。
希望能帮助到大家。下面这个是早期作者的处理libs, 清单文件等合并的办法。

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

/**

buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:manifest-merger:25.2.0'
}
}

configurations {
embedded
}

dependencies {
compile configurations.embedded
}

// Paths to embedded jar files
ext.embeddedJars = new ArrayList<String>()
// Paths to embedded aar projects
ext.embeddedAarDirs = new ArrayList<String>()
// List of embedded R classes
ext.embeddedRClasses = new ArrayList<String>()

// Change backslash to forward slash on windows
ext.build_dir = buildDir.path.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/";

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 = "{exploded_aar_dir}/{it.moduleGroup}/{it.moduleName}/{it.moduleVersion}"
it.moduleArtifacts.each {
artifact ->
if (artifact.type == 'aar') {
if (!embeddedAarDirs.contains(aarPath)) {
embeddedAarDirs.add(aarPath)
}
} else if (artifact.type == '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
    bundleRelease.dependsOn embedJniLibs
    embedJniLibs.dependsOn transformNative_libsWithSyncJniLibsForRelease

    // 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)
}

}

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)

embeddedAarDirs.each { aarPath ->
    try {
        def 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
        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(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
def libPackageName = new XmlParser().parse(android.sourceSets.main.manifest.srcFile).@package

embeddedAarDirs.each { aarPath ->

    def aarManifest = new XmlParser().parse(file("$aarPath/AndroidManifest.xml"));
    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
    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"
}

}

task 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) {
destinationDir file("$bundle_release_dir/libs/")
from 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
    copy {
    from zipTree("$aarPath/jars/classes.jar")
    into classs_release_dir
    }

     // Copy all additional jar files to bundle lib
     FileTree jars = fileTree(dir: "$aarPath/jars", include: '*.jar', exclude: 'classes.jar')
     jars += fileTree(dir: "$aarPath/jars/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/jni" // Copy JNI Folders copy { from fileTree(dir: "aarPath/jni")
    into file("$bundle_release_dir/jni")
    }
    }
    }

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

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

embeddedAarDirs.each { aarPath ->
    if (!libraryManifests.contains(aarPath)) {
        libraryManifests.add(file("$aarPath/AndroidManifest.xml"))
    }
}

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

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

}

当然综合各处,现在也有很多人在用此版本的方案处理:https://github.com/kezong/fat-aar-android
里面有中文文档。

欢迎大家提供更多的解决办法。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,591评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,448评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,823评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,204评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,228评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,190评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,078评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,923评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,334评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,550评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,727评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,428评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,022评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,672评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,826评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,734评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,619评论 2 354

推荐阅读更多精彩内容