今天要聊的就跟android有關了,可是在介紹的時候會引用到前兩篇的知識,因此沒有看過前兩篇文章的朋友,建議先看一下前面提到的概念: Gradle插件學習筆記(一) Gradle插件學習筆記(二)java
要講到android的編譯,確定要先看看android在執行assemble都執行了什麼,這個咱們能夠打印一下任務(如何打印任務?這個咱們後面再說,也是個groovy插件):android
app工程的preBuild任務開始執行
app工程的preDebugBuild任務開始執行
app工程的checkDebugManifest任務開始執行
app工程的preReleaseBuild任務開始執行
app工程的prepareComAndroidSupportAnimatedVectorDrawable2600Alpha1Library任務開始執行
app工程的prepareComAndroidSupportAppcompatV72600Alpha1Library任務開始執行
app工程的prepareComAndroidSupportConstraintConstraintLayout102Library任務開始執行
app工程的prepareComAndroidSupportSupportCompat2600Alpha1Library任務開始執行
app工程的prepareComAndroidSupportSupportCoreUi2600Alpha1Library任務開始執行
app工程的prepareComAndroidSupportSupportCoreUtils2600Alpha1Library任務開始執行
app工程的prepareComAndroidSupportSupportFragment2600Alpha1Library任務開始執行
app工程的prepareComAndroidSupportSupportMediaCompat2600Alpha1Library任務開始執行
app工程的prepareComAndroidSupportSupportV42600Alpha1Library任務開始執行
app工程的prepareComAndroidSupportSupportVectorDrawable2600Alpha1Library任務開始執行
app工程的prepareDebugDependencies任務開始執行
app工程的compileDebugAidl任務開始執行
app工程的compileDebugRenderscript任務開始執行
app工程的generateDebugBuildConfig任務開始執行
app工程的generateDebugResValues任務開始執行
app工程的generateDebugResources任務開始執行
app工程的mergeDebugResources任務開始執行
app工程的processDebugManifest任務開始執行
app工程的processDebugResources任務開始執行
app工程的generateDebugSources任務開始執行
app工程的incrementalDebugJavaCompilationSafeguard任務開始執行
app工程的javaPreCompileDebug任務開始執行
app工程的compileDebugJavaWithJavac任務開始執行
app工程的compileDebugNdk任務開始執行
app工程的compileDebugSources任務開始執行
app工程的mergeDebugShaders任務開始執行
app工程的compileDebugShaders任務開始執行
app工程的generateDebugAssets任務開始執行
app工程的mergeDebugAssets任務開始執行
app工程的transformClassesWithDexForDebug任務開始執行
app工程的mergeDebugJniLibFolders任務開始執行
app工程的transformNativeLibsWithMergeJniLibsForDebug任務開始執行
app工程的transformNativeLibsWithStripDebugSymbolForDebug任務開始執行
app工程的processDebugJavaRes任務開始執行
app工程的transformResourcesWithMergeJavaResForDebug任務開始執行
app工程的validateSigningDebug任務開始執行
app工程的packageDebug任務開始執行
app工程的assembleDebug任務開始執行
複製代碼
這是執行assembleDebug打印的全部任務,固然你要執行assembleRelease任務確定是一致的。 那接下來介紹一下經常使用的幾個任務:數組
mergeDebugResources 任務的做用是將全部依賴的aar或library module中的資源合併到app/build/intermediates/res/merged/debug目錄裏bash
processDebugManifest任務是將全部依賴的aar或library module中AndroidManifest.xml中的節點,合併到項目的AndroidManifest.xml中微信
processDebugResources的做用是調用aapt生成項目和全部aar依賴的R.java,同時生成資源索引文件,把符號表輸出到app/build/intermediates/symbols/debug/R.txtapp
compileDebugJavaWithJavac這個任務是用來把java文件編譯成class文件,輸出的路徑是app/build/intermediates/classes/debug 編譯的輸入目錄有學習
transformClassesWithJarMergingForDebug的做用是把compileDebugJavaWithJavac任務的輸出app/build/intermediates/classes/debug,和app/build/intermediates/exploded-aar中全部的classes.jar和libs裏的jar包做爲輸入,合併起來輸出到app/build/intermediates/transforms/jarMerging/debug/jars/1/1f/combined.jar,咱們在開發中依賴第三方庫的時候有時候報duplicate entry:xxx 的錯誤,就是由於在合併的過程當中在不一樣jar包裏發現了相同路徑的類gradle
transformClassesWithDexForDebug這個任務的做用是把包含全部class文件的jar包轉換爲dex,class文件越多轉換的越慢ui
若是想在本身的插件中產生干預android編譯的行爲,確定要依賴android的gradle插件。這裏要說明兩種狀況:lua
dependencies {
compile gradleApi()
compile localGroovy()
compile 'com.android.tools.build:gradle:2.3.3'
}
複製代碼
上一篇文章說到了能夠經過android的額外屬性名訪問Project的android屬性,從而訪問android的編譯。 咱們今天會經過源碼看一下,android究竟是如何實現的。 首先是AppPlugin.java
文件(即插件的主文件),裏面有這麼一行代碼:
project.getExtensions()
.create(
"android",
AppExtension.class,
project,
instantiator,
androidBuilder,
sdkHandler,
buildTypeContainer,
productFlavorContainer,
signingConfigContainer,
extraModelInfo);
複製代碼
能夠看出AppExtension就是android拓展屬性的文件,這裏要說明的是若是是編譯Library,使用的就是LibraryPlugin插件,對應的拓展文件爲LibraryExtension
。好了咱們仍是繼續說兩個文件對比一下不難發現,兩個文件都是差很少的,都是繼承TestedExtension,只是屬性變量不太同樣。今天咱們仍是隻說AppExtension。 在這個文件中有一個這樣的數組ApplicationVariant:
圖有些大了,可是應該能夠看明白BaseVariant中的方法比較多,我省略了一下,省略的部分主要是獲取上一節打印的Task的方法。暫時應該不會用到。 這裏有個重要的方法BaseVariantOutput
,咱們經常使用的替換佔位符(多渠道打包等)都會用到,這裏作個簡單的介紹:
以上介紹的方法和類都很重要,想更深瞭解的朋友不妨仿照下面的demo,多打印些log看看輸出的內容都是什麼,
若是上面的圖認真的看一下,就能夠了解variant中包含了android編譯的主要功能參數,因此要下手,只能從這裏下手了。 在這裏咱們先舉個簡單的小例子(在以前的demo中作個修改,不熟悉的朋友請參考前兩章):
void apply(Project project) {
project.extensions.create("deep", MyExtension)
project.afterEvaluate {
MyExtension extension = project['deep'];
String a = extension.aaa
String b = extension.bbb
println("deep:${a},${b}")
project.tasks.getByName("preDebugBuild") {
it.doFirst {
project.android.applicationVariants.all { variant ->
variant.outputs.each { output ->
output.processManifest.doLast {
def manifestFile = "${project.getProjectDir().absolutePath}/build/intermediates/manifests/full/${variant.dirName}/AndroidManifest.xml"
def updatedContent = new File(manifestFile).getText('UTF-8').replaceAll("vvvvv", "ccccc")
new File(manifestFile).write(updatedContent, 'UTF-8')
}
}
}
}
}
}
}
複製代碼
這段代碼的做用很明顯是修改AndroidManifest中的字符串vvvvv,改爲ccccc。說白了做用就是替換字符串,跟替換佔位符是一個做用。看看上面有個重要的寫法:
output ->
output.processManifest.doLast {}
複製代碼
這是什麼意思呢,根據上面咱們介紹的源碼,能夠知道這個就是在processManifest Task以後再去執行,再由上面介紹到的內容processManifest是合併AndroidManifest的任務,在合併以後,立刻去修改AndroidManifest文件,保證了佔位符的替換。 再修改一下這個文件,我們看看output的file是什麼:
project.tasks.getByName("preDebugBuild") {
it.doFirst {
project.android.applicationVariants.all { variant ->
variant.outputs.each { output ->
println("out put="+output.getOutputFile())
}
}
}
}
複製代碼
看看輸出:
setOutputFile
,來咱們在打打log,看一下:
project.tasks.getByName("preDebugBuild") {
it.doFirst {
project.android.applicationVariants.all { variant ->
variant.outputs.each { output ->
println("getDirName:"+output.getDirName())
output.setOutputFile(new File("${project.getProjectDir().absolutePath}/build/${output.getName()}_aaa.apk"))
println("out put=" + output.getOutputFile())
}
}
}
}
複製代碼
看看結果:
此次介紹的內容比較多,要想多掌握,可能須要多調試幾回,多打打log才能所有掌握,喜歡的用戶能夠根據我上面提到的方法,多試幾回。 接下來的文章可能會側重介紹groovy的語法,由於有用戶微信公衆號給我留言說寫的代碼,看着有些彆扭。還有可能會介紹一些其餘gradle的插件,好比上面提到的打印任務日誌等等。 喜歡的朋友能夠關注個人公衆號,第一時間看到文章: