Android Gradle defaultConfig詳解及實用技巧

HappyCorn發表於2019-02-23

實際專案中,都會應用Android Gradle Plugin,根據實際中的專案模組的職責,可以具體應用如下四種外掛型別。

1,apply plugin: 'com.android.application'
實際對應的原型是:com.android.build.gradle.AppExtension,表示此專案模組型別為Android App Module,對應構建生成的檔案為.apk型別檔案。

2,apply plugin: 'com.android.library'
實際對應的原型是:com.android.build.gradle.LibraryExtension,表示此專案模組型別為Android Library Module,對應構建生成的檔案為.arr型別的檔案。

3,apply plugin: 'com.android.test'
實際對應的原型是:com.android.build.gradle.TestExtension,表示此專案模組型別為Android test Module,可以在單個模組內通過targetProjectPath指定專案,用於對應專案的單元測試。

4,apply plugin: 'com.android.feature'
實際對應的原型是:com.android.build.gradle.FeatureExtension,表示此專案模組型別為Android feature Module,主要用於單個模組內實現特性,以支援Android Instant Apps

其中,一般專案中最常見的是applicationlibrary外掛型別。

專案模組內應用了具體的Android Gradle Plugin型別後,可以開始進行對應的配置,如最常見的如下配置項:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 28
    defaultConfig {
        applicationId "com.happycorn"
        minSdkVersion 15
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        ...
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
        ...
    }
    
    ...
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    ...
}
複製程式碼

此時可以按住CTRL,通過滑鼠懸浮,可以看到對應的配置原型資訊。

Android Gradle defaultConfig詳解及實用技巧

不同的Android Gradle Plugin外掛型別,對應不同的實現原型,以及對應可能不同的對外配置項。

同樣的,跟蹤defaultConfig{}原型資訊,可以進入到如下原型說明。

/**
     * Specifies defaults for variant properties that the Android plugin applies to all build
     * variants.
     *
     * <p>You can override any <code>defaultConfig</code> property when <a
     * href="https://developer.android.com/studio/build/build-variants.html#product-flavors">
     * configuring product flavors</a>.
     *
     * <p>For more information about the properties you can configure in this block, see {@link
     * ProductFlavor}.
     */
    public void defaultConfig(Action<DefaultConfig> action) {
        checkWritability();
        action.execute(defaultConfig);
    }
複製程式碼

可見,defaultConfig{}所對應的具體職責是:
為變體屬性,指定預設值,Android plugin 可以將指定的變體屬性的預設值,應用到所有的變體中。

執行action.execute(defaultConfig);後,將為DefaultConfig物件指定具體的配置。

實際專案開發中,我們往往關注此處有哪些配置項,以及每個配置項對應的含義及作用。

首先可以在Android Gradle DSL文件上對應查詢DefaultConfig使用說明。 具體參見: google.github.io/android-gra…

文件中列出了DefaultConfig物件的對外可配置的屬性、方法,以及對應說明,在具體配置時,可能有些需要注意的事項,文件中也做了詳盡敘述。

Android Gradle defaultConfig詳解及實用技巧

Android Gradle defaultConfig詳解及實用技巧

但無論是屬性還是方法,一般在build.gradle中配置defaultConfig{}時,一般都是採用形如 key value形式,當然,實際上也可以採用對應的方法原型形式配置,效果是等價的,不過有個前提是,此方法原型是確實存在的,否則,Gradle會報錯。 如:

defaultConfig {
    ...
    minSdkVersion 15
    ...
}

等價於
defaultConfig {
    ...
    minSdkVersion(15)
    ...
}
複製程式碼

defaultConfig{}中配置的屬性,在構建時,會預設生成對應的變體目錄下的BuildConfig.java檔案,此檔案中將之前配置的屬性轉變成了對應的JAVA常量形式。

build.gradle中配置如下:

android {
    compileSdkVersion 28

    defaultConfig {
        applicationId "com.happycorn"
        minSdkVersion 15
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
    }


    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }

        debug {

        }
    }


    flavorDimensions "default"

    productFlavors {
        demo {
            applicationIdSuffix "demo"
        }

        full {
            applicationIdSuffix "full"
        }
    }

}
複製程式碼

執行./gradlew assembleFull命令,對應生成的BuildConfig檔案為:

Android Gradle defaultConfig詳解及實用技巧

如其中的buildTypedebug對應的BuildConfig檔案內容為:

/**
 * Automatically generated file. DO NOT MODIFY
 */
package com.happycorn;

public final class BuildConfig {
  public static final boolean DEBUG = Boolean.parseBoolean("true");
  public static final String APPLICATION_ID = "com.happycorn.full";
  public static final String BUILD_TYPE = "debug";
  public static final String FLAVOR = "full";
  public static final int VERSION_CODE = 1;
  public static final String VERSION_NAME = "1.0";
}
複製程式碼

BuildConfig檔案為JAVA原始碼級別,構建時也會對應被編譯打包到包中,可以直接在對應的模組中使用。

利用此特性,我們經常可以在專案中對變體環境進行邏輯判斷,對應的進行邏輯處理。 如:判斷是否是DEBUG,對應的輸出Log等。

if (BuildConfig.DEBUG) {
    Log.d(TAG, "come here...");
}
複製程式碼

另外,DefaultConfig物件中專門對外提供了buildConfigField(type, name, value)方法,用於向構建時生成的BuildConfig.java類中增加新的屬性。

如:defaultConfig{}中通過buildConfigField(type, name, value)新增如下。

defaultConfig {
    ...
    // 是否打對對使用者的內測包
    innerTest = project.hasProperty('innertest') ? innertest : 'false'
    buildConfigField "boolean", "INNER_TEST", innerTest
    
    // 新增模組對應的模組名
    buildConfigField "String", "MODULE_NAME", "\"${project.name}\""
}
複製程式碼

生成的BuildConfig.java中將有對應屬性產生。

public final class BuildConfig {
  ...
  // Fields from default config.
  public static final boolean INNER_TEST = false;
  public static final String MODULE_NAME = "app";
}
複製程式碼

利用此特性,可以很有技巧性的去處理專案中的一些特定的問題。參照上例程式碼中的兩個追加的屬性。
如:
Gradle構建時,通過命令引數-P傳入對應引數鍵值,可以將其在defaultConfig{}中新增,以自動在BuildConfig.java中生成對應屬性,然後程式中對應進行一些邏輯的特別處理。

if (BuildConfig.INNER_TEST) {
    // 使用者內測的一些邏輯處理
    ...
}
複製程式碼

又如:
呼叫專案日誌系統時,可以傳入對應的模組名,以實現對各個模組的日誌過濾展示等。 此時就可以通過project.name取到模組名,追加到BuildConfig.java中。然後呼叫日誌庫時可以取用。

CLog.e(BuildConfig.MODULE_NAME, TAG, e)
複製程式碼

更進一步,此處對各個模組通過defaultConfig{}配置向BuildConfig.java中追加屬性可以寫成:

allprojects {
    ...
    afterEvaluate { project ->
        def android = project.extensions.findByName("android")
        if(android != null){
            def defaultConfig =  android["defaultConfig"]
            defaultConfig.buildConfigField("String", "MODULE_NAME", "\"${project.name}\"")
        }
    }
}
複製程式碼

使得整體用法顯得非常靈活。

除了buildConfigField(type, name, value)方法外,還有一個實用方法resValue(String type, String name, String value)
resValue(String type, String name, String value)等價於向模組res/values中新增一個資源。

如:在buildTypedebug中新增資源:

buildTypes {
    release {
        minifyEnabled false
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }

    debug {
        resValue("string", "app_name_debug", "HappyCornDebug")
        resValue("integer", "token", "365")
    }
}
複製程式碼

編譯後,對應變體目錄結構下會生成資原始檔,及對應的資源鍵值。

Android Gradle defaultConfig詳解及實用技巧

專案中對應需要的此資源的地方也可以直接取用:

getResources().getString(R.string.app_name_debug);
getResources().getInteger(R.integer.token);
複製程式碼

defaultConfig{}中配置的屬性與productFlavors中具體Flavor中配置的屬性重複時,Android Gradle構建時將以productFlavors中的對應配置為準,可以理解成將defaultConfig{}中對應的配置覆蓋掉了。但applicationIdSuffix除外(applicationIdSuffix依然是追加的形式)。

在現實的專案需求中,外部傳入的引數鍵值或通過Gradle/Android Gradle指令碼獲取的值,結合defaultConfig{}配置,變體,以及對應生成的BuildConfig.java或資原始檔,實現一些特定場景下的需求,整體可以非常靈活,且具有一定的技巧性。

相關文章