Gradle初探

[TOC]

Gradle

基于Groovy脚本语言进行构建的。Google选用它作为默认的Android编译工具。

Gradle的官方文档

分类

全局build.gradle

可以为项目整体配置一些属性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
buildscript {
repositories {
jcenter() //指定使用jcenter代码仓库
}
dependencies {
classpath 'com.android.tools.build:gradle:2.2.3'

// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}

allprojects {
repositories {
jcenter()
}
// 好处是这样写之后,可以将配置进行统一管理。坏处是更新通知检查机制就无效了。
ext.global_compileSdkVersion = 25
ext.global_buildToolsVersion = "25.0.0"
ext.global_minSdkVersion = 16
ext.global_targetSdkVersion = 25
ext.global_ndkCommand = getNdkCommand()
}

//windows下使用.cmd,Linux和MacOS使用无后缀
def static getNdkCommand() {
if (System.properties['os.name'].toLowerCase().contains('windows')) {
return "ndk-build.cmd"
}
return "ndk-build"
}

task clean(type: Delete) {
delete rootProject.buildDir
}

Module build.gradle

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
//描述Gradle所引入的插件,如果该模块是Library,则将application改为library
apply plugin: 'com.android.application'

//该Module构建过程中所用到的所有参数
android {
compileSdkVersion global_compileSdkVersion
buildToolsVersion global_buildToolsVersion
sourceSets.main {
jni.srcDirs = [] // disable auto ndk build
jniLibs.srcDir 'src/main/libs'
res.srcDir = ['src/main/res/',
'src/main/res/layout/activity']
}
defaultConfig {
applicationId "com.xxx.xxx"
minSdkVersion global_minSdkVersion
// 此参数表示能适应该版本的新特性,如设置为23,就需要支持动态权限
targetSdkVersion global_targetSdkVersion
versionCode 1
versionName "1.0"
}

// NDK build task,global_ndkCommand是因为各平台ndk-build命令不同做的区分处理
task buildNative(type: Exec, description: 'Compile JNI source via NDK') {
def ndkDir = android.ndkDirectory
commandLine "$ndkDir/$global_ndkCommand",,
'-C', file('src/main/jni').absolutePath,
'-j', Runtime.runtime.availableProcessors(),
'all',
'NDK_DEBUG=1'
}

task cleanNative(type: Exec, description: 'Clean JNI object files') {
def ndkDir = android.ndkDirectory
commandLine "$ndkDir/ndk-build.cmd",
'-C', file('src/main/jni').absolutePath,
'clean'
}

clean.dependsOn 'cleanNative'

tasks.withType(JavaCompile) {
compileTask -> compileTask.dependsOn buildNative
}

//签名,使用签名需要到buildTypes里面进行signingConfig设置
signingConfigs{
ch{
storeFile file("aaa_key.jks")
storePassword "1234567"
keyAlias "aaa"
keyPassword "1234567"
}
}

buildTypes {
debug {
debuggable true
//是否开启混淆,另外还有功能是将非使用到的东西不进行打包进apk
minifyEnabled false
//混淆规则
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
release {
minifyEnabled true
shrinkResources true//此配置只有在minifyEnabled成功情况下才能开启,资源精简
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
ch.initWith(buildTypes.release)
ch{
//applicationID增加后缀,Android系统以此为主键,故而可以通过增加后缀的方式同时安装app
applicationIdSuffix ".ch"
signingConfig signingConfigs.ch
}
}
}

dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
compile 'com.android.support:appcompat-v7:25.0.0'
compile 'com.android.support:recyclerview-v7:25.0.0'
compile 'com.android.support:design:25.0.0'
compile project(':pulltorefresh')
}

local.properties

1
2
ndk.dir=G\:\\android-ndk-r10
sdk.dir=E\:\\sdk

可选配置

在android领域中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//java编译版本
compileOptions{
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}

//控制lint代码检查,Lint的编译检查是Gradle编译的耗时大户
lintOptions{
abortOnError false
}

//Proguard
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android.txt'),'proguard-rules.pro'

//定义Task,执行Task方式是gradle taskName
task testTask << {
println project
println project.name
println project.buildDir
println project.buildFile
println project.version
println name
}

gradle.properties

进行一些动态配置,将一些键、值写在SystemProp中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//1. 配置到SystemProp中
systemProp.keyAlias = ch
//在signingConfig中引用
keyAlias System.properties['keyAlias']

//2. 使用KEY/VALUE进行配置
ch.keyAlias = ch
//在signingConfig中引用
keyAlias project.property['ch.keyAlias']

//3. 属性方式进行配置,缺点是不可以在命令行中设置参数
pKeyAlias = ch
//在signingConfig中引用
keyAlias pKeyAlias

flavor

测试代码和实际代码可以使用flavor进行配置。

然后从AS的build variants可以选择自己需要运行的配置参数即可运行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
productFlavors{
mock{}

prod{}
}

//release版本不需要mock这个flavor
android.variantFilter{ variant ->
if(variant.buildType.name.equals('release')){
variant.getFlavors.name.equals('release'){
variant.getFlavors().each() {flavor ->
if(flavor.name.equals('mock')){
variant.setIgnore(true);
}
}
}
}

}

多渠道打包

实际上就是在代码层面上标记不同的渠道名

  1. 创建渠道占位符(比如${CHANNEL_VALUE}就是渠道占位符)

    1
    2
    3
    <meta-data
    android:name="PRODUCT"
    android:value="${CHANNEL_VALUE}"/>
  2. 配置Gradle脚本,一般在android领域中添加productFlavors

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    productFlavors{
    product1{
    manifestPlaceholders = [CHANNEL_VALUE:"PRODUCT 1"]
    }

    product2{
    manifestPlaceholders = [CHANNEL_VALUE:"PRODUCT 2"]
    }
    }

    // 可以这样优化,即不在productX中定义,直接统一定义在外部
    productFlavors.all{
    flavor-> flavor.manifestPlaceholders = [CHANNEL_VALUE:name]
    }

重命名包

包的默认命名是 app-渠道名-buildType.apk

1
2
3
4
5
6
7
8
9
10
11
12
13
applicationVariants.all{
variant ->
variant.output.each{
output ->
if(output.outputFile !=null
&& output.outputFile.name.endsWith('.apk')
&& 'release'.equals(variant.buildType.name)){
def apkFile = new File(output.outputFile.getParent(),
"CHApp_${variant.flavorName}_ver${variant.versionName}.apk")
output.outputFile = apkFile
}
}
}

为不同版本添加不同代码

buildTypes下的具体领域中,通过buildConfigField的三个参数,类型、名称、值,可以将一个变量设置到不同的buildType中去。

这些变量会生成在系统的BuildConfig中

1
2
3
4
buildConfigField "boolean" "apkFlag" "true"

// 更改app的名称,可以放在buildTypes中,但是注意需要删除string.xml中的app_name字段,否则会冲突
resValue("string","app_name","hello_world")

上传aar到Maven库

普通libriay的aar文件会存放在build/outputs/aar中

如果要上传aar到Maven库的话,是通过gradle脚本进行提交

具体脚本可以上网查询。

常用命令

  • check
  • assemble
    • 组合项目的所有输出,包含assembleDebug和assembleRelease两个Task
  • build
    • 相当于check和assemble
  • clean
    • 清理所有的中间编译结果

Gradle依赖

1
2
3
4
5
6
7
8
9
10
// 检查依赖关系
gradle androidDependencies

// 关闭项目的依赖传递
compile 'com.xxx.xxxxx:xxxxx:1.0.0-SNAPSHOT@aar'

// 可以使用exclude module排除一个库中引用的其他库
compule('xxxx'){
exclude module:'com.xxx.asdfa'
}

Gradle编译加速

Gradle本身已经内置了性能分析工具profile

build的时候只需要增加profile参数即可执行以下脚本

执行后在根目录的build/reports目录下会生成profile文件,里面有各项耗时

1
gradle build --profile

关闭Lint

1
2
3
4
5
// 命令行
gradle build -x lint

// 脚本中动态增加编译参数
project.gradle.startParameter.excludedTaskNames.add('lint')

Gradle加速

1
2
3
4
5
6
7
8
9
10
//gradle.properties,开启多线程和多核心支持
org.gradle.daemon = true
org.gradle.parallel = true
org.gradle.configureondemand = true

//build.gradle,开启增量编译,内存资源增加
dexOptions{
incremental
javaMaxHeapSize "4g"
}

自定义插件

创建自定义插件的三种方式:

  • 在build.gradle脚本中直接使用
  • buildSrc中使用
  • 独立Module中使用
0%