今天要聊的就跟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的插件,好比上面提到的打印任务日志等等。 喜欢的朋友能够关注个人公众号,第一时间看到文章: