fat-aar地址:github.com/adwiv/andro…java
Gradle script that allows you to merge and embed dependencies in generated aar file.
複製代碼
根據官方介紹,fat-aar是一個容許你合併和嵌入依賴關係到生成的aar文件的gradle腳本,通俗點說,fat-aar的主要工做就是將project中內部所依賴的aar下載到本地,而後一塊兒發佈aar到maven庫,外部項目依賴aar時不用去下載project內部依賴的aarandroid
咱們發佈aar時,會帶有一個aarName-x.x.x.pom文件(aarName是aar的名字,x.x.x是版本號),這個pom文件裏面定義了咱們aar內部依賴的aar,外部project依賴該aar會在編譯時去下載其內部依賴的aar;對外發布的aar中若是有依賴內網maven庫中的aar,會因沒法鏈接內部maven庫致使下載內部aar失敗,最終編譯失敗。git
因此在這裏引入fat-aar解決方案,在對外發布aar時將其內部依賴的aar所有下載到本地,發佈時一塊兒打包進去,外部project在編譯時不用去內部maven庫下載github
首先了解下aar包結構bash
aar是Android Library Project的二進制文件包,文件的擴展名是aar,其實文件自己就是一個簡單的Zip文件,解壓後有如下幾種類型,相信Android開發同窗都不會陌生maven
備註:R.txt文件是aapt --output -text -symbols輸出,aapt相關細節這裏再也不敘述學習
解決思路:合併aargradle
如上圖所示,將A依賴的B.aar、C.aar、D.aar合併到A,生成新的A.aarui
將依賴的外部aar和內部module(能夠當作aar)輸出的N個aar文件進行合併,這樣原來A模塊的調用者接入方式保持不變,並且在依賴A時沒必要再從新下載A內部依賴的其餘aar,能夠提供給外部項目使用而避免訪問內部maven庫的場景lua
參考上面aar包結構形式,fat-aar合併主要過程爲:
首先了解一下gradle構建流程,gradle執行主要分爲三個過程:
fat-aar就是在配置階段完成進入afterEvaluate回調中,而後執行合併內部依賴aar的操做,咱們在對外發布aar時須要定義Task uploadArchives(如何上傳aar至maven請自行了解),而uploadArchives內部依賴assembleRelease執行結果
fat-aar中定義各子Task的執行流程以下:
// 合併Assets
generateReleaseAssets.dependsOn embedAssets
embedAssets.dependsOn prepareReleaseDependencies
// 合併Resources經過重寫inputResourceSets
packageReleaseResources.dependsOn embedLibraryResources
embedLibraryResources.dependsOn prepareReleaseDependencies
// 合併JNI So庫
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";
}
// 合併Manifests
bundleRelease.dependsOn embedManifests
embedManifests.dependsOn processReleaseManifest
// 合併proguard
embedLibraryResources.dependsOn embedProguard
embedProguard.dependsOn prepareReleaseDependencies
// 生成R.java
compileReleaseJavaWithJavac.dependsOn generateRJava
generateRJava.dependsOn processReleaseResources
// 把R.java打包進Jar包
bundleRelease.dependsOn embedJavaJars
embedJavaJars.dependsOn compileReleaseJavaWithJavac
// 若是使用混淆, bundleRelease必須在混淆以前執行
if (tasks.findByPath('proguardRelease') != null) {
proguardRelease.dependsOn embedJavaJars
} else if (tasks.findByPath('transformClassesAndResourcesWithProguardForRelease') != null) {
transformClassesAndResourcesWithProguardForRelease.dependsOn embedJavaJars
}
複製代碼
想要理解fat-aar執行流程,首先須要知道dependsOn是什麼,dependsOn用來指定Task之間的依賴關係,好比TaskA.depensOn TaskB表示TaskA在TaskB以後執行
與dependsOn相反的mustRunAfter,有興趣的同窗能夠自行了解下
fat-aar執行過程依賴assembleRelease任務,定義了embedAssets、embedLibraryResources、embedJniLibs、embedManifests、embedProguard、generateRJava、embedJavaJars多個Task,而這些Task的執行順序與assembleRelease內部執行順序相關
先來了解一下assembleRelease的執行順序:
:preBuild
:preReleaseBuild
:checkReleaseManifest
:prepareReleaseDependencies
:compileReleaseAidl
:compileReleaseNdk
:compileReleaseRenderscript
:generateReleaseBuildConfig
:generateReleaseResValues
:generateReleaseResources
:mergeReleaseResources
:processReleaseManifest
:processReleaseResources
:generateReleaseSources
:incrementalReleaseJavaCompilationSafeguard
:javaPreCompileRelease
:compileReleaseJavaWithJavac
:extractReleaseAnnotations
:mergeReleaseShaders
:compileReleaseShaders
:generateReleaseAssets
:mergeReleaseAssets
:mergeReleaseProguardFiles
:packageReleaseRenderscript
:packageReleaseResources
:processReleaseJavaRes
:transformResourcesWithMergeJavaResForRelease
:transformClassesAndResourcesWithSyncLibJarsForRelease
:mergeReleaseJniLibFolders
:transformNativeLibsWithMergeJniLibsForRelease
:transformNativeLibsWithSyncJniLibsForRelease
:bundleRelease
:compileReleaseSources
:assembleRelease
複製代碼
注:上面代碼基本上列舉了Gradle構建Android項目時執行assembleRelease的全部Task,Lint、Test等非必需Task除外
根據上面assembleRelease的執行順序,下面逐個分析fat-aar中各Task的執行順序:
綜上畫出下面的流程圖,能夠幫助咱們更好的理解fat-aar的工做流程(各子Task的執行順序)
備註:
理解了fat-aar工做流程以後,其實就是在gradle構建過程當中插入不一樣的Task來實現embedded依賴的aar下載到本地,而後一塊兒發佈到maven庫,embedAssets、embedLibraryResources、embededJniLibs、embedProguard、embedManifests都是進行資源的合併,主要思想是資源路徑的追加或者拷貝,比較簡單,這裏主要分析aar的R.java生成和打包過程
下面咱們來介紹一下generateRJava這個Task,generateRJava的目的是根據aar中的R.txt文件生成對應的R.java文件;項目build過程當中會在/generated/source/r生成R.java文件,generateRJava其實就是模擬這個過程,而build過程當中id的值是根據資源編譯過程當中有序生成的,那麼aar的R.java文件中id的值應該怎麼生成呢?其實很簡單,fat-aar生成R.java過程當中將aar的id值指向了當前project的id,外部項目依賴project時會從新編譯資源文件,生成project的R.java文件,前面已經將資源拷貝到了project中,天然也會生成aar的資源id
貼出代碼以下:
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('.', '/')
// 根據R.txt生成R.java文件,全部id指向當前project的R.java
def rTxt = file("$aarPath/R.txt")
def rMap = new ConfigObject()
if (rTxt.exists()) {
rTxt.eachLine {
line ->
// R.txt文件行存儲格式爲type, subclass, name, value
// 將subclass做爲key,(name, type)做爲value
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 ->
// 遍歷rMap,寫入資源類型subclass
sb << " public static final class $subclass {" << '\n'
values.each {
name, type ->
// 寫入資源id
sb << " public static $type $name = ${libPackageName}.R.${subclass}.${name};" << '\n'
}
sb << " }" << '\n'
}
// 結束
sb << '}' << '\n'
// 建立R.java文件,將sb寫入文件
mkdir("$generated_rsrc_dir/$packagePath")
file("$generated_rsrc_dir/$packagePath/R.java").write(sb.toString())
embeddedRClasses += "$packagePath/R.class"
embeddedRClasses += "$packagePath/R\$*.class"
}
複製代碼
而後分析embedJavaJars的依賴關係
embedJavaJars.dependsOn embedRClass
embedRClass.dependsOn collectRClass
複製代碼
結合embedJavaJars和generateRJava的執行順序,能夠理解R.java文件生成以及打包R.class的整個流程:首先根據aar的R.txt文件生成各自的R.java文件,經編譯後生成R.class文件,而後將全部R.class文件拷貝到指定目錄下並打包成Jar(以當前project命名,個R.class文件的包名保持不變),最後將包含全部R.class文件的Jar包拷貝到project打包的路徑和project一塊兒對外發布。以下圖
注:$build_dir/intermediates/bundles/release是project最終打包成aar的路徑
fat-arr已經好久沒有維護了,可是fat-aar的學習不管是對Android項目構建流程的理解,仍是學習gralde grovvy(DSL,動態描述語言)都有很大的幫助
遇到的問題:
擴展方向: