標籤:
轉自:http://blog.csdn.net/changemyself/article/details/39927381
一、前言
Gradle 是以 Groovy 語言為基礎,面向Java應用為主。基於DSL(領特定領域語言)文法的自動化構建工具。
上面這句話我覺得寫得很官方,大家只需知道Gradle可以用來android開發中進行多重專案依賴的自動化編譯指令碼,知道這點也就知道我們使用它的目的;
為什麼不使用Ant做自動化編譯指令碼,因為ant上手快,但是維護起來太不方便了,有了Gradle你可以跟項目組的同事說,用Ant的孩子們別苦逼的維護了,趕緊換成gradle吧。
本文面向gradle新手或者以前使用過gradle低版本的朋友,因為我感覺每次gradle升級那個指令碼也有些坑爹,有些api就廢棄掉了,不過總體感覺每次升級都讓這個工具更加嚴謹話,易用話了。
二、Demo描述
下面我就簡單寫一個demo,通過這個demo程式讓大家如何快速上手,比較實用的一個執行個體:
demo程式分為2個工程,你可以直接實用eclipse建立一個android工程,其實我也是這麼乾的,這樣一來大家仔細看
這裡順便強調一下demo工程的環境配置:(很重要,否則下面被我坑了別怪我提起沒跟你說)
jdk:C:\Program Files\Java\jdk1.8.0_20(注意:不要使用jre,gradle會提示你使用jdk的)
否則指令碼會提示以下錯誤:
* What went wrong:Execution failed for task ‘:appcompat_v7:compileReleaseJava‘.> Cannot find System Java Compiler. Ensure that you have installed a JDK (not just a JRE) and configured your JAVA_HOMEsystem variable to point to the according directory.
android-sdk:D:\dev\adt-bundle-windows-x86-20140702
android-api: 20, android4.4W(注意:做android開發你每次都是用最新的api編譯是一個好習慣)
gradle:2.1,(使用最新的版本,no zuo no die,被坑不斷,歡樂不斷)
gradle的:http://www.gradle.org/documentation ,大家可以看看文檔,當然你的E文好的話,會容易上手,不過沒關係,看了我寫的文章你gradle的文檔你可以不看了,因為很多東西你用不上,除非你項目中使用了特別複雜的功能
gradle2.1的api文檔:http://www.gradle.org/docs/current/javadoc/org/gradle/api/Project.html ,這個需要你偶爾翻翻,因為簡易功能會用上的
環境變數配置:
JAVA_HOME,GRADLE_HOME都要添加到環境變數裡
當然了path變數裡你也要加上 JAVA_HOME/bin,和GRADLE_HOME/bin,這樣下面你開一個CMD命令列,才可以方面使用gradle build命令
好了準備工作完成後,我們就開始正式講講這個demo工程了
TestDemo工程就寫了一個activity,顯示hello world!
Appcompatv7工程大家懂得一個library,很有代表性,我們實際項目中會用到多個library,你可以舉一反三了。
下面看看目錄檔案:
你想運行編譯指令碼,需要2個設定檔,local.properties和settings.gradle
settings.gradle裡的代碼內容:
include ‘:appcompat_v7‘, ‘:TestDemo‘
這裡面可以看到是project的描述,如果你有多個工程如論主工程還是引用的庫工程,都需要在這裡面聲明,否則gradle找不到
local.properties裡的代碼內容:
sdk.dir=D:\\dev\\adt-bundle-windows-x86-20140702\\sdk
這裡面可以看到是android sdk的目錄,自己填好,否則也會報錯。
好了下面講講每個工程裡面都需要配置一個build.gradle 檔案
appcompat_v7工程的build.gradle:
buildscript{repositories{mavenCentral();}dependencies{classpath ‘com.android.tools.build:gradle:0.13.+‘}tasks.withType(JavaCompile) { options.encoding = "UTF-8" }}apply plugin:‘android-library‘dependencies{compile fileTree(dir:‘libs‘,include:"*.jar")}android{compileSdkVersion 20buildToolsVersion "20"enforceUniquePackageName=falselintOptions{abortOnError false}sourceSets{main{manifest.srcFile ‘AndroidManifest.xml‘java.srcDirs = [‘src‘]resources.srcDirs = [‘src‘]aidl.srcDirs = [‘src‘]renderscript.srcDirs = [‘src‘]res.srcDirs = [‘res‘]assets.srcDirs = [‘assets‘]}}lintOptions{abortOnError false}}
對於這個檔案我需要強調幾點:
1、classpath ‘com.android.tools.build:gradle:0.13.+‘ ,很多人用了低版本出了問題寫什麼0.11+,我不管,你要使用gradle2.1版本,這裡就寫成1.13+包你沒錯。
2、apply plugin:‘android-library‘,說明這個一個庫工程,詳細自己找資料腦補
3、tasks.withType(JavaCompile) { options.encoding = "UTF-8" } ,task是個啥自己查去,這裡編譯encoding配成UTF-8,還有一點在低版本指令碼有的人寫成tasks.withType(Compile) ,這樣子報錯了,改成JavaCompile吧,我是一點一點排錯的
4、android{
compileSdkVersion 20
buildToolsVersion "20"
這裡面version寫20,為啥?上面你看看我的android-sdk api的版本就知道了,寫成別的也可以,你要保證你本地androidsdk都有。
TestDemo工程裡的幾個檔案:
build目錄:是gradle執行編譯時間候產生的,裡面好多內容,有興趣自己翻翻看
output目錄:我寫得指令碼,最後把build裡的apk自動copy到這個目錄,這個可以具體看指令碼
blue_key:apk簽名檔案
build.gradle:你懂得
TestDemo工程裡面的build.gradle
import java.util.regex.Pattern//import com.android.builder.DefaultManifestParserimport com.android.builder.core.DefaultManifestParserbuildscript{repositories{mavenCentral()}dependencies{classpath ‘com.android.tools.build:gradle:0.13.+‘}/***tasks.withType(Compile){options.encoding = "UTF-8"}**/tasks.withType(JavaCompile) { options.encoding = "UTF-8" }}apply plugin:‘android‘dependencies{compile fileTree(dir:"libs",include:‘*.jar‘)compile project(‘:appcompat_v7‘)}android{compileSdkVersion 20buildToolsVersion "20"enforceUniquePackageName=falsedefaultConfig{targetSdkVersion 17;}lintOptions{abortOnError false}dexOptions {preDexLibraries = false}packagingOptions {exclude ‘META-INF/DEPENDENCIES.txt‘exclude ‘META-INF/LICENSE.txt‘exclude ‘META-INF/NOTICE.txt‘exclude ‘META-INF/NOTICE‘exclude ‘META-INF/LICENSE‘exclude ‘META-INF/DEPENDENCIES‘exclude ‘META-INF/notice.txt‘exclude ‘META-INF/license.txt‘exclude ‘META-INF/dependencies.txt‘exclude ‘META-INF/LGPL2.1‘exclude ‘META-INF/ASL2.0‘}signingConfigs{myConfig{storeFile file("bluekey")storePassword "blue"keyAlias "blue"keyPassword "blue"}}buildTypes{release{runProguard true //開啟混淆開關proguardFile ‘proguard.txt.txt‘ //配置單個檔案這樣signingConfigs.myConfig}}sourceSets{main{manifest.srcFile ‘AndroidManifest.xml‘java.srcDirs = [‘src‘]resources.srcDirs = [‘src‘]aidl.srcDirs = [‘src‘]//rendersrcDirs = [‘src‘]res.srcDirs = [‘res‘]assets.srcDirs = [‘assets‘]}}task copyNativeLibs(type: Copy) { from(new File(project(‘:appcompat_v7‘).getProjectDir(), ‘libs‘)) { include ‘**/*.so‘ } into new File(buildDir, ‘native-libs‘) }tasks.withType(JavaCompile){compileTask -> compileTask.dependsOn copyNativeLibs}clean.dependsOn ‘cleanCopyNativeLibs‘tasks.withType( com.android.build.gradle.tasks.PackageApplication){pkgTask -> pkgTask.jniFolders = new HashSet<File>()pkgTask.jniFolders.add(new File(buildDir,‘native-libs‘))}}build.doLast {def today = new Date().format(‘yyMMdd‘);copy{//from(‘build/apk‘)from(‘build/outputs/apk‘)into(‘output‘)include(‘TestDemo-debug.apk‘)rename(‘TestDemo-debug.apk‘,‘blue-‘+today+‘-‘+readVersion()+‘-demo.apk‘)}}/***從Manifest.xml中讀取版本號碼**/def readVersion(){def manifestParser = new DefaultManifestParser()return manifestParser.getVersionName(android.sourceSets.main.manifest.srcFile);}
對於這個檔案我需要強調幾點(很重要):
1、//import com.android.builder.DefaultManifestParser
import com.android.builder.core.DefaultManifestParser
//注釋掉的代碼是低版本的寫法,目前使用最新api
2、/***
tasks.withType(Compile){
options.encoding = "UTF-8"
}
**/
tasks.withType(JavaCompile) { options.encoding = "UTF-8" }
//注釋掉的代碼是低版本的寫法,目前使用最新api
3、
dependencies{
compile fileTree(dir:"libs",include:‘*.jar‘)
compile project(‘:appcompat_v7‘)
}
編譯依賴,我們可以看到依賴的庫 appcompat_v7要寫在這裡,注意":"(冒號一定要寫)
4、
signingConfigs{
myConfig{
storeFile file("bluekey")
storePassword "blue"
keyAlias "blue"
keyPassword "blue"
}
}
buildTypes{
release{
signingConfigs.myConfig
}
}
編譯時間候簽名檔案配置,當然你也可以編譯出debug和沒有簽名的apk,自行查資料去
5、
task copyNativeLibs(type: Copy) {
from(new File(project(‘:appcompat_v7‘).getProjectDir(), ‘libs‘)) { include ‘**/*.so‘ }
into new File(buildDir, ‘native-libs‘)
}
tasks.withType(JavaCompile){
compileTask -> compileTask.dependsOn copyNativeLibs
}
關於依賴的so檔案和jar檔案,在編譯之前copy依賴到主工程的native-libs目錄
6、build.doLast {
def today = new Date().format(‘yyMMdd‘);
copy{
//from(‘build/apk‘)
from(‘build/outputs/apk‘)
into(‘output‘)
include(‘TestDemo-debug.apk‘)
rename(‘TestDemo-debug.apk‘,‘blue-‘+today+‘-‘+readVersion()+‘-demo.apk‘)
}
}
/**
*從Manifest.xml中讀取版本號碼
**/
def readVersion(){
def manifestParser = new DefaultManifestParser()
return manifestParser.getVersionName(android.sourceSets.main.manifest.srcFile);
}
build.doLast,就是最後執行的意思,關於gradle task大家需要簡單查資料掌握即可。
這裡面需要注意的:
def today = new Date().format(‘yyMMdd‘);
def manifestParser = new DefaultManifestParser()
都需要def聲明變數,低版本不用寫的,但是目前不寫就要報錯了。
這個代碼的功能:就是從Manifest檔案裡讀出versioncode然後結合當前日期重新命名output裡的apk檔案。
方便吧,很實用的一點。
7、apply plugin:‘android‘
這說明這個指令碼需要編譯的是一個 android工程,跟上面的library是不是有所不同呢? gradle還支援java project的編譯,大家自行查資料。
三、編譯執行:下面我們開啟cmd命令視窗進行編譯操作
在TestDemo目錄執行gradle build,因為這裡是local.properties和settings.gradle 所在的根目錄。
第一次執行時候,gradle根據依賴去下載所需要的jar包,會在你每個工程裡建立一個.gradle目錄
dependencies{
classpath ‘com.android.tools.build:gradle:0.13.+‘
}
下載成功後
ok,那我們開始執行編譯操作了,gradle build
編譯正常的話會提示 BUILD SUCCESSFUL,然後自己去output目錄找apk去。
這裡提醒大家一個jar衝突會引起編譯中斷的問題:
因為很多朋友的project的libs目錄有多個android-support-v4.jar導致的。
最後囉嗦
今天先寫到這,我們實際運用中有很多需求,例如:自動根據多渠道打包,根據不同的資源和不同的pkg進行apk打包,gradle都能幫你搞定,這塊demo後續有時間我貼上來。有什麼問題,大家可以跟我交流(QQ群:
221057495)。
四、參考資料:
After upgrading to Gradle 2.0: Could not find property ‘Compile‘ on root project
Unable to resolve class in build.gradle using Android Studio 0.60/Gradle 0.11
How to configure build.gradle files of an existing project with actionbarsherlock lib?
Multiple settings gradle files for multiple projects building
Android Tools Project Site
demo:
gradle2.1demo教程(多評論哈)
Gradle Android最新自動化編譯指令碼教程