实际项目中,都会应用Android Gradle Plugin
,根据实际中的项目模块的职责,可以具体应用如下四种插件类型。
1,apply plugin: 'com.android.application'
实际对应的原型是:com.android.build.gradle.AppExtension
,表示此项目模块类型为Android App Module
,对应构建生成的文件为.apk
类型文件。
2,apply plugin: 'com.android.library'
实际对应的原型是:com.android.build.gradle.LibraryExtension
,表示此项目模块类型为Android Library Module
,对应构建生成的文件为.arr
类型的文件。
3,apply plugin: 'com.android.test'
实际对应的原型是:com.android.build.gradle.TestExtension
,表示此项目模块类型为Android test Module
,可以在单个模块内通过targetProjectPath
指定项目,用于对应项目的单元测试。
4,apply plugin: 'com.android.feature'
实际对应的原型是:com.android.build.gradle.FeatureExtension
,表示此项目模块类型为Android feature Module
,主要用于单个模块内实现特性,以支持Android Instant Apps
。
其中,一般项目中最常见的是application
和library
插件类型。
项目模块内应用了具体的Android Gradle Plugin
类型后,可以开始进行对应的配置,如最常见的如下配置项:
- apply plugin: 'com.android.application'
-
- android {
- compileSdkVersion 28
- defaultConfig {
- applicationId "com.happycorn"
- minSdkVersion 15
- targetSdkVersion 28
- versionCode 1
- versionName "1.0"
- testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
- ...
- }
- buildTypes {
- release {
- minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
- }
- ...
- }
-
- ...
- }
-
- dependencies {
- implementation fileTree(dir: 'libs', include: ['*.jar'])
- ...
- }
- 复制代码
此时可以按住CTRL
,通过鼠标悬浮,可以看到对应的配置原型信息。
不同的Android Gradle Plugin
插件类型,对应不同的实现原型,以及对应可能不同的对外配置项。
同样的,跟踪defaultConfig{}
原型信息,可以进入到如下原型说明。
- /**
- * Specifies defaults for variant properties that the Android plugin applies to all build
- * variants.
- *
- * <p>You can override any <code>defaultConfig</code> property when <a
- * href="https://developer.android.com/studio/build/build-variants.html#product-flavors">
- * configuring product flavors</a>.
- *
- * <p>For more information about the properties you can configure in this block, see {@link
- * ProductFlavor}.
- */
- public void defaultConfig(Action<DefaultConfig> action) {
- checkWritability();
- action.execute(defaultConfig);
- }
- 复制代码
可见,defaultConfig{}
所对应的具体职责是:为变体属性,指定默认值,Android plugin 可以将指定的变体属性的默认值,应用到所有的变体中。
执行action.execute(defaultConfig);
后,将为DefaultConfig
对象指定具体的配置。
实际项目开发中,我们往往关注此处有哪些配置项,以及每个配置项对应的含义及作用。
首先可以在Android Gradle DSL
文档上对应查询DefaultConfig
使用说明。 具体参见: google.github.io/android-gra…
文档中列出了DefaultConfig
对象的对外可配置的属性、方法,以及对应说明,在具体配置时,可能有些需要注意的事项,文档中也做了详尽叙述。
但无论是属性还是方法,一般在build.gradle
中配置defaultConfig{}
时,一般都是采用形如 key value
形式,当然,实际上也可以采用对应的方法原型形式配置,效果是等价的,不过有个前提是,此方法原型是确实存在的,否则,Gradle
会报错。 如:
- defaultConfig {
- ...
- minSdkVersion 15
- ...
- }
-
- 等价于
- defaultConfig {
- ...
- minSdkVersion(15)
- ...
- }
- 复制代码
defaultConfig{}
中配置的属性,在构建时,会默认生成对应的变体目录下的BuildConfig.java
文件,此文件中将之前配置的属性转变成了对应的JAVA
常量形式。
如build.gradle
中配置如下:
- android {
- compileSdkVersion 28
-
- defaultConfig {
- applicationId "com.happycorn"
- minSdkVersion 15
- targetSdkVersion 28
- versionCode 1
- versionName "1.0"
- }
-
-
- buildTypes {
- release {
- minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
- }
-
- debug {
-
- }
- }
-
-
- flavorDimensions "default"
-
- productFlavors {
- demo {
- applicationIdSuffix "demo"
- }
-
- full {
- applicationIdSuffix "full"
- }
- }
-
- }
- 复制代码
执行./gradlew assembleFull
命令,对应生成的BuildConfig
文件为:
如其中的buildType
为debug
对应的BuildConfig
文件内容为:
- /**
- * Automatically generated file. DO NOT MODIFY
- */
- package com.happycorn;
-
- public final class BuildConfig {
- public static final boolean DEBUG = Boolean.parseBoolean("true");
- public static final String APPLICATION_ID = "com.happycorn.full";
- public static final String BUILD_TYPE = "debug";
- public static final String FLAVOR = "full";
- public static final int VERSION_CODE = 1;
- public static final String VERSION_NAME = "1.0";
- }
- 复制代码
BuildConfig
文件为JAVA
源码级别,构建时也会对应被编译打包到包中,可以直接在对应的模块中使用。
利用此特性,我们经常可以在项目中对变体环境进行逻辑判断,对应的进行逻辑处理。 如:判断是否是DEBUG
,对应的输出Log
等。
- if (BuildConfig.DEBUG) {
- Log.d(TAG, "come here...");
- }
- 复制代码
另外,DefaultConfig
对象中专门对外提供了buildConfigField(type, name, value)
方法,用于向构建时生成的BuildConfig.java
类中增加新的属性。
如:defaultConfig{}
中通过buildConfigField(type, name, value)
添加如下。
- defaultConfig {
- ...
- // 是否打对对用户的内测包
- innerTest = project.hasProperty('innertest') ? innertest : 'false'
- buildConfigField "boolean", "INNER_TEST", innerTest
-
- // 添加模块对应的模块名
- buildConfigField "String", "MODULE_NAME", "\"${project.name}\""
- }
- 复制代码
生成的BuildConfig.java
中将有对应属性产生。
- public final class BuildConfig {
- ...
- // Fields from default config.
- public static final boolean INNER_TEST = false;
- public static final String MODULE_NAME = "app";
- }
- 复制代码
利用此特性,可以很有技巧性的去处理项目中的一些特定的问题。参照上例代码中的两个追加的属性。
如:
在Gradle
构建时,通过命令参数-P
传入对应参数键值,可以将其在defaultConfig{}
中添加,以自动在BuildConfig.java
中生成对应属性,然后程序中对应进行一些逻辑的特别处理。
- if (BuildConfig.INNER_TEST) {
- // 用户内测的一些逻辑处理
- ...
- }
- 复制代码
又如:
调用项目日志系统时,可以传入对应的模块名,以实现对各个模块的日志过滤展示等。 此时就可以通过project.name
取到模块名,追加到BuildConfig.java
中。然后调用日志库时可以取用。
- CLog.e(BuildConfig.MODULE_NAME, TAG, e)
- 复制代码
更进一步,此处对各个模块通过defaultConfig{}
配置向BuildConfig.java
中追加属性可以写成:
- allprojects {
- ...
- afterEvaluate { project ->
- def android = project.extensions.findByName("android")
- if(android != null){
- def defaultConfig = android["defaultConfig"]
- defaultConfig.buildConfigField("String", "MODULE_NAME", "\"${project.name}\"")
- }
- }
- }
- 复制代码
使得整体用法显得非常灵活。
除了buildConfigField(type, name, value)
方法外,还有一个实用方法resValue(String type, String name, String value)
。resValue(String type, String name, String value)
等价于向模块res/values
中新增一个资源。
如:在buildType
为debug
中新增资源:
- buildTypes {
- release {
- minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
- }
-
- debug {
- resValue("string", "app_name_debug", "HappyCornDebug")
- resValue("integer", "token", "365")
- }
- }
- 复制代码
编译后,对应变体目录结构下会生成资源文件,及对应的资源键值。
项目中对应需要的此资源的地方也可以直接取用:
- getResources().getString(R.string.app_name_debug);
- getResources().getInteger(R.integer.token);
- 复制代码
当defaultConfig{}
中配置的属性与productFlavors
中具体Flavor
中配置的属性重复时,Android Gradle
构建时将以productFlavors
中的对应配置为准,可以理解成将defaultConfig{}
中对应的配置覆盖掉了。但applicationIdSuffix
除外(applicationIdSuffix
依然是追加的形式)。
在现实的项目需求中,外部传入的参数键值或通过Gradle/Android Gradle
脚本获取的值,结合defaultConfig{}
配置,变体,以及对应生成的BuildConfig.java
或资源文件,实现一些特定场景下的需求,整体可以非常灵活,且具有一定的技巧性。