-
Android Plugin DSL Reference
Android Gradle DSL文档
Gradle Task
- 要了解一个默认的Android工程有哪些Task,可以使用以下指令:
gradlew task
运行结果如下图所示。
gradlew task
- 要查看各个Task的具体作用与各个Task之间的相互调用关系,可以使用以下指令。
gradlew task --all
运行结果如下图所示。
gradlew task --all
- 更改项目结构
sourceSets {
main {
java.srcDirs = ['src']
res.srcDirs = ['res']
assets.srcDirs = ['assets']
jni.srcDirs = ['jni']
jniLibs.srcDirs = ['libs']
manifest.srcFile 'AndroidManifest.xml'
//如下更加完整
renderscript.srcDirs = ['src']
aidl.srcDirs = ['res']
}
}
自定义代码的目录结构
sourceSets {
main {
res.srcDirs = ['src/main/res',
'src/main/res/layout/activity',
'src/main/res/layout/fragment']
}
}
自定义目录
PS:书上示例图目录结构不正确,在Android3.0.1上,必须在src/main/res/layout/activity
和src/main/res/layout/fragment
目录下创建layout,资源文件才能被识别
构建全局配置
全局参数
在项目的根目录下的build.gradle中,通过ext领域可以指定全局的配置信息,代码如下所示:
...
ext {
compileSdkVersion = 26
buildToolsVersion = "26.0.2"
minSdkVersion = 15
targetSdkVersion = 22
versionCode = 1
versionName = "1.0"
}
引用配置
配置好全局参数后,可以在每个module中使用这些配置
android {
compileSdkVersion rootProject.ext.compileSdkVersion
...
}
另外,也可以把ext全局配置写在allprojects领域中,这样每个module中就可以直接引用申明的变量了。
...
allprojects {
repositories {
google()
jcenter()
}
ext {
COMPILE_SDK_VERSION = 22
}
}
...
引用
android {
//compileSdkVersion rootProject.ext.compileSdkVersion
compileSdkVersion COMPILE_SDK_VERSION
...
}
这样写的好处是可以将配置进行统一管理。但坏处是如果这样写的话,Gradle的版本更新通知检查机制就无效了。大部分时候,这种写法是利大于弊的。
构建defaultConfig
可以在脚本中写代码,以便动态控制编译过程。
defaultConfig {
applicationId "com.example.czl.gradle"
minSdkVersion 15
targetSdkVersion 26
versionCode 1
//versionName "1.0"
versionName getCustomVersionName()
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
在build.gradle脚本中,定义一个方法来动态获取生成的versionName ,代码如下:
def getCustomVersionName(){
return "1.0."+new Date().format("yyyy-MM-dd", TimeZone.getDefault())
}
这样就可以完全自定义,动态配置参数了,在java中引用versionName 查看编译效果:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView tv = findViewById(R.id.tv);
try {
tv.setText(getPackageManager().getPackageInfo(getPackageName(), 0).versionName);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
}
}
动态生成versionName
构建buildTypes
构建类型基础
通过构建不同的构建类型,从而生成不同类型的apk,可以帮助开发者完成很多事情。例如实现只有在debug类型下才开启的给你,如调试、Log等功能,以及为不同构建类型实现不同的参数配置,等等。
gradle支持自定义创建的构造类型。例如,在脚本中增加一个czl类型,同时设置该类型的applicationIdSuffix
参数为.czl
,代码如下所示:
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
czl{
applicationIdSuffix ".czl"
}
}
生成的apk文件多了一个app-czl-unsigned.apk
,这个就是自定义的buildType-czl类型。
applicationIdSuffix在构建类型的时候,可以指定applicationIdSuffix为默认的包名增加一个后缀。查看编译后的apk文件,可以看到包名
image.png
除了使用gradlew build指令完成整个build任务之外,当指定了自定义的构建类型时,还可以指定完成其中任何一个构建类型的构建任务,比如
gradlew assembleDebug
和gradlew assembleRelease
两个默认的构造类型。同理,系统也帮我们生成了gradlew assembleCzl
的构建任务,单独运行整个Task就可以直接生成czl类型的构建任务。
构建类型buildTypes 的继承
当创建自定义的构建类型时,不仅仅可以完全创建一个新的类型,而且还可以通过继承一个已有的构建类型来创造新的构建类型。也就是继承的方式,代码如下:
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
czl.initWith(buildTypes.debug)
czl{
applicationIdSuffix ".czl"
}
}
通过以上代码,czl构建类型就继承了默认的debug构建类型的配置,同时还添加了自定义配置。
Android领域中的可选配置
compileOptions
设置Java的编译选项,通常可以指定Java的编译版本
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
lintOptions
控制Lint的代码检查,在Lint Check的时候,编译会因为Lint的error而终止,通过设置这个选项,可以在Lint发生error的时候继续编译。
lintOptions {
abortOnError false
}
Lint的编译检查是一个耗时大户,在编译时可以去掉Lint以便提高编译速度。但是只有尽可能的修复Lint提示,才是最佳的开发策略。
Gradle动态参数配置
System.properties 方式
首先,打开gradle.properties
文件,添加以下配置。
systemProp.keyAlias=czl
systemProp.keyPassword=123456
systemProp.storeFile=czl_key.jks
systemProp.storePassword=123456
在build.gradle中进行引用的时候,通过System.properties['KEY']
获取这些参数
signingConfigs {
config {
keyAlias System.properties['keyAlias']
keyPassword System.properties['keyPassword']
storeFile file(System.properties['storeFile'])
storePassword System.properties['storePassword']
}
}
Key\Value 方式
除了使用System.properties方式获取自定义的配置参数之外,还可以使用Key\Value的方式来定义。在gradle.properties文件,添加以下配置。
czl.keyAlias=czl
czl.keyPassword=123456
然后在build.gradle中进行引用
signingConfigs {
config {
// keyAlias System.properties['keyAlias']
// keyPassword System.properties['keyPassword']
keyAlias project.properties['czl.keyAlias']
keyPassword project.properties['czl.keyPassword']
storeFile file(System.properties['storeFile'])
storePassword System.properties['storePassword']
}
}
通过project.properties[KEY]方法,就可以取出对应的Value。
属性方式
前面两种方式,均可以在命令行中设置参数,从而设置给编译指令。如果不需要再命令行中设置参数,那么直接写属性名,同样可以进行引用。在gradle.properties文件,添加以下配置。
pkeyAlias=czl
pkeyPassword=123456
这样,在build.gradle脚本中就可以直接引用了
signingConfigs {
config {
// keyAlias System.properties['keyAlias']
// keyPassword System.properties['keyPassword']
// keyAlias project.properties['czl.keyAlias']
// keyPassword project.properties['czl.keyPassword']
keyAlias pkeyAlias
keyPassword pkeyPassword
storeFile file(System.properties['storeFile'])
storePassword System.properties['storePassword']
}
}
系统参数
Gradle内置了很多系统级别的参数,在使用中可以直接获取值。例如,在build.gradle脚本中,增加一个Task
task printProperties << {
println project
println project.name
println project.buildDir
println project.rootDir
println project.buildFile
println project.version
println name
println buildDir
println path
}
打印出一些gradle内置的系统变量gradlew app:printProperties
> Task :app:printProperties
project ':app'
app
C:\Users\czl\Documents\AndroidLearn\Gradle\app\build
C:\Users\czl\Documents\AndroidLearn\Gradle
C:\Users\czl\Documents\AndroidLearn\Gradle\app\build.gradle
unspecified
printProperties
C:\Users\czl\Documents\AndroidLearn\Gradle\app\build
:app:printProperties
多渠道打包
创建渠道占位符
首先在AndroidManifest.xml文件的application节点下,创建如下所示的meta-data节点
<meta-data
android:name="PRODUCT"
android:value="${CHANNEL_VALUE}" />
其中"${CHANNEL_VALUE}
就是要进行替换的渠道占位符
配置Gradle脚本
在项目的Gradle脚本的android领域中,添加定义的渠道名,使用manifestPlaceholders 指定要替换渠道占位符的值
flavorDimensions("official")
productFlavors {
product1 {
manifestPlaceholders = [CHANNEL_VALUE: "PRODUCT1"]
}
product2 {
manifestPlaceholders = [CHANNEL_VALUE: "PRODUCT2"]
}
product3 {
manifestPlaceholders = [CHANNEL_VALUE: "PRODUCT3"]
}
}
manifestPlaceholders 的module传递,可以参考下文
一个字符解决Gradle aar编译参数传递问题是怎样一种体验
关于维度,可参考:
Android Gradle(3)— FlavorDimensions,构建变体
脚本优化
对于上面的多渠道打包脚本,可以对脚本进行以下优化
flavorDimensions("official")
productFlavors {
product1 {
// manifestPlaceholders = [CHANNEL_VALUE: "PRODUCT1"]
}
product2 {
// manifestPlaceholders = [CHANNEL_VALUE: "PRODUCT2"]
}
product3 {
// manifestPlaceholders = [CHANNEL_VALUE: "PRODUCT3"]
}
}
productFlavors.all {
flavor -> flavor.manifestPlaceholders = [CHANNEL_VALUE: name]
}
增加的 productFlavors.all领域对所有的productFlavors进行了遍历,并使用其name作为渠道名。这些name实际上就是product1 ,product2 ,product3。
生成重命名包
默认包文件名一般我们要求对包进行重命名,以满足运营需求
applicationVariants.all {
variant ->
variant.outputs.all {
output ->
if (output.outputFile != null
&& output.outputFile.name.endsWith(".apk")
&& "release" == variant.buildType.name) {
outputFileName = "CZLApp_${variant.flavorName}_ver${variant.versionName}.apk"
}
}
}
PS:书中output.outputFile = apkFile已失效。
为不同版本添加不同代码
如下是添加boolean类型的变量。
buildTypes {
release {
buildConfigField "boolean", "testFlag", "true"
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
czl.initWith(buildTypes.debug)
czl {
buildConfigField "boolean", "testFlag", "false"
applicationIdSuffix ".czl"
signingConfig signingConfigs.config
}
}
查看BuildConfig.java
public final class BuildConfig {
public static final boolean DEBUG = Boolean.parseBoolean("true");
public static final String APPLICATION_ID = "com.example.czl.gradle.czl";
public static final String BUILD_TYPE = "czl";
public static final String FLAVOR = "product1";
public static final int VERSION_CODE = 1;
public static final String VERSION_NAME = "1.0.2018-03-30";
// Fields from build type: czl
public static final boolean testFlag = false;
}
public final class BuildConfig {
public static final boolean DEBUG = false;
public static final String APPLICATION_ID = "com.example.czl.gradle";
public static final String BUILD_TYPE = "release";
public static final String FLAVOR = "product1";
public static final int VERSION_CODE = 1;
public static final String VERSION_NAME = "1.0.2018-03-30";
// Fields from build type: release
public static final boolean testFlag = true;
}
添加String类型的变量buildConfigField "String", "myname", '"czl"'
在设置变量的时候,甚至可以继续使用变量,这个时候需要使用转义字符
release {
def param1="ddd"
buildConfigField "boolean", "testFlag", "true"
buildConfigField "String", "myname", '"czl"'
buildConfigField "String", "param", "\"String.${param1}.String\""
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
使用变量设置变量
资源文件同样可以进行设置属性值
resValue("string","app_name","AppRelease")
,比如设置AppName
release {
resValue("string","app_name","AppRelease")
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
czl.initWith(buildTypes.debug)
czl {
resValue("string","app_name","AppCzl")
applicationIdSuffix ".czl"
signingConfig signingConfigs.config
}
同时在defaultConfig领域添加默认设置
defaultConfig {
applicationId "com.example.czl.gradle"
minSdkVersion 15
targetSdkVersion 26
versionCode 1
versionName "1.0"
resValue("string","app_name","App")
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
注意:需要删掉string.xml的app_name才能编译通过。
另外resValue配置的参数,不一定要替换代码中的占位,还可以直接增加变量到R文件中
def buildTime() {
return new Date().format("yyyy-MM-dd HH:mm:ss")
}
defaultConfig {
applicationId "com.example.czl.gradle"
minSdkVersion 15
targetSdkVersion 26
versionCode 1
versionName "1.0"
resValue("string", "app_name", "App")
resValue("string", "build_time", buildTime())
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
在Java中,直接引用R文件的变量build_time即可
Log.d(TAG, "onCreate: " + getString(R.string.build_time));
03-30 16:51:30.604 14146-14146/com.example.czl.gradle.czl D/MainActivity: onCreate: 2018-03-30 16:51:01
网友评论