Gradle for Android

目录
  1. 1. Android build.gradle文件
    1. 1.1. compiledSdkVersion
    2. 1.2. buildToolsVersion
    3. 1.3. applicationId
    4. 1.4. minSdkVersion
    5. 1.5. targetSdkVersion
  2. 2. (一)基本配置、依赖管理
    1. 2.1. 基本配置
      1. 2.1.1. app/build.gradle
      2. 2.1.2. gradle-wrapper.properties
      3. 2.1.3. 根目录的build.gradle
      4. 2.1.4. setting.gradle
    2. 2.2. 依赖管理
      1. 2.2.1. 本地依赖
        1. 2.2.1.1. jar
        2. 2.2.1.2. so包
        3. 2.2.1.3. library工程
        4. 2.2.1.4. aar文件
      2. 2.2.2. 远程仓库
  3. 3. (二)全局设置、自定义BuildConfig、混淆
    1. 3.1. 全局设置
    2. 3.2. 自定义BuildConfig
    3. 3.3. 启用proguard混淆
  4. 4. (三)多渠道打包、配置签名信息
    1. 4.1. 多渠道打包
    2. 4.2. 定制生成的apk文件名
    3. 4.3. 占位符
    4. 4.4. 渠道打包完整代码:
    5. 4.5. 配置签名信息
      1. 4.5.1. Android Studio设置默认的签名文件
    6. 4.6. 签名打包
      1. 4.6.1. 通过Android Studio签名
      2. 4.6.2. 通过命令行签名
  5. 5. 完整配置
  6. 6. 附录

Android build.gradle文件

app/build.gradle

Android Studio使用Gradle 编译运行Android工程,工程的每个模块以及整个工程都有一个build.gradle文件。通常你只需要关注模块的build.gradle文件,该文件存放编译依赖设置,包括defaultConfig设置:

compiledSdkVersion

应用将要编译的目标Android版本,此处默认为你的SDK已安装的最新Android版本,我们仍然可以使用较老的版本编译项目,但把该值设为最新版本,可以使用Android的最新特性,同时可以在最新的设备上优化应用来提高用户体验。

buildToolsVersion

使用什么版本的编译工具。使用SDK Manager安装多个版本的编译工具。

applicationId

创建新项目时指定的包名。

minSdkVersion

创建项目时指定的最低SDK版本,是新建应用支持的最低SDK版本。

targetSdkVersion

表示你测试过你的应用支持的最高Android版本(同样用API level表示),当Android发布最新版本后,我们应该在最新版本的Android测试自己的应用同时更新target sdk到Android最新版本,以便充分利用Android新版本的特性。举例来说,设置这个值为11或更高,当你的应用运行在Android3.0或更高的系统上时,系统会为你的应用使用新的默认主题(Holo主题),并且当运行在大屏幕的设备上时会禁用屏幕兼容模式(screen compatibility mode),因为支持了 API level 11就暗示了支持大屏幕。

(一)基本配置、依赖管理

Gradle是一种基于Groovy的动态DSL,而Groovy语言是一种基于jvm的动态语言。这里只分享实际开发中会用到的场景,您不需要去学习Groovy语言,知道Java的您是很容易阅读Groovy语言的。
系列博客涉及的知识点有:Gradle基本配置、依赖管理、全局设置、自定义BuildConfig、混淆、多渠道打包、配置签名信息、单元测试,是不是迫不及待了啊,快来学习学习。

基本配置

新建项目,目录结构如下:

app/build.gradle

初始化的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
apply plugin: 'com.android.application'
android {
compileSdkVersion 23
buildToolsVersion "23.0.2"
defaultConfig {
applicationId "com.wuxiaolong.gradle4android"
minSdkVersion 15
targetSdkVersion 23
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.2.1'
compile 'com.android.support:design:23.2.1'
}
1
2
3
4
5
6
7
8
9
apply plugin: ‘com.android.application’,表示该module是一个app module,应用了com.android.application插件,如果是一个android library,那么这里写apply plugin: ‘com.android.library’
compileSdkVersion:基于哪个SDK编译,这里是API LEVEL
buildToolsVersion:基于哪个构建工具版本进行构建的。
defaultConfig:默认配置,如果没有其他的配置覆盖,就会使用这里的。
applicationId:配置包名的
versionCode:版本号
versionName:版本名称
buildTypes是构建类型,常用的有release和debug两种,可以在这里面启用混淆,启用zipAlign以及配置签名信息等。
dependencies:不属于Android专有的配置了,它定义了该module需要依赖的jar,aar,jcenter库信息。

gradle-wrapper.properties

声明了gradle的目录与下载路径以及当前项目使用的gradle版本,这些默认的路径我们一般不会更改的

1
2
3
4
5
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.8-all.zip

根目录的build.gradle

定义在这个工程下的所有模块的公共属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
buildscript {
repositories {
jcenter()//使用jcenter库
}
dependencies {
classpath 'com.android.tools.build:gradle:1.5.0'// 依赖android提供的1.5.0的gradle build
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
//为所有的工程的repositories配置为jcenters
allprojects {
repositories {
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}

setting.gradle

包含哪些模块,比如有app和library:
include ':app',':library'

依赖管理

本地依赖

jar

默认情况下,新建的Android项目会有一个lib文件夹

1
2
3
4
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])//即添加所有在libs文件夹中的jar
//compile files('libs/WuXiaolong.jar')//不需要这样一个个去写了
}
so包

用c或者c++写的library会被叫做so包,Android插件默认情况下支持native包,你需要把.so文件放在对应的文件夹中

1
2
3
4
5
6
7
8
9
10
11
app
├── AndroidManifest.xml
└── jniLibs
├── armeabi
│ └── WuXiaolong.so
├── armeabi-v7a
│ └── WuXiaolong.so
├── mips
│ └── WuXiaolong.so
└── x86
└── WuXiaolong.so
library工程

直接依赖library库:

1
2
3
4
5
dependencies {
compile project(':library名字')
//多个library,libraries是文件夹名字
compile project(':libraries:library名字')
}
aar文件

library库输出文件是.aar文件,包含了Android资源文件,在library工程build/output/aar/下,然后app目录下创建一个aars文件夹,然后把.aar文件拷贝到该文件夹里面,然后添加该文件夹作为依赖库:
app/bulid.gradle

1
2
3
4
5
6
7
8
repositories {
flatDir {
dirs 'aars'
}
}
dependencies {
compile(name:'libraryname', ext:'aar')
}

如何生成.aar文件:
执行./gradlew assembleRelease,然后就可以在build/outputs/aar文件夹里生成aar文件

.jar和.aar区别:
*.jar:只包含了class文件与清单文件,不包含资源文件,如图片等所有res中的文件;
*.aar:包含所有资源,class以及res资源文件全部包含。

注意:
如果你的library依赖了第三方库aar,须app再次依赖。比如lib1依赖了lib2 的aar,app依赖lib1,需要:

1
2
3
4
dependencies {
compile(name: 'library1-release', ext: 'aar')
compile(name: 'library2-release', ext: 'aar')
}

远程仓库

1
2
3
dependencies {
compile 'com.wuxiaolong.pullloadmorerecyclerview:library:1.0.4'
}

(二)全局设置、自定义BuildConfig、混淆

全局设置

如果有很多项目,可以设置全局来统一管理版本号或依赖库,根目录下build.gradle下:

1
2
3
4
5
6
ext {
compileSdkVersion = 23
buildToolsVersion = "23.0.2"
minSdkVersion = 14
targetSdkVersion = 23
}

app/build.gradle

1
2
3
4
5
6
7
8
9
10
android {
compileSdkVersion rootProject.ext.compileSdkVersion
buildToolsVersion rootProject.ext.buildToolsVersion
defaultConfig {
applicationId "com.wuxiaolong.gradle4android"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 1
versionName "1.0"
}

可以在根目录下建个config.gradle,然后只需在根目录下build.gradle最顶部加上下面一行代码,然后同步下,意思就是所有的子项目或者所有的modules都可以从这个配置文件里读取内容。
apply from: "config.gradle"

config.gradle

1
2
3
4
5
6
7
8
9
10
11
12
ext {
android = [
compileSdkVersion: 23,
buildToolsVersion: "23.0.2",
minSdkVersion : 14,
targetSdkVersion : 22,
]
dependencies = [
appcompatV7': 'com.android.support:appcompat-v7:23.2.1',
design : 'com.android.support:design:23.2.1'
]
}

app/build.gradle

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
android {
compileSdkVersion rootProject.ext.android.compileSdkVersion
buildToolsVersion rootProject.ext.buildToolsVersion
defaultConfig {
applicationId "com.wuxiaolong.gradle4android"
minSdkVersion rootProject.ext.android.minSdkVersion
targetSdkVersion rootProject.ext.android.targetSdkVersion
versionCode 1
versionName "1.0"
}

...
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile rootProject.ext.dependencies.appcompatV7
compile rootProject.ext.dependencies.design
}

自定义BuildConfig

实际开发中服务器可能有正式环境和测试环境,gradle可以通过app/build.gradle下的buildConfigField来配置。

1
2
3
defaultConfig {
buildConfigField 'String','API_SERVER_URL','"http://wuxiaolong.me/"'
}

buildConfigField 一共有3个参数,第一个是数据类型,和Java的类型是对等的;第二个参数是常量名,这里是API_SERVER_URL;第三个参数就是你要配置的值。

如图路径下就有个常量API_SERVER_URL,如何在代码取得这个常量值:
Log.d("wxl", "API_SERVER_URL=" + BuildConfig.API_SERVER_URL);

启用proguard混淆

一般release发布版本是需要启用混淆的,这样别人反编译之后就很难分析你的代码,而我们自己开发调试的时候是不需要混淆的,所以debug不启用混淆。对release启用混淆的配置如下:

1
2
3
4
5
6
7
8
9
android {
buildTypes {
release {
minifyEnabled true//是否启动混淆
shrinkResources true //是否移除无用资源文件,shrinkResources依赖于minifyEnabled,必须和minifyEnabled一起用
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}

minifyEnabled为true表示启用混淆,proguardFile是混淆使用的配置文件,这里是module根目录下的proguard-rules.pro文件

(三)多渠道打包、配置签名信息

多渠道打包

国内有太多Android App市场,每次发版几十个渠道包。还好Android Gradle给我们提供了productFlavors,我们可以对生成的APK包进行定制。

1
2
3
4
5
6
7
8
productFlavors {//多渠道打包
xiaomi {
applicationId 'com.wuxiaolong.gradle4android1'
}
googlepaly {
applicationId 'com.wuxiaolong.gradle4android2'
}
}

定制生成的apk文件名

1
2
3
4
5
6
7
8
9
10
11
applicationVariants.all { variant ->
if (variant.buildType.name.equals('release')) {
variant.outputs.each { output ->
def outputFile = output.outputFile
if (outputFile != null && outputFile.name.endsWith('.apk')) {
def fileName = "gradle4android_v${defaultConfig.versionName}_${releaseTime()}_${variant.flavorName}.apk"
output.outputFile = new File(outputFile.parent, fileName)
}
}
}
}

输出apk名字:gradle4android_v1.0_2016-03-23_xiaomi.apk

注意:在Android Studio 3.0版本中,上面的做法编译报错:

1
Error:(56, 0) Cannot set the value of read-only property 'outputFile' for ApkVariantOutputImpl_Decorated{apkData=Main{type=MAIN, fullName=debug, filters=[]}} of type com.android.build.gradle.internal.api.ApkVariantOutputImpl.​

解决 :修改文件名代码请这样写

1
2
3
4
5
android.applicationVariants.all { variant ->
variant.outputs.all {
outputFileName = "xinlebao_${defaultConfig.versionName}_${releaseTime()}.apk"
}
}

占位符

多渠道打包,还会遇到一个问题,比如友盟统计的渠道号,Gradle处理办法:manifestPlaceholders,它允许我们动态替换我们在AndroidManifest文件里定义的占位符。
AndroidManifest.xml:

1
2
3
<meta-data
android:name="UMENG_CHANNEL"
android:value="${UMENG_CHANNEL_VALUE}" />

如下,${UMENG_CHANNEL_VALUE}占位符会被dev替换。

1
2
3
defaultConfig {
manifestPlaceholders = [UMENG_CHANNEL_VALUE: 'dev']
}

如果渠道太多,不用这样一个个去写,可以循环:

1
2
3
productFlavors.all { flavor ->
manifestPlaceholders.put("UMENG_CHANNEL_VALUE",name)
}

渠道打包完整代码:

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
android {
//省略部分代码
buildTypes {
release {
minifyEnabled false//是否启动混淆
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
applicationVariants.all { variant ->
if (variant.buildType.name.equals('release')) {
variant.outputs.each { output ->
def outputFile = output.outputFile
if (outputFile != null && outputFile.name.endsWith('.apk')) {
def fileName = "gradleTest_v${defaultConfig.versionName}_${releaseTime()}_${variant.flavorName}.apk"
output.outputFile = new File(outputFile.parent, fileName)
}
}
}
}
//针对很多渠道
//productFlavors.all { flavor ->
// manifestPlaceholders.put("UMENG_CHANNEL_VALUE",name)
// }
}
}
productFlavors {//多渠道打包,命令行打包:gradlew assembleRelease
xiaomi {
applicationId 'com.wuxiaolong.gradle4android1'
manifestPlaceholders.put("UMENG_CHANNEL_VALUE", 'xiaomi')
}
googlepaly {
applicationId 'com.wuxiaolong.gradle4android2'
manifestPlaceholders.put("UMENG_CHANNEL_VALUE", 'googlepaly')
}
}
//省略部分代码
def releaseTime() {
return new Date().format("yyyy-MM-dd", TimeZone.getTimeZone("UTC"))
}

配置签名信息

Android Studio设置默认的签名文件

新浪微博SSO登录,微信分享这些都需要签名打包,才能看到效果,设置默认签名文件为自己的签名jks,这样就不需要打包了直接运行起来就是正式的签名。
android.signingConfigs{}下定义一个或者多个签名信息,然后在buildTypes{}配置使用即可。
在app目录下添加你的.jks,然后app的build.gradle文件中的增加以下内容:
第一种:

1
2
3
4
5
6
7
8
9
10
android {  
signingConfigs {
debug {
storeFile file("WuXiaolong.jks")
storePassword 'android'
keyAlias 'android'
keyPassword 'android'
}
}
}

buildTypes没有配置,也是直接取得debug,是不是不配置默认取得是debug呢?
第二种:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
android {  
signingConfigs {
release {
storeFile file("WuXiaolong.jks")
storePassword 'android'
keyAlias 'android'
keyPassword 'android'
}
}
buildTypes {
debug {
signingConfig signingConfigs.release
}
}
}

签名打包

通过Android Studio签名

这里不细说了。

通过命令行签名

如上那样配置签名信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
android {  
signingConfigs {
release {
storeFile file("WuXiaolong.jks")
storePassword 'android'
keyAlias 'android'
keyPassword 'android'
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
}
}
}

build-clean Project,然后Terminal输入命名行:
gradlew assembleRelease

打印信息如下:

1
2
3
4
5
6
7
8
9
10
E:\AndroidStudioProjects\Gradle4Android>gradlew assembleRelease
:app:preBuild UP-TO-DATE
:app:preReleaseBuild UP-TO-DATE
:app:checkReleaseManifest
//省略部分
:app:packageRelease
:app:zipalignRelease
:app:assembleRelease

BUILD SUCCESSFUL

OK,打包成功的apk路径如:E:\AndroidStudioProjects\Gradle4Android\app\build\outputs\apk\app-release.apk

完整配置

https://github.com/WuXiaolong/Gradle4Android

附录

Gradle for Android 第一篇( 从 Gradle 和 AS 开始 )
使用Gradle管理你的Android Studio工程