1.build.gradle讲解
首先我将一个demo项目中的一份build.gradle拿出来讲解下
apply plugin: 'com.android.application'
apply plugin: 'com.jakewharton.butterknife'
android {
//签名配置
signingConfigs {
//签名Name
config {
//签名别名
keyAlias 'gjn'
//签名别名密码
keyPassword '11223344'
//签名文件位置
storeFile file('D:/project/MyDemo/gjnKey.jks')
//签名密码
storePassword '11223344'
}
}
//开发环境版本号
compileSdkVersion 26
//默认配置
defaultConfig {
//Id
applicationId "com.gjn.mydemo"
//最小支持版本号
minSdkVersion 19
//运行版本号
targetSdkVersion 25
//appCode
versionCode 1
//app版本号
versionName "1.0"
//测试相关
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
//Build类型 默认有release和debug两个版本
buildTypes {
release {
//是否开始混淆
minifyEnabled false
//混淆文件路径
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
//打包时候调用的签名
signingConfig signingConfigs.config
//在BuildConfig生成一个String类型的Host=release_Host
//即 public static final String Host = "release_Host";
buildConfigField "String", "Host", "\"release_Host\""
//编译之后会在res文件中的string.xml中加入一个string类型的app_name1=myMode
//即 myMode
resValue "string", "app_name1", "myMode"
//修改build之后的app名称
//这边编译出来的名字是 release_1.0.apk
//这个写法是Android Studio 3.0之后的方法
android.applicationVariants.all { variant ->
variant.outputs.all {
outputFileName = "${variant.name}_${variant.versionName}.apk"
}
}
}
debug {
//为Id添加后缀 这边生成新的Id为com.gjn.mydemo.debug
applicationIdSuffix ".debug"
//这边下面和上面是一样
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
buildConfigField("String", "Host", "\"debug_Host\"")
resValue("string", "app_name1", "myModedebug")
//占位符 替换AndroidManifest.xml 中的${test_key}字符
//AndroidManifest.xml中的源代码为
//
//替换之后
//
manifestPlaceholders = ["test_key": "debug_key"]
}
}
//多版本
productFlavors{
//dev版本
dev{
manifestPlaceholders = ["test_key": "release_key"]
}
//free版本
free{
//这边在提下,由于free也会有release和debug两个版本
//release的Id为com.gjn.mydemo.free
//debug的Id为com.gjn.mydemo.free.debug
applicationIdSuffix ".free"
manifestPlaceholders = ["test_key": "free_key"]
}
}
//遍历了全部版本
productFlavors.all{
//设置统一Code Android Studio 3.0之后需要设置这个属性 不然构建多版本的时候会报错
flavorDimensions("versionCode")
}
}
//导入第三方之类的jar aar 等 就不说了
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'com.android.support:appcompat-v7:26.1.0'
implementation 'com.android.support:design:26.1.0'
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.1'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
implementation 'com.jakewharton:butterknife:8.7.0'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.7.0'
implementation 'com.github.bumptech.glide:glide:3.7.0'
implementation 'com.google.code.gson:gson:2.8.0'
implementation 'com.squareup.okhttp3:okhttp:3.8.1'
implementation 'io.reactivex.rxjava2:rxjava:2.1.1'
implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
implementation 'com.squareup.retrofit2:retrofit:2.3.0'
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'
implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
}
我将大部分内容都设置了备注,可以看到很多常用的属性设置。还有许多其他的,后续在补充
2.Groovy讲解
这边我稍微对Groovy的语法和逻辑说一点!
首先说下
关于注释之类和java是一样的
- 字符串
在java中就只有一种"android"
而Groovy中有
单行'android'
, "android"
多行 '''android'''
, """android""
还有/.../
,${...}
- 集合(List,Map)
List
创建和初始化
def list = [1,'hello',false]
这边不需要List中的每个类型都相同,当然Map也一样。
使用
println list[1] //输出 hello
println list[-1] //输出 false
list[1] = 5 //5 替换 hello
list[0] = "android" //android 替换 1
list << "gjn" //追加 gjn
list.each { l -> //遍历整个list
println l //每次输出一项
}
结果
hello
false
android
5
false
gjn
Map
创建和初始化
def map = [1:'hello',android:233,b:false]
使用
println map[1] //输出 hello
println map.b //输出 false
map << [2:33] //追加 2:33
map.each { k,v-> //遍历map
println k+":"+v
}
结果
hello
false
1:hello
android:233
b:false
2:33
- 数组
关于数组
groovy 其实没有严格区分数组和集合,数组的定义和使用方法跟集合一样,只是你需要强制声明为数组,否则默认为集合。
创建和初始化
String[] arrString = ['hello',"android","""groovy
=============="""]
def arrNum = [1,2,3] as int[]
直接String[]和Java一样是创建数组
as int[]是把arrNum设置为数组,不然就会变成集合
使用
arrString.each {str->
println str
}
arrNum.each {num->
println num
}
结果
hello
android
groovy
==============
1
2
3
- 遍历
groovy中的遍历有2个each{...}
和all{...}
遍历在上面的数组和集合都使用了,大体上都知道使用了。
拿第一个说下each就是Java中的foreach
list.each { l -> //遍历整个list
println l //每次输出一项
}
其实就等于Java中的
List list = new ArrayList<>();
for(String l : list){
System.out.println(l);
}
all和each的使用是一样的,区别我查了下,有提到是each使用的是迭代,不能实时修改值,all使用的是拾取对象,可以修改值。好比ArrayList和CopyOnWriteArrayList的区别吧!
我也不太确定,只是在 Android Gradle 3.0.0-alpha2 plugin, Cannot set the value of read-only property 'outputFile'
中有看到。
- 方法简化使用
groovy的一个特性
groovy 定义方法时可以不声明返回类型和参数类型,也可以不需要 return 语句,最后一行代码默认就是返回值。使用的时候也可以不需要添加括号。
使用1
def add(a,b){
a+b
}
def str = add 1,2
println str //结果为3
结果1
3
这边我们就能发现很多在build.gradle中的参数的真实代码
例如
compileSdkVersion 26
就是 compileSdkVersion(26)
applicationId "com.gjn.mydemo"
就是 applicationId("com.gjn.mydemo")
等等
使用2
def getmap(Map map){
map.each {
println it.key + ":" + it.value
}
}
def map = [1:"hello",2:true]
getmap map
def map2 = [add:'groovy']
getmap map2
getmap add:'groovy test'
结果2
1:hello
2:true
add:groovy
add:groovy test
这次使用我们就发现了一个getmap add:'groovy test'
和build.gradle中的apply plugin: 'com.android.application'
很像有没有。
如果按照我们上面的写法,那么原本的apply方法就是
apply plugin: 'com.android.application'
等于
def map = [plugin: 'com.android.application']
apply(map)
- 闭包
闭包是 groovy 的一大特性,例如build.gradle中的android{...}
,defaultConfig{...}
,buildTypes{...}
,dependencies{...}
等 这些都是闭包的使用
使用
def add(a,Closure c){
println a + c.call()
}
add(1,{2+3})
add 1,{
5+6
}
结果
6
12
使用2
def myprintln(Closure c){
println c.call()
}
myprintln {
123
}
myprintln {
"Msss"
}
myprintln {
123+"Msss"
}
结果2
123
Msss
123Msss
Android Studio的build.gradle代码整合优化
继续来说关于build.gradle代码优化。这边我们拿最开始的build.gradle代码进行优化。
说是优化,其实就是吧一些东西写在另一个gradle文件下,然后直接调用就好了。而且把部分参数写在另一个gradle中,修改这些代码的时候,就根本不需要Sync build.gradle代码,也算加快了编译速度吧!
首先我们在项目的project目录下新建一个config.gradle文件
注:要让config.gradle代码能够在app的build.gradle中使用,在主项目的build.gradle中加入 apply from:'config.gradle'
表示导入config文件代码
具体位置如下
apply from:'config.gradle'
buildscript {
repositories {
....
}
dependencies {
....
}
}
allprojects {
repositories {
....
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
创建好config.gradle文件之后写入一个ext{}
默认如下
ext{
}
然后我们看下,哪些可以写在config中
这边我选了签名相关、APP的版本、正式版和测试版之间相同的数据设置、加载第三方库dependencies相关这几项
所以我在config中加入
ext{
SigningConfigs = [
]
DefaultConfig = [
]
Release = [
]
Debug = [
]
Dependencies = [
]
}
之后我们对比原来的build.gradle进行配置config文件
ext{
SigningConfigs = [
keyAlias : 'gjn',
keyPassword : '11223344',
storeFile : 'D:/project/MyDemo/gjnKey.jks',
storePassword : '11223344'
]
DefaultConfig = [
versionCode : 1,
versionName : "1.0"
]
Release = [
"Host_bcf":"release_Host",
"appname_res": "myMode",
"test_key_mp": "release_key"
]
Debug = [
"Host_bcf":"debug_Host",
"appname_res": "myModedebug",
"test_key_mp": "debug_key"
]
Dependencies = [
appcompat:'com.android.support:appcompat-v7:26.1.0',
design:'com.android.support:design:26.1.0',
constraint:'com.android.support.constraint:constraint-layout:1.0.2',
butterknife:'com.jakewharton:butterknife:8.7.0',
glide:'com.github.bumptech.glide:glide:3.7.0',
gson:'com.google.code.gson:gson:2.8.0',
okhttp:'com.squareup.okhttp3:okhttp:3.8.1',
rxjava:'io.reactivex.rxjava2:rxjava:2.1.1',
rxandroid:'io.reactivex.rxjava2:rxandroid:2.0.1',
retrofit:'com.squareup.retrofit2:retrofit:2.3.0',
adapterrxjava2:'com.squareup.retrofit2:adapter-rxjava2:2.3.0',
convertergson:'com.squareup.retrofit2:converter-gson:2.3.0',
]
}
现在看下如何在build.gradle中使用
首先先创建好对应的def
def sc = rootProject.ext.SigningConfigs
def dc = rootProject.ext.DefaultConfig
def r = rootProject.ext.Release
def d = rootProject.ext.Debug
def dep = rootProject.ext.Dependencies
之后就只要在用到的地方把原来的参数替换掉就好了
好比
//签名配置
signingConfigs {
//签名Name
config {
//签名别名
keyAlias 'gjn'
//签名别名密码
keyPassword '11223344'
//签名文件位置
storeFile file('D:/project/MyDemo/gjnKey.jks')
//签名密码
storePassword '11223344'
}
}
就变成了
//签名配置
signingConfigs {
//签名Name
config {
//签名别名
keyAlias sc.keyAlias
//签名别名密码
keyPassword sc.keyPassword
//签名文件位置
storeFile file(sc.storeFile)
//签名密码
storePassword sc.storePassword
}
}
使用是很简单的,这边要提及下第三方库导入相关,这边可以用上面学的groovy循环直接一次性全部加进去。可以省略很多代码。
直接改成
dep.each{ k,v->
implementation v
}
就等于加入了第三方引用
修改后的build.gradle如下
apply plugin: 'com.android.application'
apply plugin: 'com.jakewharton.butterknife'
def sc = rootProject.ext.SigningConfigs
def dc = rootProject.ext.DefaultConfig
def r = rootProject.ext.Release
def d = rootProject.ext.Debug
def dep = rootProject.ext.Dependencies
android {
//签名配置
signingConfigs {
//签名Name
config {
//签名别名
keyAlias sc.keyAlias
//签名别名密码
keyPassword sc.keyPassword
//签名文件位置
storeFile file(sc.storeFile)
//签名密码
storePassword sc.storePassword
}
}
//开发环境版本号
compileSdkVersion 26
//默认配置
defaultConfig {
//Id
applicationId "com.gjn.mydemo"
//最小支持版本号
minSdkVersion 19
//运行版本号
targetSdkVersion 25
//appCode
versionCode dc.versionCode
//app版本号
versionName dc.versionName
//测试相关
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
//Build类型 默认有release和debug两个版本
buildTypes {
release {
//是否开始混淆
minifyEnabled false
//混淆文件路径
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
//打包时候调用的签名
signingConfig signingConfigs.config
//在BuildConfig生成一个String类型的Host=release_Host
//即 public static final String Host = "release_Host";
buildConfigField "String", "Host", "\"${r.Host_bcf}\""
//编译之后会在res文件中的string.xml中加入一个string类型的app_name1=myMode
//即 myMode
resValue "string", "app_name1", "${r.appname_res}"
//修改build之后的app名称
//这边编译出来的名字是 release_1.0.apk
//这个写法是Android Studio 3.0之后的方法
android.applicationVariants.all { variant ->
variant.outputs.all {
outputFileName = "${variant.name}_${variant.versionName}.apk"
}
}
}
debug {
//为Id添加后缀 这边生成新的Id为com.gjn.mydemo.debug
applicationIdSuffix ".debug"
//这边下面和上面是一样
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
buildConfigField("String", "Host", "\"${d.Host_bcf}\"")
resValue("string", "app_name1", "${d.appname_res}")
//占位符 替换AndroidManifest.xml 中的${test_key}字符
//AndroidManifest.xml中的源代码为
//
//替换之后
//
manifestPlaceholders = ["test_key": "${d.test_key_mp}"]
}
}
//多版本
productFlavors{
//dev版本
dev{
manifestPlaceholders = ["test_key": "${r.test_key_mp}"]
}
//free版本
free{
//这边在提下,由于free也会有release和debug两个版本
//release的Id为com.gjn.mydemo.free
//debug的Id为com.gjn.mydemo.free.debug
applicationIdSuffix ".free"
manifestPlaceholders = ["test_key": "free_key"]
}
}
//遍历了全部版本
productFlavors.all{
//设置统一Code Android Studio 3.0之后需要设置这个属性 不然构建多版本的时候会报错
flavorDimensions("versionCode")
}
}
//导入第三方之类的jar aar 等 就不说了
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.1'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.7.0'
dep.each{ k,v->
implementation v
}
}
这样就把一些build.gradle中的配置分离出来了。到时候需要修改的时候,大部分只需要修改config文件就好了。其实优化下来,也就导入第三方库这块算是优化了(:з」∠)
Gradle打包
关于说打包之前,先说下Gradle的3个操作
复制Copy
删除Delete
压缩Zip
- Copy
下面做一个任务,将/src/main/xml下的*.xml文件复制到/build/xml文件夹下
task CopyXml(type: Copy){
includeEmptyDirs = false
destinationDir = file('build')
from( 'src/main/xml') {
include '**.xml'
into ('xml')
}
}
- Delete
删除任务就是吧刚才的文件夹删除
task DeleteXml(type: Delete){
delete 'build/xml', 'src/main/xml'
followSymlinks = true
}
效果就不截图了。就是删除掉了两个文件夹
- Zip
压缩任务。将app目录下的app.iml文件压缩到build目录下的adc.zip中的zip文件夹下。
task ZipTest(type: Zip){
destinationDir = file('build')
archiveName = 'abc.zip'
from('.'){
include('app.iml')
into('zip')
}
}
知道了上面3个操作。就可以开始进行Gradle打包操作了!
以下项目example为例子原例子代码
.
├── example
│ ├── build.gradle
│ ├── example.iml
│ ├── proguard-rules.pro
│ └── src
├── libs
│ ├── armeabi
│ ├── armeabi-v7a
│ ├── com.umeng.fb.5.3.0.jar
│ ├── mips
│ └── x86
├── releasenote.txt
└── res
├── anim
├── drawable
├── drawable-xhdpi
├── layout
├── values
└── values-zh
首先我们要知道,打包一个jar需要哪些步骤
- 编译工程(源代码)导出jar文件
- 复制"example"工程到"outputs/example"目录
- 复制jar文件到"outputs/libs"目录
- 复制资源文件到"outputs/res"目录
- 把 "outputs" 目录压缩成 zip 文件
之后就可以写入代码了
task dabao(type:Zip, dependsOn:build) {
destinationDir = file('outputs')
duplicatesStrategy = 'exclude'
archiveName = 'com.umeng.fb.' + android.defaultConfig.versionName + '.zip'
from('/'){
include 'releasenote.txt'
}
into('example') {
from '../example' exclude '**/build/**'
}
from('src/main/res'){
into 'res'
}
from('libs'){
into 'libs'
}
from(zipTree('build/outputs/aar/sdk-release.aar')){
include 'classes.jar'
rename 'classes.jar','com.umeng.fb.' + android.defaultConfig.versionName + '.jar'
into 'libs'
}
}
资料
Gradle 完整指南(Android)
看不懂的build.gradle代码
学点Groovy来理解build.gradle代码
如果像写代码一样写Gradle脚本
Gradle使用技巧总结