Gradle buildType/productFlavor с помощью неожиданного buildConfigField - программирование

Gradle buildType/productFlavor с помощью неожиданного buildConfigField

Учитывая приведенную ниже конфигурацию:

productFlavors {
  normal {
    applicationId "com.app"
  }

  mock {
    applicationId "com.app.mock"
  }
}

buildTypes {
  debug {
    productFlavors.normal.buildConfigField "boolean", "mockMode", "false"
    productFlavors.mock.buildConfigField "boolean", "mockMode", "true"
  }

  release {
    productFlavors.normal.buildConfigField "boolean", "mockMode", "false"
    // Release should never point to mocks. Ever.
    productFlavors.mock.buildConfigField "boolean", "mockMode", "false"
  }
}

enter image description here

Я бы ожидал BuildConfig.mockMode = true;, однако это результирующая конфигурация сборки:

public final class BuildConfig {
  public static final boolean DEBUG = Boolean.parseBoolean("true");
  public static final String APPLICATION_ID = "*****";
  public static final String BUILD_TYPE = "debug";
  public static final String FLAVOR = "mock";
  public static final int VERSION_CODE = 1;
  public static final String VERSION_NAME = "1.0";
  // Fields from product flavor: mock
  public static final boolean mockMode = false;
}

Из небольшого исследования/отладки я понял, что если я изменю значение для аромата продукта в версии buildType, он фактически обновит значение BuildConfig.mockMode, несмотря на то, что в качестве моего варианта сборки выбран mockDebug.

У меня уже есть лучшее решение для достижения того, что я хочу сделать, поэтому я просто ищу ответ, который помогает мне понять, почему Gradle действует таким образом на основе конфигурации, чтобы помочь мне понять больше что он делает.

4b9b3361

Ответ 1

Вы можете извлечь логику, чтобы определить фактическое значение поля BuildConfig в собственном методе. Таким образом, конфигурация DSL имеет одну строку. Это выглядит примерно так (не проверено - ожидайте синтаксические ошибки):

buildTypes {
    applicationVariants.all { variant ->
        variant.buildConfigField "boolean", "mockMode", mockMode(variant)
    }
}

def mockMode(variant) {
    //Return true or false depending on variant.buildType and variant.productFlavors 
}

Ответ 2

Довольно легко понять, как только вы запускаете эту конфигурацию:

buildTypes {
    debug {
        println("debug!")
    }
    release {
        println("release!")
    }
}

Что вы увидите в журнале сборки:

Information:Gradle tasks [:app:assembleOneDebug]
debug!
release!
:app:preBuild UP-TO-DATE
...

Это означает, что все 4 строки вашего кода выполнены, поэтому единственными эффективными линиями являются последние 2:

productFlavors.normal.buildConfigField "boolean", "mockMode", "false"
productFlavors.mock.buildConfigField "boolean", "mockMode", "false"

Что приводит к вашему BuildConfig наличию:

public static final boolean mockMode = false;