[AS3.0.1]Gradle代碼整合優(yōu)化

1.build.gradle講解

首先我將一個(gè)demo項(xiàng)目中的一份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'
        }
    }
    //開發(fā)環(huán)境版本號
    compileSdkVersion 26
    //默認(rèn)配置
    defaultConfig {
        //Id
        applicationId "com.gjn.mydemo"
        //最小支持版本號
        minSdkVersion 19
        //運(yùn)行版本號
        targetSdkVersion 25
        //appCode
        versionCode 1
        //app版本號
        versionName "1.0"
        //測試相關(guān)
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    //Build類型 默認(rèn)有release和debug兩個(gè)版本
    buildTypes {
        release {
            //是否開始混淆
            minifyEnabled false
            //混淆文件路徑
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            //打包時(shí)候調(diào)用的簽名
            signingConfig signingConfigs.config
            //在BuildConfig生成一個(gè)String類型的Host=release_Host
            //即 public static final String Host = "release_Host";
            buildConfigField "String", "Host", "\"release_Host\""
            //編譯之后會在res文件中的string.xml中加入一個(gè)string類型的app_name1=myMode
            //即 <string name="app_name1">myMode</string>
            resValue "string", "app_name1", "myMode"
            //修改build之后的app名稱
            //這邊編譯出來的名字是 release_1.0.apk
            //這個(gè)寫法是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中的源代碼為
            //<meta-data android:name="TEST_KEY" android:value="${test_key}"/>
            //替換之后
            //<meta-data android:name="TEST_KEY" android:value="debug_key"/>
            manifestPlaceholders = ["test_key": "debug_key"]
        }
    }
    //多版本
    productFlavors{
        //dev版本
        dev{
            manifestPlaceholders = ["test_key": "release_key"]
        }
        //free版本
        free{
            //這邊在提下,由于free也會有release和debug兩個(gè)版本
            //release的Id為com.gjn.mydemo.free
            //debug的Id為com.gjn.mydemo.free.debug
            applicationIdSuffix ".free"
            manifestPlaceholders = ["test_key": "free_key"]
        }
    }
    //遍歷了全部版本
    productFlavors.all{
        //設(shè)置統(tǒng)一Code Android Studio 3.0之后需要設(shè)置這個(gè)屬性 不然構(gòu)建多版本的時(shí)候會報(bào)錯(cuò)
        flavorDimensions("versionCode")
    }
}
//導(dǎo)入第三方之類的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'
}

我將大部分內(nèi)容都設(shè)置了備注,可以看到很多常用的屬性設(shè)置。還有許多其他的,后續(xù)在補(bǔ)充


2.Groovy講解

這邊我稍微對Groovy的語法和邏輯說一點(diǎn)!
首先說下
關(guān)于注釋之類和java是一樣的

  • 字符串

在java中就只有一種"android"

而Groovy中有
單行'android', "android"
多行 '''android''', """android""
還有/.../,${...}

  • 集合(List,Map)

List

創(chuàng)建和初始化

def list = [1,'hello',false]

這邊不需要List中的每個(gè)類型都相同,當(dāng)然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 ->    //遍歷整個(gè)list
        println l       //每次輸出一項(xiàng)
    }

結(jié)果

hello
false
android
5
false
gjn

Map

創(chuàng)建和初始化

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
    }

結(jié)果

hello
false
1:hello
android:233
b:false
2:33
  • 數(shù)組

關(guān)于數(shù)組
groovy 其實(shí)沒有嚴(yán)格區(qū)分?jǐn)?shù)組和集合,數(shù)組的定義和使用方法跟集合一樣,只是你需要強(qiáng)制聲明為數(shù)組,否則默認(rèn)為集合。

創(chuàng)建和初始化

String[] arrString = ['hello',"android","""groovy
=============="""]
def arrNum = [1,2,3] as int[]

直接String[]和Java一樣是創(chuàng)建數(shù)組
as int[]是把a(bǔ)rrNum設(shè)置為數(shù)組,不然就會變成集合

使用

    arrString.each {str->
        println str
    }
    arrNum.each {num->
        println num
    }

結(jié)果

hello
android
groovy
==============
1
2
3
  • 遍歷
    groovy中的遍歷有2個(gè)each{...}all{...}
    遍歷在上面的數(shù)組和集合都使用了,大體上都知道使用了。
    拿第一個(gè)說下each就是Java中的foreach
    list.each { l ->    //遍歷整個(gè)list
        println l       //每次輸出一項(xiàng)
    }

其實(shí)就等于Java中的

    List<String> list = new ArrayList<>();
    for(String l : list){
        System.out.println(l);
    }

all和each的使用是一樣的,區(qū)別我查了下,有提到是each使用的是迭代,不能實(shí)時(shí)修改值,all使用的是拾取對象,可以修改值。好比ArrayList和CopyOnWriteArrayList的區(qū)別吧!
我也不太確定,只是在 Android Gradle 3.0.0-alpha2 plugin, Cannot set the value of read-only property 'outputFile'
中有看到。

  • 方法簡化使用

groovy的一個(gè)特性
groovy 定義方法時(shí)可以不聲明返回類型和參數(shù)類型,也可以不需要 return 語句,最后一行代碼默認(rèn)就是返回值。使用的時(shí)候也可以不需要添加括號。
使用1

def add(a,b){
    a+b
}

def str = add 1,2
println str    //結(jié)果為3

結(jié)果1

3

這邊我們就能發(fā)現(xiàn)很多在build.gradle中的參數(shù)的真實(shí)代碼
例如
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'

結(jié)果2

1:hello
2:true
add:groovy
add:groovy test

這次使用我們就發(fā)現(xiàn)了一個(gè)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
}

結(jié)果

6
12

使用2

def myprintln(Closure c){
    println c.call()
}

myprintln {
    123
}
myprintln {
    "Msss"
}
myprintln {
    123+"Msss"
}

結(jié)果2

123
Msss
123Msss

Android Studio的build.gradle代碼整合優(yōu)化

繼續(xù)來說關(guān)于build.gradle代碼優(yōu)化。這邊我們拿最開始的build.gradle代碼進(jìn)行優(yōu)化。
說是優(yōu)化,其實(shí)就是吧一些東西寫在另一個(gè)gradle文件下,然后直接調(diào)用就好了。而且把部分參數(shù)寫在另一個(gè)gradle中,修改這些代碼的時(shí)候,就根本不需要Sync build.gradle代碼,也算加快了編譯速度吧!

首先我們在項(xiàng)目的project目錄下新建一個(gè)config.gradle文件
注:要讓config.gradle代碼能夠在app的build.gradle中使用,在主項(xiàng)目的build.gradle中加入 apply from:'config.gradle' 表示導(dǎo)入config文件代碼
具體位置如下

apply from:'config.gradle'
buildscript {
    repositories {
        ....
    }
    dependencies {
        ....
    }
}

allprojects {
    repositories {
        ....
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

創(chuàng)建好config.gradle文件之后寫入一個(gè)ext{}
默認(rèn)如下

ext{
    
}

然后我們看下,哪些可以寫在config中
這邊我選了簽名相關(guān)、APP的版本、正式版和測試版之間相同的數(shù)據(jù)設(shè)置加載第三方庫dependencies相關(guān)這幾項(xiàng)
所以我在config中加入

ext{
    SigningConfigs = [
        
    ]
    DefaultConfig = [

    ]
    Release = [

    ]
    Debug = [

    ]
    Dependencies = [

    ]
}

之后我們對比原來的build.gradle進(jìn)行配置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',
    ]
}

現(xiàn)在看下如何在build.gradle中使用
首先先創(chuàng)建好對應(yīng)的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

之后就只要在用到的地方把原來的參數(shù)替換掉就好了
好比

    //簽名配置
    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
        }
    }

使用是很簡單的,這邊要提及下第三方庫導(dǎo)入相關(guān),這邊可以用上面學(xué)的groovy循環(huán)直接一次性全部加進(jìn)去。可以省略很多代碼。
直接改成

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
        }
    }
    //開發(fā)環(huán)境版本號
    compileSdkVersion 26
    //默認(rèn)配置
    defaultConfig {
        //Id
        applicationId "com.gjn.mydemo"
        //最小支持版本號
        minSdkVersion 19
        //運(yùn)行版本號
        targetSdkVersion 25
        //appCode
        versionCode dc.versionCode
        //app版本號
        versionName dc.versionName
        //測試相關(guān)
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    //Build類型 默認(rèn)有release和debug兩個(gè)版本
    buildTypes {
        release {
            //是否開始混淆
            minifyEnabled false
            //混淆文件路徑
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            //打包時(shí)候調(diào)用的簽名
            signingConfig signingConfigs.config
            //在BuildConfig生成一個(gè)String類型的Host=release_Host
            //即 public static final String Host = "release_Host";
            buildConfigField "String", "Host", "\"${r.Host_bcf}\""
            //編譯之后會在res文件中的string.xml中加入一個(gè)string類型的app_name1=myMode
            //即 <string name="app_name1">myMode</string>
            resValue "string", "app_name1", "${r.appname_res}"
            //修改build之后的app名稱
            //這邊編譯出來的名字是 release_1.0.apk
            //這個(gè)寫法是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中的源代碼為
            //<meta-data android:name="TEST_KEY" android:value="${test_key}"/>
            //替換之后
            //<meta-data android:name="TEST_KEY" android:value="debug_key"/>
            manifestPlaceholders = ["test_key": "${d.test_key_mp}"]
        }
    }
    //多版本
    productFlavors{
        //dev版本
        dev{
            manifestPlaceholders = ["test_key": "${r.test_key_mp}"]
        }
        //free版本
        free{
            //這邊在提下,由于free也會有release和debug兩個(gè)版本
            //release的Id為com.gjn.mydemo.free
            //debug的Id為com.gjn.mydemo.free.debug
            applicationIdSuffix ".free"
            manifestPlaceholders = ["test_key": "free_key"]
        }
    }
    //遍歷了全部版本
    productFlavors.all{
        //設(shè)置統(tǒng)一Code Android Studio 3.0之后需要設(shè)置這個(gè)屬性 不然構(gòu)建多版本的時(shí)候會報(bào)錯(cuò)
        flavorDimensions("versionCode")
    }
}
//導(dǎo)入第三方之類的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中的配置分離出來了。到時(shí)候需要修改的時(shí)候,大部分只需要修改config文件就好了。其實(shí)優(yōu)化下來,也就導(dǎo)入第三方庫這塊算是優(yōu)化了(:з」∠)


Gradle打包

關(guān)于說打包之前,先說下Gradle的3個(gè)操作
復(fù)制Copy
刪除Delete
壓縮Zip

  • Copy

下面做一個(gè)任務(wù),將/src/main/xml下的*.xml文件復(fù)制到/build/xml文件夾下

task CopyXml(type: Copy){
    includeEmptyDirs = false
    destinationDir = file('build')
    from( 'src/main/xml') {
        include '**.xml'
        into ('xml')
    }
}
效果
  • Delete

刪除任務(wù)就是吧剛才的文件夾刪除

task DeleteXml(type: Delete){
    delete 'build/xml', 'src/main/xml'
    followSymlinks = true
}

效果就不截圖了。就是刪除掉了兩個(gè)文件夾

  • Zip

壓縮任務(wù)。將app目錄下的app.iml文件壓縮到build目錄下的adc.zip中的zip文件夾下。

task ZipTest(type: Zip){
    destinationDir = file('build')
    archiveName =  'abc.zip'

    from('.'){
        include('app.iml')
        into('zip')
    }
}
壓縮結(jié)果

壓縮包

知道了上面3個(gè)操作。就可以開始進(jìn)行Gradle打包操作了!

以下項(xiàng)目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

首先我們要知道,打包一個(gè)jar需要哪些步驟

  1. 編譯工程(源代碼)導(dǎo)出jar文件
  2. 復(fù)制"example"工程到"outputs/example"目錄
  3. 復(fù)制jar文件到"outputs/libs"目錄
  4. 復(fù)制資源文件到"outputs/res"目錄
  5. 把 "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代碼
學(xué)點(diǎn)Groovy來理解build.gradle代碼
如果像寫代碼一樣寫Gradle腳本
Gradle使用技巧總結(jié)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容