目錄
1)Gradle簡(jiǎn)介
2)Android中的gradle
- 2.1)gradle文件
- 2.2)gradle wrapper
- 2.3)配置輸出文件格式
- 2.3.1)基本用法
- 2.3.2)使用簽名文件進(jìn)行簽名
- 2.3.3)多渠道包配置
- 2.4)配置Gradle 編譯速度
3)Groovy基本語(yǔ)法
4)Gradle插件開(kāi)發(fā)
1)Gradle簡(jiǎn)介
- mac在~/.bash_profile中添加如下代碼
//此處是gradle路徑宗兼,我本機(jī)在AS時(shí)已下載過(guò)4.1版本市咆,此處我使用已下載好的地址
export GRADLE_HOME=~/.gradle/wrapper/dists/gradle-4.1-all/bzyivzo6n839fup2jbap0tjew/gradle-4.1
export PATH=${PATH}:${GRADLE_HOME}/bin
- 保存配置
source ~/.bash_profile - gradle -v
------------------------------------------------------------
Gradle 4.1
------------------------------------------------------------
Build time: 2017-08-07 14:38:48 UTC
Revision: 941559e020f6c357ebb08d5c67acdb858a3defc2
Groovy: 2.4.11
Ant: Apache Ant(TM) version 1.9.6 compiled on June 29 2015
JVM: 1.8.0_91 (Oracle Corporation 25.91-b14)
OS: Mac OS X 10.12.4 x86_64
2)Android中的gradle
2.1)gradle文件
文件 | 說(shuō)明 |
---|---|
setting.gradle | 文件定義了哪些module 應(yīng)該被加入到編譯過(guò)程 |
Project-build.gradle | 此處的配置會(huì)被應(yīng)用到所有項(xiàng)目中 |
Module-build.gradle | 每個(gè)module的配置啰扛,會(huì)覆蓋Project-build.gradle的相同部分 |
// ~/Project-build.gradle
buildscript {
repositories {
google()
//一般用共有的jCenter倉(cāng)庫(kù)
jcenter()
}
dependencies {
//gradle-wrapper.properties中配置的是的Gradle的版本.
//build.gradle中的依賴指定的是Gradle插件的版本.
//對(duì)應(yīng)關(guān)系請(qǐng)自查詢
classpath 'com.android.tools.build:gradle:3.0.0'
}
}
//此處配置會(huì)應(yīng)用至所有module中
allprojects {
repositories {
google()
jcenter()
//有一些項(xiàng)目械姻,可能在公司的私有的倉(cāng)庫(kù)中
maven {
url "http://maven.aliyun.com/nexus/content/repositories/releases"
//若有密碼 則加上credentials
credentials {
username "xxx"
password "xxx"
}
}
//也可以使用相對(duì)路徑配置本地倉(cāng)庫(kù)
flatDir {
dirs "xxx"
}
}
}
// ~/Module-build.gradle
//android應(yīng)用程序的gradle插件
apply plugin: 'com.android.application'
//apply plugin: 'com.android.library' //library項(xiàng)目
//apply plugin: 'java-library'
//關(guān)于android的配置項(xiàng)
android {
compileSdkVersion 26
//默認(rèn)配置
defaultConfig {
applicationId "com.tgf.studygradle"
minSdkVersion 21
targetSdkVersion 26
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
//編譯類型配置 默認(rèn)的有debug运准、release 的類型
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
//依賴配置掏颊,定義了項(xiàng)目需要依賴的其他庫(kù)
dependencies {
//可以使用文件依賴
implementation fileTree(dir: 'libs', include: ['*.jar'])
//最新版的gradle已經(jīng)使用api替代了compile某抓。 api和implementation的依賴層次是有區(qū)別的揖膜,請(qǐng)查資料
//一定要指名依賴版本,盡量不要使用通配符+看锉,可以避免檢查是否有新版本姿锭,也能做到工程化開(kāi)發(fā)都統(tǒng)一依賴庫(kù)版本
//對(duì)于特定的buildTypes不同依賴的塔鳍,可以使用debugImplementation或debugApi
implementation 'com.android.support:appcompat-v7: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'
}
2.2)gradle wrapper
gradle wrapper的誕生是為了兼容不斷發(fā)展的Gradle版本。
//通過(guò)此命令可以手動(dòng)創(chuàng)建wrapper腳本,AS創(chuàng)建工程時(shí)會(huì)自動(dòng)創(chuàng)建
gradle wrapper
gradle wrapper --gradle-version 4.1 //也可以加入版本號(hào)
下載目錄
cd ~/.gradle/wrapper/dists
- gradle-wrapper.properties中配置的是的Gradle的版本.
...
distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
- 通過(guò)wrapper可以使用命令行編譯:
命令 | 說(shuō)明 |
---|---|
./gradlew ... | mac系統(tǒng) |
gradle.bat | win系統(tǒng) |
-
使用 ./gradlew tasks可列出所有所有task
常用task | 說(shuō)明 |
---|---|
./gradlew assemble | 對(duì)所有的 buildType 生成 apk 包,會(huì)編譯debug和release |
./gradlew assembleDebug | 只編譯debug版本 |
./gradlew assembleRelease | 只編譯release版本 |
./gradlew clean | 刪除所有編譯輸出文件 |
./gradlew check | lint檢測(cè), Wrote HTML report to file:///Users/tugaofeng/tgf/study/Learn-Android/studyGradle/app/build/reports/lint-results.html |
./gradlew build | 相當(dāng)于執(zhí)行assemble -> check |
2.3)配置輸出文件格式
2.3.1)基本用法
- gradle build后會(huì)根據(jù)配置文件生成BuildConfig.java呻此。因?yàn)間radle基于grovvy語(yǔ)言轮纫,其是一種JVM語(yǔ)言,可以生成Java字節(jié)碼文件焚鲜。
//我們?cè)诖a中可以使用BuildConfig 判斷當(dāng)前環(huán)境是否debug
if (BuildConfig.DEBUG){
...
}
- 可以在buildTypes中對(duì)不同的編譯環(huán)境定義不同的鍵值對(duì)掌唾,這些值在不同的編譯包apk中對(duì)應(yīng)的值不一樣,來(lái)實(shí)現(xiàn)一些需求忿磅,比如API服務(wù)器環(huán)境配置
// ~/build.gradle
buildTypes {
debug {
buildConfigField "String", "API_URL", "\"http://www.baidu.com/api\""
buildConfigField "boolean", "LOG_SHOW", "true"
// 相當(dāng)于在res/strings.xml 下增加一個(gè)名為 app_name糯彬,debugAPP 的資源
// 注意,這里是添加葱她,在 string.xml 不能有這個(gè)字段撩扒,會(huì)重名!6中搓谆!
resValue "string", "app_name", "debugAPP"
}
release {
buildConfigField "String", "API_URL", "\"http://www.google.com/api\""
buildConfigField "boolean", "LOG_SHOW", "false"
resValue "string", "app_name", "releaseAPP"
...
}
}
//debug環(huán)境編譯后的 BuildConfig.java
public final class BuildConfig {
public static final boolean DEBUG = Boolean.parseBoolean("true");
public static final String APPLICATION_ID = "com.tgf.studygradle";
public static final String BUILD_TYPE = "debug";
public static final String FLAVOR = "";
public static final int VERSION_CODE = 1;
public static final String VERSION_NAME = "1.0";
// Fields from build type: debug
public static final String API_URL = "http://www.baidu.com/api";
public static final boolean LOG_SHOW = true;
}
Log.d("MainActivity","API環(huán)境: "+ BuildConfig.API_URL);
Log.d("MainActivity","是否打印日志: "+ BuildConfig.LOG_SHOW);
Log.d("MainActivity","app_name="+getString(R.string.app_name));
2.3.2)使用簽名文件進(jìn)行簽名
// ~/build.gradle
apply plugin: 'com.android.application'
...
//獲取local.properties的內(nèi)容
Properties properties = new Properties()
properties.load(project.rootProject.file('local.properties').newDataInputStream())
android {
...
//第一種:使用gradle直接簽名打包
// signingConfigs {
// release {
// storeFile file("/Users/tugaofeng/tgf/study/Learn-Android/studyGradle/studyGradle_keystore")
// storePassword "123456"
// keyAlias "studyGradle_keystore"
// keyPassword "123456"
// }
// }
//第二種:為了保護(hù)簽名文件,把它放在local.properties中并在版本庫(kù)中排除
//不把這些信息寫(xiě)入到版本庫(kù)中(注意豪墅,此種方式簽名文件中不能有中文)
signingConfigs {
release {
storeFile file(properties.getProperty("keystroe_storeFile"))
storePassword properties.getProperty("keystroe_storePassword")
keyAlias properties.getProperty("keystroe_keyAlias")
keyPassword properties.getProperty("keystroe_keyPassword")
}
}
buildTypes {
...
release {
...
signingConfig signingConfigs.release
}
}
}
// ~/local.properties
#對(duì)應(yīng)自己實(shí)際的證書(shū)路徑和名字
keystroe_storeFile=/Users/tugaofeng/tgf/study/Learn-Android/studyGradle/studyGradle_keystore
keystroe_storePassword=123456
keystroe_keyAlias=studyGradle_keystore
keystroe_keyPassword=123456
2.3.3)多渠道包配置
apply plugin: 'com.android.application'
//打包時(shí)間
def releaseTime() {
return new Date().format("yyyy-MM-dd", TimeZone.getTimeZone("UTC"))
}
//獲取local.properties的內(nèi)容
Properties properties = new Properties()
properties.load(project.rootProject.file('local.properties').newDataInputStream())
android {
compileSdkVersion 26
// 默認(rèn)配置
defaultConfig {
applicationId "com.tgf.studygradle"
minSdkVersion 21
targetSdkVersion 26
versionCode 1
versionName "1.0.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
//為了保護(hù)簽名文件泉手,把它放在local.properties中并在版本庫(kù)中排除
//不把這些信息寫(xiě)入到版本庫(kù)中(注意,此種方式簽名文件中不能有中文)
signingConfigs {
release {
storeFile file(properties.getProperty("keystroe_storeFile"))
storePassword properties.getProperty("keystroe_storePassword")
keyAlias properties.getProperty("keystroe_keyAlias")
keyPassword properties.getProperty("keystroe_keyPassword")
}
}
//維度偶器,gradle3.0后此處需要有個(gè)默認(rèn)斩萌,名字隨便取。此屬性可用于不同維度的組合
flavorDimensions "default"
// 多渠道配置
productFlavors {
baidu{
// 每個(gè)環(huán)境包名不同
applicationId "com.tgf.studygradle.multichannel.baidu"
// 動(dòng)態(tài)添加 string.xml 字段屏轰;
// 注意术裸,這里是添加,在 string.xml 不能有這個(gè)字段亭枷,會(huì)重名O铡!叨粘!
resValue "string", "app_name", "studyGradle百度版本"
// 動(dòng)態(tài)修改 常量 字段
buildConfigField "String", "ENVIRONMENT", '"我是百度首頁(yè)"'
// 修改 AndroidManifest.xml 里渠道變量
//manifestPlaceholders = [UMENG_CHANNEL_VALUE: "baidu"]
}
qq{
applicationId "com.tgf.studygradle.multichannel.qq"
resValue "string", "app_name", "studyGradle騰訊版本"
buildConfigField "String", "ENVIRONMENT", '"我是騰訊首頁(yè)"'
//manifestPlaceholders = [UMENG_CHANNEL_VALUE: "qq"]
}
}
buildTypes {
debug {
// debug模式猾编,API服務(wù)地址
buildConfigField "String", "API_URL", "\"http://www.baidu.com/api\""
// debug模式,顯示log
buildConfigField("boolean", "LOG_SHOW", "true")
//為已經(jīng)存在的applicationId添加后綴
applicationIdSuffix ".debug"
// 為版本名添加后綴
versionNameSuffix "-debug"
// 不開(kāi)啟混淆
minifyEnabled false
// 不開(kāi)啟ZipAlign優(yōu)化
zipAlignEnabled false
// 不移除無(wú)用的resource文件
shrinkResources false
}
release {
// release模式升敲,API服務(wù)地址
buildConfigField "String", "API_URL", "\"http://www.google.com/api\""
// release模式答倡,不顯示log
buildConfigField "boolean", "LOG_SHOW", "false"
// 為版本名添加后綴
versionNameSuffix "-release"
// 開(kāi)啟ZipAlign優(yōu)化
zipAlignEnabled true
// 移除無(wú)用的resource文件
shrinkResources true
// 使用config簽名
signingConfig signingConfigs.release
// 開(kāi)啟混淆
minifyEnabled true
// 混淆文件位置
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
// 批量打包
android.applicationVariants.all { variant ->
variant.outputs.all {
outputFileName = "${variant.productFlavors[0].name}_v${defaultConfig.versionName}_${variant.buildType.name}_${releaseTime()}.apk"
}
}
}
}
//忽略lint檢測(cè)的error [lint配置說(shuō)明](http://blog.csdn.net/berber78/article/details/60766091)
lintOptions {
// true--錯(cuò)誤發(fā)生后停止gradle構(gòu)建
abortOnError false
}
}
dependencies {
//可以使用文件依賴
implementation fileTree(dir: 'libs', include: ['*.jar'])
//最新版的gradle已經(jīng)使用api替代了compile。 api和implementation的依賴層次是有區(qū)別的驴党,請(qǐng)查資料
//一定要指名依賴版本,盡量不要使用通配符+瘪撇,可以避免檢查是否有新版本,也能做到工程化開(kāi)發(fā)都統(tǒng)一依賴庫(kù)版本
//對(duì)于特定的buildTypes不同依賴的,可以使用debugImplementation或debugApi
implementation 'com.android.support:appcompat-v7: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'
}
productFlavors和buildTypes一樣倔既,可以擁有自己的sourceset文件夾恕曲,且productFlavors和buildTypes可以結(jié)合擁有一個(gè)優(yōu)先級(jí)高于productFlavors和buildTypes單獨(dú)設(shè)置的sourceset,比如想要qq的release版本擁有一個(gè)單獨(dú)的圖標(biāo)渤涌,可以建立qqRelease的sourceset佩谣。注意:順序必須是flavor+buildType形式。
2.4)配置Gradle 編譯速度
- ./gradle.properties
#加大可用編譯內(nèi)存
org.gradle.jvmargs=-Xmx1536m
# 開(kāi)啟并行編譯
org.gradle.parallel=true
#開(kāi)啟守護(hù)進(jìn)程实蓬,該進(jìn)程在第一次啟動(dòng)后一直存在茸俭,后續(xù)的編譯可以重用該進(jìn)程
org.gradle.daemon=true
-
執(zhí)行所有task的時(shí)候我們都可以通過(guò)添加--profile生成一份執(zhí)行報(bào)告
3)Groovy基本語(yǔ)法
- 新建一個(gè)文件夾安皱,并在文件夾內(nèi)創(chuàng)建build.gradle
//變量:使用def關(guān)鍵字 單引號(hào)只是一串字符串
def name1 = 'tgf'
//變量:插值占位符 需要使用雙引號(hào)
def greeting = "hello,$name1"
//方法:如果不指定返回值 則返回最后一行代碼
def add(def num) {
num + num
}
//類:類中聲明的屬性會(huì)自動(dòng)生成get和set方法
//myClass.name = 'xxx'相當(dāng)于 myClass.setName('xxx')
//myClass.name 相當(dāng)于 myClass.getName()
class MyClass{
String name
}
//列表
List list = [1,2,3]
//Map
Map map = [id:1,name:'玄策']
//閉包寫(xiě)法,如果只有一個(gè)參數(shù) 可以忽略此參數(shù)调鬓,使用it代替
//閉包寫(xiě)法在Android build.gradle中大量使用
/*def multi = { num ->
num * num
}*/
def multi = {
it * it
}
//任務(wù)-打印
task myTask << {
println '========打印變量&方法==========='
//測(cè)試打印
println "hello world"
//測(cè)試打印變量
println greeting
//測(cè)試打印方法
println add(2)
println '========打印類屬性值==========='
//創(chuàng)建類的實(shí)例對(duì)象
def myClass = new MyClass()
myClass.name = '大家好'
//測(cè)試打印類屬性值
println myClass.name
println '=========打印列表數(shù)據(jù)=========='
//測(cè)試打印列表
list.each(){element ->
println element
}
println '=========打印Map數(shù)據(jù)=========='
println map['id']
println map.get('name')
println '=========打印閉包寫(xiě)法=========='
println multi(4)
}
//任務(wù)-從文件夾拷貝至另一個(gè)
task copyFile(type: Copy){
from 'src'
into 'dst'
}
//task的依賴關(guān)系 dependsOn
//如果是Muliti-Project的模式,依賴關(guān)系要帶著所屬的Project酌伊,如taskA.dependsOn ':other-project:taskC' 其中taskC位于和taskA不同的Project中袖迎,相對(duì)于AndroidStudio來(lái)說(shuō),就是位于不同的Module下的build.gradle中腺晾,而other-project為Module名字。
task taskA <<{
println "這是taskA"
}
task taskB <<{
println "這是taskB"
}
taskA.dependsOn taskB
4)Gradle插件開(kāi)發(fā)簡(jiǎn)介
-
新建Android-library的Module,刪除非必要的文件辜贵,保留如下格式
com.tgf.mygradleplugin.properties代表了我們這個(gè)插件的id就是com.tgf.mygradleplugin
#指向我們新建的類
implementation-class=com.tgf.mygradleplugin.MyGradlePlugin
- build.gradle
apply plugin: 'java'//導(dǎo)入java插件用于悯蝉,編譯打包我們的插件, 也可以使用apply plugin: 'groovy'
apply plugin: 'maven'//maven插件托慨,用于上傳插件到倉(cāng)庫(kù)
//uploadArchives 類型是upload鼻由,這個(gè)task不是'maven'創(chuàng)建的
// 使用命令./gradlew uploadArchives 可以在指定路徑生成jar
uploadArchives{
//本地倉(cāng)庫(kù)的一種
repositories{
flatDir{
name "localRepository"
dir "localRepository/libs"
}
}
//提交到遠(yuǎn)程服務(wù)器:
// repository(url: "http://xxx") {
// authentication(userName: "xxx", password: "xxx")
// }
//本地的Maven地址設(shè)置為D:/repos
// repository(url: uri('/Users/tugaofeng/xxx'))
}
group = "com.tgf.mygradleplugin"http://project屬性
version = "1.0"http://project屬性
dependencies {
//導(dǎo)入Gradle的api,要寫(xiě)插件厚棵,肯定要使用Gradle的api
compile gradleApi()
}
- 舉例:我們使用這個(gè)插件來(lái)在指定路徑里生成一個(gè)文件蕉世,并寫(xiě)入作者信息
- AuthorBean.java
public class AuthorBean {
//姓名
private String name;
//年齡
private int age;
public AuthorBean(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "作者:"+name+" ,年齡:"+age;
}
@Input
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Input
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
- WriteAuthorTask.java
public class WriteAuthorTask extends DefaultTask{
private AuthorBean authorBean; //作者實(shí)體
private String fileName;
private File targetDict;
@Nested
public AuthorBean getAuthorBean() {
return authorBean;
}
@Input
public String getFileName() {
return fileName;
}
@InputDirectory
public File getTargetDict() {
return targetDict;
}
@TaskAction
public void writeObject(){
File targetFile = new File(targetDict,fileName);
try {
FileOutputStream fos = new FileOutputStream(targetFile);
fos.write(authorBean.toString().getBytes());
fos.flush();
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public void setAuthorBean(AuthorBean authorBean) {
this.authorBean = authorBean;
}
public void setTargetDict(File targetDict) {
this.targetDict = targetDict;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
}
- MyGradlePlugin.java
public class MyGradlePlugin implements Plugin<Project> {
@Override
public void apply(Project project) {
WriteAuthorTask task = project.getTasks().create("writeAuthor", WriteAuthorTask.class);
task.setTargetDict(new File("" + "/Users/tugaofeng/Desktop"));
task.setFileName("author.txt");
task.setAuthorBean(new AuthorBean("涂高峰",30));
task.writeObject();
}
}
- Project-build.gradle
buildscript {
repositories {
google()
jcenter()
flatDir name:'localRepository',dir:'mygradleplugin/localRepository/libs'
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.0'
//命名是我們的groupId:moduleName:version
classpath 'com.tgf.mygradleplugin:mygradleplugin:1.0'
}
}
- app的Module-build.gradle
//新增apply插件id
apply plugin: 'com.tgf.mygradleplugin'
-
運(yùn)行命令或點(diǎn)擊AS的命令,會(huì)生成對(duì)應(yīng)路徑的jar婆硬,并執(zhí)行插件代碼狠轻,寫(xiě)入txt文件
./gradlew uploadArchives
簡(jiǎn)單介紹了如何自定義gradle插件,詳細(xì)的學(xué)習(xí)在插件化的時(shí)候進(jìn)行學(xué)習(xí)
參考資料
Gradle 完整指南(Android)
《Gradle for Android》
Groovy 基本語(yǔ)法