Gradle让Android中的依赖管理、库管理、渠道管理以及一些动态地编译配置变得极为方便!!
本文是对Gradle在Android项目中进阶使用的知识点整理和简要讲解
较为详细的Gradle教科书Github
Gradle脚本配置文档:Google Githubjavascript
下面简述对咱们工程最重要的几个Gradle文件,后续也会围绕他们进行详细讲解和补充
(请仔细看代码中的注释哈)html
build.gradle
: 工程控制Gradle编译配置build.gradle
: 控制每一个Module的编译过程gradle.properties
: gradle动态参数的配置文件local.properties
: 本地的配置,如:SDK位置gradle-wrapper.properties
:gradle本地代理,声明了指向目录和版本
distributionUrl
: 指定gradle版本不存在时,就从Value的地址中去下载。不少时候,咱们只要版本换成咱们本地存在的gradle版本就能够了settings.gradle
: 配置Gradle中的Module管理~
表示 gradlewgradlew task -all
: 罗列出全部Task ,同时携带具体做用和相互关系gradlew assembleDebug
: 导出全部渠道测试包java
~ assembleRelease
: 导出全部渠道正式包~ assembleBaiduDebug --stacktrace
: 导出指定渠道测试包,同时携带异常信息~ --stop
: 当即中止编译react
~ check
: 检查任务~ build
: 执行了 check和assemble~ clean
: 清除全部中间编译结果在Gradle中动态配置资源参数
咱们能够根据各自的需求在不一样的领域(如:buildType 的debug, defaultConfig ...)下去动态替换或配置咱们项目中所使用到的资源,如 log 开关, 针对不一样渠道的对应内容字段,不一样版本定义引入的不一样值等等android
首先说清一点,对于动态资源在build.gradle
中多个领域中的使用,会遵循一下顺序来进行覆盖:
buildType > productFlavor > defaultConfig > Manifest中的配置 > 依赖的第三方库的配置 > 任意领域中的默认值(也就是没有设置值)git
Manifest
占位符: 能够动态配置Manifest的参数在Manifest的Application节点下
//这里以友盟为例
<!-- 友盟统计相关meta-data -->
<meta-data
android:name="UMENG_APPKEY"
android:value="balabalabala" />
<meta-data
android:name="UMENG_CHANNEL"
android:value="${UMENG_CHANNEL_VALUE}" />
在build.gradle中对参数进行动态配置
productFlavors {
baidu {
manifestPlaceholders = [UMENG_CHANNEL_VALUE: "baidu"]
}
}复制代码
gradle.properties
的使用
systemProp.proName=123
System.properties['proName']
ray.proName=123
,无key : proName = 123
project。property('proName')
, 无key : proName
gradle.properties中的配置
#使用系统参数配置
systemProp.keyStore=ray.jks
#使用key/value键值对配置
ray.keyPassword=123456
#属性配置
mKeyAlias=ray
build.gradle中的使用
//签名打包
release {
//签名文件所在路径
storeFile file(System.properties['keyStore'])
//签名密码
storePassword "111111"
//别名
keyAlias mKeyAlias
keyPassword project.property('ray.keyPassword')
}复制代码
BuildConfig
文件
app/build/generated/source/buildConfig
文件夹下面buildConfigField "String" , "key" , "\"value\""
buildConfig
中的属性参数 String
: 参数类型(int,boolean...), key
: 属性的名字, value
: 属性的值, \
为转义字符resValue
动态修改工程资源
resValue("string","key","value")
string
表示 会在 app/build/generated/res/resValue/.../generated.xml
中生成对应的String 的 key 和Value, 代码中能够直接getResources().getString(R.string.key);
获取到value//下面模拟在不一样渠道下修改资源参数
productFlavors{
baidu{
buildConfigField "String" , "productCode" , "\"baidu 1.0\""
resValue("string","productName","baidu")
}
}复制代码
build.gradle
的buildscript
中声明ext
和自定义属性,而后在其余module中就能够直接使用这个属性了Project : build.gradle
buildscript {
//自定义工程使用的属性
ext {
kotlin_version = '1.1.0'
compile_version = 25
}
//声明依赖Android Gradle 插件版本
dependencies {
classpath 'com.android.tools.build:gradle:2.3.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
Module : build.gradle 中使用
Android
{
compileSdkVersion compile_version
}
dependencies
{
compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
}复制代码
text.gradle
, 而后在Project
中引入,最后就能够在其余的module中直接使用了,具体应用能够参考印象笔记Githubtext.gradle 编写以下:
ext {
kotlinVersion = "1.1.0"
rxjavaLibVersion = "1.2.0"
dependencies = [
// Rx
rxJava: "io.reactivex:rxjava:$rxjavaLibVersion"
]
}
Project : build.gradle 中引入
//就是引入他的相对根目录路径
apply from: 'config/text.gradle'
Module : build.gradle 中使用
rootProject.ext.XXXXX
dependencies {
def dependencies=rootProject.ext.dependencies
compile dependencies.rxJava
compile "org.jetbrains.kotlin:kotlin-stdlib:$rootProject.ext.kotlinVersion"
}复制代码
//声明引入的参数配置文件
apply from: 'config/dependencies.gradle'
apply from: 'config/text.gradle'
//编译配置
buildscript {
//自定义参数
ext {
kotlin_version = '1.1.0'
compile_version = 25
}
//Gradle指定使用jcenter代码仓库
repositories {
jcenter()
}
//声明依赖Android Gradle 插件版本
dependencies {
classpath 'com.android.tools.build:gradle:2.3.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
//这里能够为项目总体配置属性
allprojects{
repositories {
jcenter()
}
}
//任务:每次构建的时候删除指定目录
task clean(type: Delete) {
delete rootProject.buildDir
}复制代码
控制每一个Module的编译过程以及具体的参数配置github
基本配置信息segmentfault
//默认配置
defaultConfig {
//包名
applicationId "com.rayhahah.gradledemo"
//最低版本
minSdkVersion 19
//目标版本
targetSdkVersion 25
//版本代码
versionCode getVersinCode()
//版本
versionName "1.0"
//自动化测试
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
resValue "int","test","1"
}复制代码
签名配置信息api
signingConfigs {
//debug模式签名文件
debug {}
//签名打包
release {
//签名文件所在路径
storeFile file("ray.jks")
//签名密码
storePassword "111111"
//别名
keyAlias "rayhahah"
keyPassword "111111"
}
//自定义签名配置
ray{
//和上面的属性一致,根据我的需求实现不一样配置
}
}复制代码
编译类型 : 指定编译不一样类型状况下的不一样配置信息
这里是列举了部分属性和方法,所有的方法和属性请看官网文档浏览器
//构建配置
buildTypes {
release {
//是否启用资源优化
minifyEnabled
//启用舍弃无用资源,只有当开启混淆才可以启用
shrinkResources false
//指定混淆文件
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
//指定咱们release包的输出文件名就是咱们的渠道名字
applicationVariants.all { variant ->
variant.outputs.each { output ->
def outputFile = output.outputFile
if (outputFile != null && outputFile.name.endsWith(".apk")) {
def fileName = "${variant.productFlavors[0].name}" + ".apk"
output.outputFile = new File(outputFile.parent, fileName);
}
}
}
}
debug {
}
//继承
// rayhahah.initWith(debug)
//自定义buildType
rayhahah {
//指定签名配置文件
signingConfig signingConfigs.debug
//包名增长后缀
applicationIdSuffix ".ray"
}
}复制代码
配置资源逻辑组
指定Android所须要文件夹所在具体路径
sourceSets {
//这样的配置适用于将Eclipse中的项目结构迁移到AndroidStudio中
main {
//指定src资源目标目录
java.srcDirs = ['src']
//指定asset的目标目录
assets.srcDirs = ['assets']
//指定res的目标目录
res.srcDirs = ['res']
//指定依赖C文件的目标目录
jni.srcDirs = ['jni']
//指定依赖so文件的目标目录
jniLibs.srcDirs = ['libs']
//指定Manifest的目标文件路径
manifest.srcFile 'AndroidManifest.xml'
}
}复制代码
1. 在res下新建文件夹 layouts(其实叫什么都无所谓)
2. 而后在 layouts下 新建你要分的包 如: activity,fragment 或按照业务模块来分
3. 在分包内新建Android resource directory -> layout 不要更名字
4. 在module:build gradle 以下配置
5. 而后将之前的layout文件拷贝到对应分包的layout下就可使用了
PS:只有在Project目录才能看到,Android目录结构是看不到的
sourceSets {
main {
res.srcDirs = [
'src/main/res/layouts/activity',
'src/main/res/layouts/fragment',
'src/main/res/layouts',
'src/main/res'
]
}
}复制代码
打包渠道配置信息(仔细看代码注释)
//多渠道打包配置
//利用Manifest占位符动态参数配置
productFlavors {
baidu {
manifestPlaceholders = [UMENG_CHANNEL_VALUE: "baidu"]
}
wandoujia {
manifestPlaceholders = [UMENG_CHANNEL_VALUE: "wandoujia"]
}
googleplayer {
manifestPlaceholders = [UMENG_CHANNEL_VALUE: "googleplayer"]
}
//不想每个都去配置渠道名称也能够用下面这个函数
//这个函数能够将 Manifest中的占位符替换成 每一个渠道的名字
productFlavors.all {
flavor -> flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]
}
}复制代码
//编译配置项
//主要配置Java编译版本
compileOptions {
sourceCompatibility org.gradle.api.JavaVersion.VERSION_1_8
targetCompatibility org.gradle.api.JavaVersion.VERSION_1_8
}复制代码
//lint配置项
lintOptions {
//启用出错中止grgradle构建
abortOnError false
// true--检查全部问题点,包含其余默认关闭项
checkAllWarnings true
// 关闭指定问题检查
disable 'TypographyFractions','TypographyQuotes'
// 打开指定问题检查
enable 'RtlHardcoded','RtlCompat', 'RtlEnabled'
// 仅检查指定问题
check 'NewApi', 'InlinedApi'
// true--生成HTML报告(带问题解释,源码位置,等)
htmlReport true
// html报告可选路径(构建器默认是lint-results.html )
htmlOutput file("lint-report.html")
// 忽略指定问题的规则(同关闭检查)
ignore 'TypographyQuotes'
}复制代码
AndroidStuido 给咱们提供了十分友好地对于Build.gradle 图形化配置的界面,使用以下:
//dependencies : 当前Android Module构建过程当中所依赖的全部库
dependencies {
//依赖指定目录下全部指定后缀的文件
compile fileTree(dir: 'libs', include: ['*.jar'])
//测试工具依赖
testCompile 'junit:junit:4.12'
//远程库的依赖 (当从远程库中下载一次事后,就会缓存到本地了)
//默认远程库配置为 jcenter()
compile 'com.android.support:appcompat-v7:25.2.0'
//依赖指定文件(这里依赖的是jar包)
compile file('libs/test-1.0.0.jar')
//依赖本地项目库
compile project(':testLibrary')
//格式: groupId: com.squareup.retrofit2
// artifactId : retrofit
// version: 2.1.0
// SNAPSHOT : 表示依赖 retrofit 及其依赖的全部项目,若是他所依赖的项目在本项目中重复出现依赖,则只依赖retrofit项目中的。
// @aar : 表示只依赖retrofit,不依赖他所依赖的项目
compile ('com.squareup.retrofit2:retrofit:2.1.0-SNAPSHOT@aar')
{
//强制刷新远程库,避免远程库刷新,本地未更新
transitive = true
//exclude : 单独去除okhttp3的依赖
exclude module : 'com.squareup.okhttp3:okhttp:3.3.0'
}
}复制代码
so库依赖
src/main
目录下建立jniLibs
,而后将so文件拷贝进去就能够了sourceSet
指定jniLib
的目标目录来自定义管理依赖的so文件存放本地Module依赖
build.gradle
的dependencies
领域中添加 compile project(':testLibrary')
setting.gradle
中添加module到include
中 如:include ':app',':testLibrary'
在Gradle中你能够写方法供 配置信息动态调用
//自定义函数
def getVersinCode() {
// ......
}
Android{
defaultConfig{
versionCode getVersinCode()
}
}复制代码
gradlew build -profile
: 编译工程同时生成编译性能分析文件,在根目录build/reports/profile/profile-xxxx.xxx....html
,经过浏览器打开之后Task Execution
能够看到lint耗时最多,而后咱们就能够根据本身项目中的具体状况来作优化
Project:build.gradle
中的 buildScript
中动态配置编译时禁用便可, 代码:gradle.startParameter.excludedTaskNames.add('lint')
就能够实现禁用了,具体须要继续禁用的能够根据项目输出的编译分析文件来做出添加和调整aapt即Android Asset Packaging Tool,在SDK的build-tools目录下。该工具能够查看,建立, 更新ZIP格式的文档附件(zip, jar, apk)。也可将资源文件编译成二进制文件,尽管你可能没有直接使用过aapt工具,可是build scripts和IDE插件会使用这个工具打包apk文件构成一个Android 应用程序(百度百科)
aaptOtions{
cruncherEnabled = false
}复制代码
gradle.properties
中配置//开启守护线程支持
org.gradle.daemon=true
//开启并行编译
org.gradle.parallel=true
//按需编译
org.gradle.configureondemand=true
//手动配置Gradle编译时内存分配
# Default value: -Xmx10248m -XX:MaxPermSize=256m
org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
# 开启JNI编译支持过期API
android.useDeprecatedNdk=true复制代码
build.gradle
中配置 //增长编译内存到4g
dexOptions{
incremental true
javaMaxHeapSize "4g"
}复制代码
task testTask << {
println 'testTask << print'
// 表示在task最前面来执行的过程
doFirst {
println 'testTask do first'}
// << 和 doLast表示对当前task追加执行过程,效果是同样的
doLast{
println 'testTask do last!'}
}
//task之间的依赖 dependsOn
//当执行存在依赖的task时,会先执行他的父类也就是依赖目标
task testDependsOn(dependsOn:testTask){
println 'testDependsOn default print '
}
//或者
testDependsOn.dependsOn testTask
//当执行testDependsOn是 打印顺序: testDependsOn default print -> testTask do first -> testTask << print -> testTask do last!
//顺序总结为:
//1.不加doLast和doFirst的最早执行
//2.依赖task优先级高于本身的doFirst和doLast
//3.同一个task中的doLast按从上向下顺序执行
//4.同一个task中的doFirst按从下到上倒序执行
//5.同一个task的doFirst优先级高于doLast
//显示声明类型为Copy, 不声明默认为defaultTask
task testCopy(type : Copy){
//将当前gradle文件从src目录拷贝到dst目录
from "src"
into "dst"
}
//每个特定的Task类型还能够含有特定的Property,好比Copy的from和to等。
//自定义property
ext.testProperty = ""
task testExtProperty << {
//直接使用自定义的property
println testProperty
}复制代码
//局部自定义Task
//直接在build.gradle中自定义Task
//可是也只能在当前module中引用
class TestCustomTask extends DefaultTask {
//@Optional,表示在配置该Task时,message是可选的。
@Optional
String message = 'I am jjx'
//@TaskAction表示该Task要执行的动做,即在调用该Task时,hello()方法将被执行
@TaskAction
def hello() {
println "hello world $message"
}
}
//hello使用了默认的message值
task hello(type: TestCustomTask)
//从新设置了message的值
task helloOne(type: TestCustomTask) {
message = "I am a android developer"
}
全局自定义Task
若是须要自定义大量的Task,就要新建一个Gradle文件来统一管理
经过apply来引入使用
//这是插件
apply plugin: 'com.android.application'
//这里gradle-quality.gradle就是另外单独定义了task的gradle
apply from: '../build-config/gradle-quality.gradle'复制代码
自定义Plugin可让咱们在工程编译根据需求中自动去完成一些操做
下面就是一个编译后自动打印当前时间的Plugin
与自定义Task十分相似
能够在build.gradle中自定义plugin
apply plugin: DateAndTimePlugin
dateAndTime {
timeFormat = 'HH:mm:ss.SSS'
dateFormat = 'MM/dd/yyyy'
}
class DateAndTimePlugin implements Plugin<Project> {
//该接口定义了一个apply()方法,在该方法中,咱们能够操做Project,
//好比向其中加入Task,定义额外的Property等。
void apply(Project project) {
//加载Extension
project.extensions.create("dateAndTime", DateAndTimePluginExtension)
//使用Extension配置信息
project.task('showTime') << {
println "Current time is " + new Date().format(project.dateAndTime.timeFormat)
}
project.tasks.create('showDate') << {
println "Current date is " + new Date().format(project.dateAndTime.dateFormat)
}
}
}
//每一个Gradle的Project都维护了一个ExtenionContainer,
//咱们能够经过project.extentions进行访问
//好比读取额外的Property和定义额外的Property等。
//向Project中定义了一个名为dateAndTime的extension
//并向其中加入了2个Property,分别为timeFormat和dateFormat
class DateAndTimePluginExtension {
String timeFormat = "MM/dd/yyyyHH:mm:ss.SSS"
String dateFormat = "yyyy-MM-dd"
}复制代码
其实本质上就是对上面的自定义Plugin结构化拆解
Plugin目录建立
buildSrc
buildSrc/src/main/groovy/com/ray
和 buildSrc/src/main/resources/META-INF/gradle-plugins
建立buildSrc/build.gradle
, 配置以下
apply plugin:'groovy'
dependecies{
compile gradleApi()
compile localGroovy()
}复制代码
Plugin
逻辑实现buildSrc/src/main/groovy/com/ray
下建立DateAndTimePlugin
class DateAndTimePlugin implements Plugin<Project> {
void apply(Project project) {
//加载Extension
project.extensions.create("dateAndTime", DateAndTimePluginExtension)
//使用Extension中的配置信息
project.task('showTime') << {
println "Current time is " + new Date().format(project.dateAndTime.timeFormat)
}
project.tasks.create('showDate') << {
println "Current date is " + new Date().format(project.dateAndTime.dateFormat)
}
}
}复制代码
Extension
实现Extension
至关于Gradle配置信息(至关于实体类),而后主项目的build.gradle
经过Extension
传递配置(至关于赋值)一样在buildSrc/src/main/groovy/com/ray
下建立DateAndTimePluginExtension
//每一个Gradle的Project都维护了一个ExtenionContainer,
//咱们能够经过project.extentions进行访问
//好比读取额外的Property和定义额外的Property等。
//向Project中定义了一个名为dateAndTime的extension
//并向其中加入了2个Property,分别为timeFormat和dateFormat
class DateAndTimePluginExtension {
String timeFormat = "MM/dd/yyyyHH:mm:ss.SSS"
String dateFormat = "yyyy-MM-dd"
}复制代码
Plugin命名
自定义外部引用时Plugin的名字
在buildSrc/src/main/resources/META-INF/gradle-plugins
下建立timePlugin.properties
,内容只有一行代码 : implementation-class = com.ray.DateAndTimePlugin
Plugin的使用
主项目中apply plugin:'timePlugin'
可选:配置Extension
:
timePlugin{
//动态修改和配置Extension属性
//这里修改了日期格式
timeFormat = 'MM/dd/yyyy'
}复制代码
buildSrc/build.gradle
的修改 以下:apply plugin: 'groovy'
//增长Maven的支持
apply plugin: 'maven'
version = 1.0
group = 'com.ray.plugin'
archivesBaseName = 'timeplugin'
repositories.mavenCentral()
dependencies {
compile gradleApi()
groovy localGroovy()
}
//将插件部署到repo目录下
uploadArchives {
repositories.mavenDeployer {
repository(url: uri('../repo'))
}
}复制代码
apply plugin: 'timePlugin'
buildscript {
repositories {
maven {
url uri('../repo')
} }
dependencies {
classpath group: 'com.ray.plugin', name: 'timePlugin',
version: '1.0'
}
}复制代码
以上就是总结的Gradle实用的进阶指南,让咱们能够更加为所欲为地去管理咱们的工程。之后若是有一些新的认识或者想法,我也会在这里实时更新的。也算是本身对Gradle认识和学习的总结整理吧。
正确使用Gradle的配置是为了让咱们开发更加便捷、效率更高,千万不要本末倒置了。
文中哪里有错误的话,欢迎你们指出纠正
若是文章对你有用的话,请点赞鼓励一下哈O(∩_∩)O~~~~
参考和感谢如下博文和项目: