参考
https://developer.android.com/studio/build
http://google.github.io/android-gradle-dsl/current/index.html
https://developer.android.com/reference/tools/gradle-api/classes
说明
学习gradle最烦人的就是api不知道去哪查询,想要实现某个打包功能只能去网上copy人家的,
gradle官方的文档还好,但Android gradle plugin的官方文档却更新不及时,原来的文档一直是3.4的,
现在竟然完全删除了,真tm狗东西,现在只有api了,想要深入只能通过complieOnly导入gradle依赖,下边有说明。
android gradle plugin版本查询
https://developer.android.com/studio/releases/gradle-plugin
gradle plugin和gradle版本对应
Plugin version |
Required Gradle version |
1.0.0 - 1.1.3 |
2.2.1 - 2.3 |
1.2.0 - 1.3.1 |
2.2.1 - 2.9 |
1.5.0 |
2.2.1 - 2.13 |
2.0.0 - 2.1.2 |
2.10 - 2.13 |
2.1.3 - 2.2.3 |
2.14.1+ |
2.3.0+ |
3.3+ |
3.0.0+ |
4.1+ |
3.1.0+ |
4.4+ |
3.2.0 - 3.2.1 |
4.6+ |
3.3.0 - 3.3.3 |
4.10.1+ |
3.4.0 - 3.4.3 |
5.1.1+ |
3.5.0 - 3.5.4 |
5.4.1+ |
3.6.0 - 3.6.4 |
5.6.4+ |
4.0.0+ |
6.1.1+ |
4.1.0+ |
6.5+ |
Extension types
Listed below are the Gradle extension types used by respective plugins:
Type |
Description |
The android extension for application plugins. |
|
The android extension for com.android.library projects. |
|
android extension for com.android.test projects. |
|
The android extension for com.android.feature projects. |
Configuration blocks
下边列出了在android{}的closure中可访问的配置
Block |
Description |
Specifies options for the Android Asset Packaging Tool (AAPT). |
|
Specifies options for the Android Debug Bridge (ADB), such as APK installation options. |
|
Encapsulates all build type configurations for this project. |
|
Specifies Java compiler options, such as the language level of the Java source code and generated bytecode. |
|
Specifies options for the Data Binding Library. |
|
Specifies defaults for variant properties that the Android plugin applies to all build variants. |
|
Specifies options for the DEX tool, such as enabling library pre-dexing. |
|
Configure JaCoCo version that is used for offline instrumentation and coverage report. |
|
Specifies options for the lint tool. |
|
Specifies options and rules that determine which files the Android plugin packages into your APK. |
|
Encapsulates all product flavors configurations for this project. |
|
Encapsulates signing configurations that you can apply to BuildType and ProductFlavor configurations. |
|
Encapsulates source set configurations for all variants. |
|
Specifies configurations for building multiple APKs or APK splits. |
|
Specifies options for how the Android plugin should run local and instrumented tests. |
AppExtension
其实对应的就是app中的build.gradle中的android,它对应的类型是BaseAppModuleExtension,继承关系如下:
- BaseAppModuleExtension实现了AppExtension,ApplicationExtension,
- ApplicationExtension实现了 CommonExtension,ApkExtension,TestedExtension
BaseAppModuleExtension是内部的api,在api文档中被隐藏了,其实大部分的属性方法都是在CommonExtension中定义的。
variantFilter
https://developer.android.com/studio/build/build-variants.html#filter-variants
variantFilter(Action<VariantFilter> filter)
在这里你可以对variant进行过滤,通过调用VariantFilter.setIgnore(true)。
android { ... variantFilter { variant -> def buildTypeName = variant.buildType*.name def flavorName = variant.flavors*.name if (flavorName.contains("dev") && buildTypeName.contains("release")) { // Tells Gradle to ignore each variant that satisfies the conditions above. setIgnore(true) } } }
applicationVariants
DomainObjectSet<ApplicationVariant> applicationVariants
ApplicationVariant在com.android.build.gradle.api.ApplicationVariant
你可以在这里获取到最终的可构建的variant,你可以在此处对各variant进行属性修改。
另外由于此集合时DomainObjectSet,所以应该使用.all来遍历,而不是each,原因是插件只在project is evaluated之后才填充此集合。
android.applicationVariants.all { variant -> StringBuilder sb = new StringBuilder() for (def productFlavor : variant.productFlavors) { sb.append(productFlavor.name) } println "productFlavor:$sb, buildType:$variant.buildType.name, applicationId:$variant.applicationId" def mergedFlavor = variant.getMergedFlavor() if ("debug".equalsIgnoreCase(variant.buildType.name)) { mergedFlavor.applicationId = "com.fuck.you" mergedFlavor.manifestPlaceholders = [hostName:"www.example.com/${variant.versionName}"] } }
通过variant.getMergedFlavor()获取最后组合的flavor,通过这个productFlavor可以修改最后的包名、placeholder等等属性。
自定义打包后要输出的目录
def releaseTime() { return new Date().format("yyyy-MM-dd", TimeZone.getTimeZone("UTC")) } android{ applicationVariants.all { variant -> variant.outputs.each { output -> def outputFile = output.outputFile if (outputFile != null && outputFile.name.endsWith('.apk')) { File outputDirectory = new File(outputFile.parent); def fileName if (variant.buildType.name == "release") { fileName = "app_v${defaultConfig.versionName}_${releaseTime()}_${variant.productFlavors[0].name}.apk" } else { fileName = "app_v${defaultConfig.versionName}_${packageTime()}_debug.apk" } output.outputFile = new File(outputDirectory, fileName) } } } }
在Android Gradle Plugin 4.x中Variant新的配置方式
https://medium.com/androiddevelopers/new-apis-in-the-android-gradle-plugin-f5325742e614
以下是Android项目构建所经历的阶段的概述:
1. 运行Build scripts,允许构建和插件配置Android Gradle Plugin DSL对象以及注册variant 回调。
2. Android Gradle Plugin 结合了build types和product flavors来创建variants 和test components。
3. 将为每个variant调用onVariants,从而允许自定义variant设置,并为每个测试组件均调用onTestComponent。
4. 将为每个启用的variant调用onVariantProperties,并为每个启用的测试组件调用onTestComponentProperties,从而允许注册使用或修改构建中间件的任务。
5. 在调用onVariants和onVariantProperties回调后,Android Gradle Plugin 插件会为variant注册task。
6. 使用已注册task,为每个variant调用先前的variant API。
7. Gradle计算task graph,构建即可开始执行。
import com.android.build.api.variant.impl.ApplicationVariantPropertiesImpl import com.android.build.api.variant.impl.ApplicationVariantImpl import com.android.build.gradle.internal.dsl.BaseAppModuleExtension apply plugin: 'com.android.application' android { BaseAppModuleExtension appModuleExtension -> onVariants { ApplicationVariantImpl applicationVariant -> StringBuilder sb = new StringBuilder() sb.append("name:" + applicationVariant.name + ", ") sb.append("flavorName:" + applicationVariant.flavorName + ", ") sb.append("productFlavors:" + applicationVariant.productFlavors + ", ") sb.append("buildType:" + applicationVariant.buildType + ", ") println sb } onVariantProperties { ApplicationVariantPropertiesImpl applicationVariantProperties -> StringBuilder sb = new StringBuilder() sb.append("productFlavor:$applicationVariantProperties.name, ") sb.append("buildType:$applicationVariantProperties.buildType, ") sb.append("applicationId:" + applicationVariantProperties.applicationId.get() + ", ") println sb // API 'MergedFlavor.getApplicationId()' is obsolete and has been replaced with 'VariantProperties.getApplicationId()'. // It will be removed in version 5.0 of the Android Gradle plugin. if ("debug".equalsIgnoreCase(applicationVariantProperties.buildType)) { applicationVariantProperties.applicationId.set(mlwDebugApplicationId) } //修改打包的名字 applicationVariantProperties.outputs.each { output -> def date = new Date().format('yyyy_MMdd_HHmm') def file = output.outputFileName.get() def fileName = file.replace(".apk", "_" + android.defaultConfig.versionName + "_" + date + ".apk").replaceFirst("app", "rent_customer").replace("-", "_") output.outputFileName.set(fileName) // println "output.outputFileName:" + output.outputFileName } } }
上边的导入的api需要添加依赖才不会变红
compileOnly group: 'com.android.tools.build', name: 'gradle', version: '4.1.0'
在 Android Gradle Plugin 5.0中R.xxx不再是final
https://sites.google.com/a/android.com/tools/tips/non-constant-fields
Resource IDs will be non-final in Android Gradle Plugin version 5.0, avoid using them in switch case statements
一般我们会在onClick中使用switch(id)来检索对应操作,
public void onClick(View v) { switch (v.getId()) { case R.id.iv_close: { dismiss(); break; } case R.id.bt_share: { if (onClickListener != null) { onClickListener.onClick(v); } dismiss(); break; } } }
但在Android Gradle Plugin version 5.0中,资源id都不是final了,而switch在编译器就把R.id.xx的值写入到class中,不是final就意味着可能发生改变,那么在运行时的时候可能就找不到对应的case了,
解决方法就是:
把switch换成if else,在as中选中switch关键字,然后键盘输入show context action的快捷键(我的是alt+enter),就会弹出快捷转换操作。