雜篇:一代版本一代神[-Gradle-]

零、前言

本文主要包括:
|---Gradle簡介,下載,安裝
|---Groovy語言的簡單認識
|---Gradle構建java項目
|---Gradle構建腳本的書寫
|---Gradle構建java多模塊項目
|---Gradle在Android中的應用
|---最後寫一個建立文件夾的小插件
複製代碼

1、Gradle簡介

1.我與Gradle的邂逅

百分之八十的Gradle使用者應該都是從AndroidStudio接觸Gradlejava

想當年用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目錄加入環境變量,下面的幾點就不用看了,android


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文件夾目錄加到環境變量便可,ios

下載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
複製代碼

2、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)git

Idea插件報錯.png

修改Gradle配置,出現下面的界面,Gradle插件就運行ok了github

成功.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
 * 郵箱:1981462002@qq.com
 * 說明:將字符大寫方法
 */
public class UpCase {
    public static String toUpCase(String str) {
        System.out.println(str);
        return str.toUpperCase();
    }
}
複製代碼

3.導出jar包

打jar包很是簡單,點兩下就好了,(其中字符集的問題後面解決,不影響jar包使用)api

打jar包.png


4.使用jar包

打了jar包就用用吧,雖然實際中已經不多用jar包依賴了,這裏演示一下
新建一個App的module,將jar包導入,並依賴,而後就能正常使用了緩存

引入jar包.png


4、關於Gradle構建腳本

gradle根目錄\src\core-api\org\gradle\api\Project.java是一個interface
它定義了一個項目類,而build.gradle中即便用了項目對象的屬性和方法
這兩個類是Gradle的核心,其中定義了不少方法,能夠在.gradle文件中隨意調用bash

實體類.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-->B  B-->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
 * 郵箱:1981462002@qq.com
 * 說明:測試使用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'
}
複製代碼

5、項目的模塊化構建及測試

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,你應該更有感受


6、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.srcDirs      assets文件目錄
aidl.srcDirs        aidl文件目錄
jniLibs.srcDirs     .so文件目錄
jni.srcDirs         jni文件目錄
manifest.srcFile    AndroidManifest.xml的位置
java.srcDirs        java代碼的文件目錄
複製代碼

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-]
捷文連接:www.jianshu.com/p/075f84620…

2.更多關於我
筆名 QQ 微信
張風捷特烈 1981462002 zdl1994328

個人github:github.com/toly1994328
個人簡書:www.jianshu.com/u/e4e52c116…
個人掘金:juejin.im/user/5b42c0…
我的網站:www.toly1994.com

3.聲明

1----本文由張風捷特烈原創,轉載請註明
2----歡迎廣大編程愛好者共同交流
3----我的能力有限,若有不正之處歡迎你們批評指證,一定虛心改正
4----看到這裏,我在此感謝你的喜歡與支持

icon_wx_200.png
相關文章
相關標籤/搜索