1. 程式人生 > >Gradle系列《二》: 在Android中的應用

Gradle系列《二》: 在Android中的應用

Gradle的更多用法

這裡主要介紹app/build.gradle這個檔案,因為這裡面的配置是與我們應用開發最為息息相關的。首先,先看看我們都可以在這個檔案中配置哪些內容(功能)。另外,這裡略去了部分上文提到的一些配置:

android {
    defaultConfig {
        //預設配置項
    }

    buildTypes {
      // 編譯配置,release或debug版本的內容
    }

    compileOptions {
      // Java 的版本配置
    }

    sourceSets {
        //原始碼設定(專案目錄結構的設定)
} packagingOptions { //打包時的相關配置 } lintOptions { //編譯的 lint 開關,程式在buid的時候,會執行lint檢查,有任何的錯誤或者警告提示,都會終止構建,我們可以將其關掉。 //abortOnError false } productFlavors { //產品釋出的一些東西,比如渠道、包名等 flavor1 { } flavor2 { } } signingConfigs { //簽名的配置
release { } } }

接下來將對部分功能特性(主要是與Android開發相關的特性)及使用進行詳細介紹

  • buildTypes–編譯配置
    這裡主要是對release與debug版本做些不同的配置,如是否啟用混淆、修改對應版本的包名、對應版本使用的簽名等(更多配置可以檢視:Build Types(構建型別))。
 buildTypes {
        release {
           //為釋出版本啟用混淆
            minifyEnabled true  
            //混淆檔案
            proguardFiles getDefaultProguardFile('proguard-android.txt'
), 'proguard-rules.pro' } debug { //將debug版本的包名設定為.debug以便能夠同時在一臺裝置上安裝debug和release版本的apk。 applicationIdSuffix ".debug" } }
  • compileOptions–配置JDK版本
compileOptions {  
    //配置使用JDK1.88),比如需要使用Lambda特性時,那麼就可以在這裡進行JDK版本的配置
    sourceCompatibility JavaVersion.VERSION_1_8  
    targetCompatibility JavaVersion.VERSION_1_8  
}  
  • sourceSets
    配置專案的目錄結構,其中較為常見的一個應用場景是,將Eclipse 中的專案遷移至AS,由於兩者目錄結構相差較大,所以需要手動指定,部分程式碼如:
    ( 更多介紹可以檢視:工程結構
sourceSets {  
    main {  
        manifest.srcFile 'AndroidManifest.xml'  
        java.srcDirs = ['src']  
        resources.srcDirs = ['src']  
        aidl.srcDirs = ['src']  
        renderscript.srcDirs = ['src']  
        res.srcDirs = ['res']  
        assets.srcDirs = ['assets']  
        jniLibs.srcDirs = ['libs']  
    }  

}  
  • packagingOptions –打包時的相關配置
    當專案中依賴的第三方庫越來越多時,有可能會出現兩個依賴庫中存在同一個(名稱)檔案。如果這樣,Gradle在打包時就會提示錯誤(警告)。那麼就可以根據提示,然後使用以下方法將重複的檔案剔除。
    packagingOptions {
        //這個是在同時使用butterknife、dagger2做的一個處理。同理,遇到類似的問題,只要根據gradle的提示,做類似處理即可。
        exclude 'META-INF/services/javax.annotation.processing.Processor'
    }
  • productFlavors

這個配置是經常會使用到的,通常在適配多個渠道的時候,需要為特定的渠道做部分特殊的處理,比如設定不同的包名、應用名等。場景:當我們使用友盟統計時,通常需要設定一個渠道ID,那麼我們就可以利用productFlavors來生成對應渠道資訊的包,如:

android {  
    productFlavors {
        wandoujia {
            //豌豆莢渠道包配置
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "wandoujia"]
            //manifestPlaceholders的使用在後續章節(AndroidManifest裡的佔位符)中介紹
        }
        xiaomi {
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "xiaomi"]
            applicationId "com.wiky.gradle.xiaomi" //配置包名

        }
        _360 {
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "_360"]
        }
        //...
    }  
}

當然也有更簡潔的方式:

android {  
    productFlavors {
        wandoujia {}
        xiaomi {}
        _360 {}
       //...
    }  

    productFlavors.all { 
        //批量修改,類似一個循序遍歷
        flavor -> flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name] 
    }
}

配置完之後,在命令列視窗中(Terminal)中輸入gradlew assembleRelease(window)即可開始打包,在Mac系統中對應指令應該是./gradlew assembleRelease。當然,如果想要debug版本的包,將指令中assembleRelease改為assembleDebug即可。最後生成的包還是在app/build/outputs/apk中,預設命名格式如app-wandoujia-release-unsigned.apk。

  • signingConfigs–應用簽名配置

為release版本配置簽名,如:

android {
    signingConfigs {
        release {
            //簽名證書檔案
            storeFile file("release.keystore")
            //別名
            keyAlias "release"
            //key的密碼
            keyPassword "123456"
            //證書的密碼
            storePassword "123456"
        }
        debug {

        }
    }

    //需要注意的是:配置好籤名資訊後,需要在buildTypes配置使用
    buildTypes {
        release {
            signingConfig signingConfigs.release
        }
        debug {

        }
    }
  }

當然,應用簽名可以借用AS(build – > generate signed apk)提供的圖形化介面來完成,如:

這裡寫圖片描述

具體設定流程就不再這裡介紹了。

批量修改生成的apk檔名

場景:我們需要一次性打多個包並且想讓生成的apk檔名有區分。比如格式為:應用名版本打包時間_渠道.apk。那麼我們可以採用如下方式:

//獲取並格式化時間資訊,注意,應該是與android{}同一層級
def buildTime() {
    return new Date().format("yyyy_MM_dd", TimeZone.getTimeZone("UTC"))
}

android {
    buildTypes {
        release {
         //只針對release版本進行配置
            applicationVariants.all {
                variant ->
                    variant.outputs.each {
                        output ->
                            def outputFile = output.outputFile
                            if (outputFile != null && outputFile.name.endsWith('.apk') && 'release'.equals(variant.buildType.name)) {
                                // 輸出apk格式命名如:Gradle_v1.0_2016_07_01_wandoujia.apk
                                def fileName = "Gradl_v${variant.versionName}_${buildTime()}_${variant.flavorName}.apk"
                                output.outputFile = new File(outputFile.parent, fileName)
                            }
                    }
            }
        }
    }
}

AndroidManifest裡的佔位符

AndroidManifest.xml就不在這裡介紹了。我們知道,專案中的很多配置都需要在這裡定義。而當在需要生成多個版本並要為每個版本配置相應的屬性值時,以我們最基本的做法(每生成一個版本前修改對應的屬性值)來看,這將是一件麻煩的事情。現在Gradle為我們提供了一個解決方案,就是利用manifestPlaceholders,進行動態賦值。它的使用有點類似HashMap。現在還是以使用友盟統計時的配置舉例:在友盟統計分析中,我們需要在AndroidManifest裡配置一個name為UMENG_CHANNEL的meta-data,這樣這個meta-data的值就表示這個apk是哪個渠道,如配置小米應用商店:

<meta-data android:value="xiaomi" android:name="UMENG_CHANNEL"/>

顯然,這個value值,不同版本的包都需要不同,所以以下為了能夠使用manifestPlaceholders進行動態替換,我們需要換一種寫法:

<meta-data android:value="${UMENG_CHANNEL_VALUE}" android:name="UMENG_CHANNEL"/>

如上${UMENG_CHANNEL_VALUE}就是一個佔位符,然後我們在gradle的defaultConfig;裡這樣定義指令碼:

android {
    defaultConfig {
        //可以在預設配置中設定,以下的語法格式應該比較清晰,就不再介紹了。
        manifestPlaceholders = [UMENG_CHANNEL_VALUE: 'xiaomi']
    }
}

我們回顧一下上文中介紹productFlavors時,對每個渠道包進行配置時所舉的例子正是利用manifestPlaceholders配置UMENG_CHANNEL_VALUE的值,如:

android {  
    productFlavors {
        wandoujia {
            //豌豆莢渠道包配置
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "wandoujia"]
              //另外寫法也有manifestPlaceholders.put("UMENG_CHANNEL_VALUE",'xiaomi'),稍有區別。
        }
        //...
    }  
}

通過以上例子,我們可以發現,AndroidManifest中的一些屬性值也是可以動態改變的,這樣在對特定包進行特定處理也將變得十分方便,更多的用法依次類推即可。

自定義你的BuildConfig

BuildConfig.java是Android Gradle自動生成的一個java類檔案,無法手動編譯,但是可以通過Gradle控制,也就是說他是動態可配置的。比如在build.gradle中配置buildConfigField “boolean”, “LOG_DEBUG”, “false”後,我們點選“Sync now”後,即可在程式碼中使用BuildConfig.java新加的LOG_DEBUG屬性,如:

public final class BuildConfig {
  //...
  // Fields from build type: debug
  public static final boolean LOG_DEBUG = true;
}

buildConfigField 一共有3個引數,第一個是資料型別,即新增成員變數的型別(與Java的型別是對等);第二個引數是成員變數名,如:LOG_DEBUG;第三個引數是常量值。

以下我們介紹一種常見的用法,場景:我們需要在debug版本包中輸出log,而不希望在release版本中輸出log,那麼就可以通過以下方法進行配置(當然,我們程式碼中的log開關是使用BuildConfig中相關屬性進行設定的):

buildTypes {
     debug {
        // 顯示Log
        buildConfigField "boolean", "LOG_DEBUG", "true"
        //...
     }

     release {
        // 不顯示Log
        buildConfigField "boolean", "LOG_DEBUG", "false"
        //...
     }
}

另外,還用一種常見的情況是:當我們的伺服器有debug和release環境時,我們可能也需要在App對應的版本中配置對應的資訊。如在debug版本中配置服務端debug環境對應的url。這樣我們在開發的過程中將減少很多麻煩的工作。具體做法就不再細說了。

PS:buildConfigField也是可以在對特定渠道包處理時進行特定的配置。

參考資料: