雜篇:一代版本一代神[-Gradle-]
零、前言

本文主要包括: |---Gradle簡介,下載,安裝 |---Groovy語言的簡單認識 |---Gradle構建java專案 |---Gradle構建指令碼的書寫 |---Gradle構建java多模組專案 |---Gradle在Android中的應用 |---最後寫一個建立資料夾的小外掛
一、Gradle簡介
1.我與Gradle的邂逅
百分之八十的Gradle使用者應該都是從 AndroidStudio
接觸 Gradle
的
想當年用Eclipse喜歡收藏jar包,但版本迭代後,還要重新找 雖然挺麻煩,但是有jar包用感覺也是無比幸福的,畢竟別人的心血能省自己不少事 畢竟簡單的學習小專案不需要那麼多第三方依賴,更不用說什麼依賴管理 當我剛用AndroidStudio時,最不解的就是Gradle,開始一段時間基我倆井水不犯河水 我依然用著我的jar包,在src下寫程式碼,似乎不用Gradle也沒什麼影響 第一次接觸Gradle是看一片介紹oKHttp的文章,照著寫一句,然後神奇的就OK了 這讓我很驚訝,當看到原始碼時發現已經下載到本地了。心想:現在這麼智慧了? 當我發現斷網情況下依然可以使用本地的庫檔案,jar包就被我徹底拋棄了 一直以來Gradle對我來說就是新增依賴,感覺熟悉又陌生 就像一個人一直幫你幹活,你卻對它除了工作之外一無所知,這顯然不太好
2.構建工具
Ant: 長江後浪推前浪,前浪已經over了 |---編譯、測試、打包 Maven:使用xml標記構建指令碼 |---依賴管理、編譯、測試、打包、釋出 Gradle:使用Groovy語言構建指令碼 |---依賴管理、編譯、測試、打包、釋出、靈活的指令碼
3.Gradle是什麼,怎麼安裝?
一個基於 Groovy語言
的開源 專案自動化構建工具
如果你用過AndroidStudio,Gradle已經被你下好了,直接開啟下面的路徑
你可以將bin目錄加入環境變數,下面的幾點就不用看了,

3.1:確保jdk已安裝
C:\Users\Administrator>java -version java version "10.0.1" 2018-04-17 Java(TM) SE Runtime Environment 18.3 (build 10.0.1+10) Java HotSpot(TM) 64-Bit Server VM 18.3 (build 10.0.1+10, mixed mode)
3.2: 下載Gradle,地址:
將解壓後的bin資料夾目錄加到環境變數即可,

下載Gradle.png

新增環境變數.png
3.3:檢視是否安裝正確
C:\Users\Administrator>gradle -v Welcome to Gradle 5.2! Here are the highlights of this release: - Define sets of dependencies that work together with Java Platform plugin - New C++ plugins with dependency management built-in - New C++ project types for gradle init - Service injection into plugins and project extensions
二、Groovy語言
1.Groovy簡介
基於java虛擬機器的動態語言 面向物件/指令碼,完全相容java語法
2.建立一個gradle專案

建立一個gradle專案
3.修改Gradle配置的方法
注:目前2019-2-7日: gradle-5.2
在Idea裡Build失敗, gradle-4.10.1
沒問題
估計是Idea外掛的版本未更新,PS(Android目前也是用的 gradle-4.10.1
)

Idea外掛報錯.png
修改Gradle配置,出現下面的介面,Gradle外掛就執行ok了

成功.png
4.Java VS Groovy

Java VS Groovy
---->[java]------------------ public class Version { private int major; private int minor; public Version(int major, int minor) { this.major = major; this.minor = minor; } public int getMajor() { return major; } public void setMajor(int major) { this.major = major; } public int getMinor() { return minor; } public void setMinor(int minor) { this.minor = minor; } } Version version = new Version(2, 1); System.out.println(version.getMajor()); //2 ---->[Groovy]------------------ class Version { private int major private int minor Version(int major, int minor) { this.major = major this.minor = minor } } def version = new Version(2, 1) println version.major //2
5.Groovy的特色
類及方法預設public,欄位自動getter,setter,直接點號獲取 最後一個表示式的值作為返回值 == 等用於equals(),assert語句,弱型別, 分號可選,擴號可選,字串三種,閉包

groovy簡介.png
def age = 24//推到型別 assert age < 25 //斷言 println age//省略括號 def name = '張風捷特烈'//單引號字串 def say = "我是${name}"//雙引號插值字串 def code = //三引號原樣輸出 ''' 我是${name} def age = 24//推到型別 assert age < 25 //斷言 ''' println say println code //list def platform = ["java", "Android", "ios"]//定義集合 platform << 'Linux'//新增元素 println platform.class//class java.util.ArrayList println platform.size()//4 //map def release = [ 'v0.01': '2018-12-13', 'v0.02': '2018-12-14', 'v0.03': '2018-12-15'] release.'v0.04' = '2018-12-16'//新增 println release.getClass()//class java.util.LinkedHashMap println release.size()//4 //閉包 def update ={ v-> return v+1 } def updateFun(Closure closure,int version) { closure(version) } def newVersion = updateFun(update, 1) println newVersion//2
三.建立專案
1.新建專案
Idea會為我們自動生成專案結構

建立新的module.png
2.寫一個方法
/** * 作者:張風捷特烈 * 時間:2019/2/7/007:8:58 * 郵箱:[email protected] * 說明:將字元大寫方法 */ public class UpCase { public static String toUpCase(String str) { System.out.println(str); return str.toUpperCase(); } }
3.匯出jar包
打jar包非常簡單,點兩下就行了,(其中字符集的問題 後面解決
,不影響jar包使用)

打jar包.png
4.
使用jar包
打了jar包就用用吧,雖然實際中已經很少用jar包依賴了,這裡演示一下
新建一個App的module,將jar包匯入,並依賴,然後就能正常使用了

引入jar包.png
四、關於Gradle構建指令碼
在 gradle根目錄\src\core-api\org\gradle\api\Project.java
是一個 interface
它定義了一個專案類,而 build.gradle
中即使用了專案物件的屬性和方法
這兩個類是Gradle的核心,其中定義了很多方法,可以在.gradle檔案中隨意呼叫

實體類.png
|---比如列印一下當前專案目錄 ---->[org.gradle.api.Project#getProjectDir]------- /** * <p>The directory containing the project build file.</p> * * @return The project directory. Never returns null. */ File getProjectDir(); ---->[App/build.gradle]---------- println getProjectDir()//J:\Java\GradleTest\toly\App
1.解放雙手 task
1.1 :簡單的建立資料夾任務
public interface Task extends Comparable<Task>, ExtensionAware
Task是一個介面,可以助你完成一些無聊的工作,這裡以建立三個資料夾為例

建立任務.png
def mkDir = {//建立資料夾的方法 path -> def dir = new File(path) if (!dir.exists()) { dir.mkdirs() } } task mkDirTask() {//自定義一個任務 def paths = [ 'src/main/java/com/toly1994/app/adapter', 'src/main/java/com/toly1994/app/activity', 'src/main/java/com/toly1994/app/fragment', ] doFirst { paths.forEach(mkDir) } }
如果上面的看懂了,這裡用projectName替換一下專案名
這樣就可以在任意專案裡建立這三個檔案夾了,
task mkDirTask() {//自定義一個任務 def projectName = project.name.toLowerCase()//獲取工程目錄 def paths = [ "src/main/java/com/toly1994/${projectName}/adapter", "src/main/java/com/toly1994/${projectName}/activity", "src/main/java/com/toly1994/${projectName}/fragment", ] doFirst { paths.forEach(mkDir) } }
1.2:Task之間的依賴 dependsOn
也就是在執行之前,先執行被依賴的Task

task依賴.png
task mkDirTaskWithUtils{ dependsOn 'mkDirTask'//依賴mkDirTask任務 def projectName = project.name.toLowerCase()//獲取去工程目錄 def paths = [ "src/main/java/com/toly1994/${projectName}/utils" ] doFirst { paths.forEach(mkDir) } }
2.構建的生命週期

構建的生命週期及回撥.png
//在構建專案前呼叫的鉤子函式 gradle.beforeProject { project -> println "-------beforeProject-------" } //配置解析前回調 gradle.taskGraph.whenReady { graph -> println "-------whenReady-------" } gradle.buildFinished { result -> println "-------buildFinished-------" }
3.依賴管理
3.1.簡介
關於implementation和compile的區別,這裡簡單說一下。可詳見:

依賴管理.png
工件座標:(group,name,version) 工件倉庫:mavenCentral/jcenter 依賴的傳遞:若A-->BB-->C則A-->C implementation(編譯期)-----曾經為compile |--1.加快編譯速度(本模組編譯)。 |--2.對外隱藏不必要的介面。 runtime(執行期)、testCompile(測試編譯期)、testRuntime(測試執行期)
//使用mavenCentral倉庫 repositories { mavenCentral() } //依賴管理 dependencies { //測試編譯時依賴 testCompile group: 'junit', name: 'junit', version: '4.12'
3.2:mavenCentral與依賴使用
maven倉庫相比大家都知道吧,簡單說一下怎麼檢視一個依賴(okhttp為例): 倉庫網址
可以看到okhttp的工件座標(group,name,version),它確定了唯一的存在

尋找okhttp依賴.png
//依賴管理 dependencies { //測試編譯時依賴 testCompile group: 'junit', name: 'junit', version: '4.12' // https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp implementation group: 'com.squareup.okhttp3', name: 'okhttp', version: '3.13.1' }

新增依賴.png
//簡寫形式 implementation'組:名:版本號' -----是不是很親切 implementation 'com.squareup.okhttp3:okhttp:3.13.1'
3.3:okhttp的使用
/** * 作者:張風捷特烈 * 時間:2019/2/8/008:10:27 * 郵箱:[email protected] * 說明:測試使用okhttp */ public class Api { public static void main(String[] args) { doGet("http://www.toly1994.com:8089/api/android/note"); } public static void doGet(String url) { //1.獲取OkHttpClient物件 OkHttpClient okHttpClient = new OkHttpClient(); //2.獲取Request物件 Request request = new Request.Builder().get().url(url).build(); //3.將Request封裝為Call物件 Call call = okHttpClient.newCall(request); //4.執行Call call.enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { System.out.println(e); } @Override public void onResponse(Call call, Response response) throws IOException String str = response.body().string(); System.out.println(str); } }); } }

訪問網路成功.png

快取到本地的原始碼.png
3.4:使用其他的倉庫
前面找不到就找下一個
repositories { mavenCentral()//使用mavenCentral倉庫 google()//使用google倉庫 jcenter()//使用jcenter倉庫 maven {//maven私服 url 'https://jitpack.io' } }
4:版本衝突
4.1:版本衝突簡介
okhttp:3.13.1
依賴了 okio:1.17.2
,如果專案中再依賴 okio:2.2.2
就會版本衝突
預設情況下版本衝突時,Gradle會自動使用最高版本,所以我們並不怎麼煩神

版本衝突.png

版本衝突-.png
4.2:自己解決版本衝突
自動使用最高版本,大多數情況都適用,但你還是有自定義解決方案的機會的
首先,顯示版本衝突在哪裡

顯示版本衝突.png
configurations.all{ resolutionStrategy{ failOnVersionConflict()//版本衝突時報錯 } }
4.3:強制使用某版本

強制使用制定版本.png
configurations.all { resolutionStrategy { //failOnVersionConflict()//版本衝突時報錯 force 'com.squareup.okio:okio:1.17.2'//強制指定版本 } }
4.4:排除一個依賴中的依賴
implementation('com.squareup.okhttp3:okhttp:3.13.1'){ exclude group: 'com.squareup.okio',module:'okio' }
五、專案的模組化構建及測試
0.專案的模組化

建立三個module.png
1.settings.gradle
一個專案只有一個,用來管理子模組名稱
rootProject.name = 'toly-all' include 'model' include 'repository' include 'player'
2.新增模組間依賴關係
implementation project(":模組名")
-或compile
注意:專案間的傳遞型依賴要用compile,不然引用不到

四個模組間的依賴關係.png
---->[toly-all\repository\build.gradle]------------ dependencies { compile project(":model") testCompile group: 'junit', name: 'junit', version: '4.12' } ---->[toly-all\player\build.gradle]------------ dependencies { testCompile group: 'junit', name: 'junit', version: '4.12' compile project(":repository") } ---->[toly-all\build.gradle]------------ dependencies { testCompile group: 'junit', name: 'junit', version: '4.12' implementation project(":player") }
3.Gradle資訊的公共處理
每個 build.gradle
都有的東西,統一處理一下,以後改起來方便
在根專案下的 build.gradle
裡使用 allprojects
---->[toly-all\build.gradle]------------ allprojects { apply plugin:'java' sourceCompatibility = 1.8 repositories { mavenCentral() } dependencies { testCompile group: 'junit', name: 'junit', version: '4.12' } }
4.使用 gradle.properties
統一配置引數
---->[toly-all\gradle.properties]------------ group='com.toly1994' version='0.01'
5.測試

idea自動生成測試方法.png
public class PlayerTest { @Test public void tolySay() { Player player = new Player(); Person person = player.tolySay(); assert person.name.equals("toly"); assert person.age == 24; } }

build.png
6.釋出
使用maven-publish外掛,發表到中央倉庫挺麻煩的,還是自己搭個私服,或直接本地吧

maven.png
以上是Gradle在java中的使用,現在回頭看一下Android裡的Gradle,你應該更有感覺
六、Gradle在Android中
1.現在新建一個Android普通專案
---->[模組:build.gradle]----------------- apply plugin: 'com.android.application'//啟用外掛 com.android.application android {//安卓 compileSdkVersion 27//SDK編譯版本 defaultConfig {//預設配置 applicationId "com.toly1994.gradletest"//應用id minSdkVersion 21//相容的SDK最低版本 targetSdkVersion 27//SDK目標版本(本應用的SDK--向下相容) versionCode 1//版本號 versionName "1.0" //版本名稱 testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes {//build配置 release {//釋出設定 minifyEnabled false //是否混淆 //混淆檔案 proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies {//依賴 implementation fileTree(include: ['*.jar'], dir: 'libs') implementation 'com.android.support:appcompat-v7:27.1.1' implementation 'com.android.support.constraint:constraint-layout:1.1.3' testImplementation 'junit:junit:4.12' androidTestImplementation 'com.android.support.test:runner:1.0.2' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' } ---->[專案:build.gradle]----------------- buildscript {//構建指令碼 repositories { google() jcenter() } dependencies { classpath 'com.android.tools.build:gradle:3.2.1' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } } allprojects {//對所有模組適用 repositories {//倉庫 google()//google倉庫 jcenter()//jcenter倉庫 } } task clean(type: Delete) {//清除的task delete rootProject.buildDir }
2.現在新建一個JNI的Android專案
模組級的gradle檔案多了 externalNativeBuild
android { ... defaultConfig { ... externalNativeBuild { cmake { cppFlags "" } } } ... externalNativeBuild {//設定cmake的目錄 cmake { path "CMakeLists.txt" } } }
將 stringFromJNI
抽取出來放在一個類中作為靜態方法,然後生成so檔案

jni目錄結構.png

生成so檔案.png
3.回到前一個工程,使用so檔案
注意so檔案在其他工程下需要保證介面名的一致,比不剛才的C++中的函式:
Java_com_toly1994_jni_HelloJNI_stringFromJNI
該函式只能用在:com.toly1994.jni下的HelloJNI類中的stringFromJNI方法,錯一個字都不行

使用so.png

使用so檔案.png
android {//安卓 ... sourceSets {//------預設如下,可不用配置 main { jni.srcDirs = [] jniLibs.srcDirs = ['src/main/jniLibs']//預設路徑,可修改 } } }
4.資源分包
這裡以佈局為例,其他資原始檔夾也一樣

佈局分包.png
android { ... sourceSets { main { res.srcDirs = [ 'src/main/res/layouts/home', 'src/main/res/layouts/player', 'src/main/res/layouts/news', 'src/main/res' ] }} }
public interface AndroidSourceSet
介面定義很多檔案的位置
都可以根據自己的需要,自行修改
res.srcDirs資原始檔目錄 assets.srcDirsassets檔案目錄 aidl.srcDirsaidl檔案目錄 jniLibs.srcDirs.so檔案目錄 jni.srcDirsjni檔案目錄 manifest.srcFileAndroidManifest.xml的位置 java.srcDirsjava程式碼的檔案目錄
5.混淆與釋出
提一下: gradle.properties
裡的鍵值對可以在.gradle裡直接使用
你可以將密碼寫在裡面, .gitignore
配置一下,不上傳到github就行了

簽名.png
android { ... signingConfigs { release { storeFile file("tolyapp.jks") storePassword APK_SIGN_STORE_PASSWORD keyAlias "toly" keyPassword APK_SIGN_KEY_PASSWORD } } buildTypes { release { shrinkResources true//是否去除未利用的資源,預設false,表示不去除。 minifyEnabled true//是否混淆 signingConfig signingConfigs.release//簽名 proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } ---->[gradle.properties]-------------- APK_SIGN_KEY_PASSWORD=777777 APK_SIGN_STORE_PASSWORD=666666

釋出.png
6.公共資訊提取: ext
對於很多公共的東西,提取出來容易統一管理和修改,特別對於多模組專案而言

自定義引數.png
7.引用其他的.gradle檔案
.gradle 檔案一直被我認為是神聖的存在,不能亂改,更別提自己建立了
騎士gradle檔案是可以相互引用的,下面通過建立資料夾小外掛來說明

資料夾外掛.png
---->[mkdir.gradle]--------- import java.util.function.Consumer apply plugin: 'com.android.application' apply plugin: MkDirPlugin//宣告使用外掛 mkDir {//根據拓展引數來自定義資料夾 pkg = 'com.toly1994.gradletest_' names = ['adapter','activity','app/config', 'app/compat','utils','view','presenter','model'] } //----------------------------以下是外掛部分-------------------------------- class MkDirPlugin implements Plugin<Project> { //該介面定義了一個apply()方法,在該方法中,我們可以操作Project, //比如向其中加入Task,定義額外的Property等。 void apply(Project project) { //載入Extension project.extensions.create("mkDir", MkDirPluginPluginExtension) def mkDir = { //建立資料夾的方法 path -> def dir = new File(path) if (!dir.exists()) { dir.mkdirs() } } //使用Extension配置資訊 project.task('mkDirTask') << { String pkg = project.mkDir.pkg ArrayList<String> names = project.mkDir.names def dir='src/main/java/'+pkg.replaceAll("\\.",'''/''') ArrayList<String> paths = new ArrayList<>() names.forEach(new Consumer<String>() { @Override void accept(String s) { paths.add(dir+"/"+s) println dir+"/"+s } }) paths.forEach(mkDir) } } } class MkDirPluginPluginExtension {//拓展引數 String pkg = '' def names = [] } //----------------------------外掛結束-------------------------------- ---->[模組級build.gradle]-------------- apply from: 'mkdir.gradle' //引用mkdir.gradle ---一行搞定
外掛部分你不用Groovy,全部用java寫都可以,Groovy對java是相容的
外掛你也可以 新建一個專案來製作
,可以釋出一下,給更多人使用
所以燃燒你的小宇宙,用gradle盡情偷懶吧!相信你會發現另一片天地!
後記:捷文規範
1.本文成長記錄及勘誤表
專案原始碼 | 日期 | 附錄 |
---|---|---|
V0.1-- | 2018-2-12 | 無 |
釋出名: 一代版本一代神[-Gradle-]
捷文連結: https://www.jianshu.com/p/075f846207a9
2.更多關於我
筆名 | 微信 | |
---|---|---|
張風捷特烈 | 1981462002 | zdl1994328 |
我的github: https://github.com/toly1994328
我的簡書: https://www.jianshu.com/u/e4e52c116681
我的掘金: https://juejin.im/user/5b42c0656fb9a04fe727eb37
個人網站: http://www.toly1994.com
3.宣告
1----本文由張風捷特烈原創,轉載請註明
2----歡迎廣大程式設計愛好者共同交流
3----個人能力有限,如有不正之處歡迎大家批評指證,必定虛心改正
4----看到這裡,我在此感謝你的喜歡與支援

icon_wx_200.png