이번에는 Gradle 빌드 변형 구성에 대해 알아보겠습니다.
먼저, 현재 빌드정보를 담고있는 buildConfig에 필드를 추가하는 방법 필드의 정보들을 불러오는 방법을 알아보겠습니다.
그리고 BuildType, ProductFlavors마다 BuildConfig을 변형 구성하는 방법과 Source Set을 바꿔서 구성하는 방법을 알아보겠습니다.
BuildType이란?
buildType은 일반적으로 개발자가 새 모듈을 생성하면 debug와 release 두 가지를 생성합니다.
debug는 빌드 유형을 선언하지 않더라도 Android Studio에서는 debuggable true를 default값으로 구성하며 이 속성 덕분에 Android 기기에서 앱을 디버깅할 수 있습니다.
release는 출시용 buildType으로 일반적으로 proguard를 사용하여 난독화 및 앱 축소를 진행합니다.
또한, 새로운 buildType을 만들고 기존의 buildType의 값들로 초기화 하려면 initWith 속성을 사용하면 됩니다.
android {
// ...
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
debug {
applicationIdSuffix ".debug"
debuggable true
}
staging {
initWith debug
applicationIdSuffix ".debugStaging"
}
}
}
BuildConfig이란?
buildConfig에는 현재 빌드에 대한 정보들이 들어있고 이 정보들을 통해서 코드에서도 현재 빌드에 대한 정보들을 읽어올 수 있습니다.
대부분의 정보들은 app레벨의 build.gradle의 defaultConfig에 설정한 값으로 가져옵니다.
하지만, defaultConfig은 모든 빌드 구성에서 가져오는 기본값일 뿐, BuildConfig은 BuildType과 ProductFlavor를 변경할 경우 다르게 구성됩니다.
BuildConfig은 아래와 같이 구성됩니다.
public final class BuildConfig {
public static final boolean DEBUG = Boolean.parseBoolean("true");
public static final String APPLICATION_ID = "com.seosh817.androidconfigs.stage.debug";
public static final String BUILD_TYPE = "debug";
public static final String FLAVOR = "stage";
public static final int VERSION_CODE = 1;
public static final String VERSION_NAME = "1.0-stage";
}
DEBUG -> 현재 BuildType이 Debug인지 Release인지 Boolean값으로 return합니다.
APPLICATION_ID -> 일반적으로 현재 빌드구성의 {applicationId}.{productFlavor}.{buildType}으로 구성됩니다.
BUILD_TYPE -> 현재 빌드의 BuildType을 return 합니다
FLAVOR -> 현재 빌드의 ProductFlavor를 return 합니다.
VERSION_CODE -> 현재 빌드의 버전코드를 return 합니다.
VERSION_NAME -> 현재 빌드의 버전네임을 reutrn 합니다.
build.gradle
android {
// ...
defaultConfig {
applicationId "com.seosh817.androidconfigs"
minSdk 23
targetSdk 31
versionCode 1
versionName "1.0"
}
// ...
}
buildConfigField로 BuildConfig에 필드 추가하기
buildConfigField를 통해 BuildConfig에 필드를 추가할 수 있고 Type, Name, Value 순서로 입력해주면 됩니다.
build.gradle에 buildConfigField를 추가하고 빌드를 돌려주면 BuildConfig에 필드가 추가됩니다.
build.gradle
android {
// ...
defaultConfig {
buildConfigField "String", "BASE_URL", "\"https://url.com/\""
}
// ...
}
public final class BuildConfig {
// ...
// Field from default config.
public static final String BASE_URL = "https://url.com/";
}
이렇게 생성된 필드들은 모두 static으로 선언되므로 BuildConfig.name을 통해 값들을 읽어올 수 있습니다.
Log.i(TAG, "BASE_URL: ${BuildConfig.BASE_URL}")
resValue로 res > values 디렉토리의 gradleResValues.xml에 값 추가하기
resValue를 통해 gradleResValues.xml에 값을 추가할 수 있습니다.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Automatically generated file. DO NOT MODIFY -->
<!-- Value from default config. -->
<string name="base_url" translatable="false">BASE_URL</string>
</resources>
이렇게 생성된 값들은 R.string.name을 통해 값을 읽어올 수 있습니다.
Log.i(TAG, "base_url: ${R.string.base_url}")
mainfestPlaceholders를 이용해서 manifest에서 빌드정보 가져오기
mainfestPlaceholders에 넣어주면 AndroidManifest에서도 빌드정보를 읽을 수 있습니다.
build.gradle
android {
defaultConfig {
// ...
manifestPlaceholders = ["baseUrl": "https://url.com/"]
}
// ...
}
AndroidManifest.xml
<intent-filter ... >
<data android:scheme="https" android:host="${baseUrl}" ... />
...
</intent-filter>
그 외에도 현재 빌드의 BuildConfig의 applicationId도 가져올 수 있습니다.
<intent-filter ... >
<action android:name="${applicationId}.TRANSMOGRIFY" />
...
</intent-filter>
// product flavor dev
<intent-filter ... >
<action android:name="com.seosh817.androidconfings.dev.debug.TRANSMOGRIFY" />
...
</intent-filter>
gradle.properties와 local.properties에서 정보읽기
기본적으로 앱 코드상으로 노출시키지 않고 싶은 정보들은 gradle.properties 혹은 local.properties에 저장합니다.
gradle.properties와 local.properties에서 정보를 가져오도록 하겠습니다.
local.properties에서 프로퍼티 가져오기
local.properties에서 프로퍼티는 Properties를 통해서 읽을 수 있습니다.
Properties는 HashTable을 상속하며 Properties.load()를 통해서 Inputstream을 라인별로 읽어서 HashTable에 값을 넣어주므로 객체를 통해 프로퍼티들을 가져올 수 있게 해줍니다.
def getLocalProperty(String propName) {
def propsFile = rootProject.file("local.properties")
if (propsFile.exists()) {
def props = new Properties()
props.load(new FileInputStream(propsFile))
if (props[propName] != null) {
return props[propName]
} else {
print("no such property" + propName)
}
}
}
android {
// ...
defaultConfig {
// ...
buildConfigField "String", "BASE_URL", "\"${getLocalProperty("BASE_URL")}\""
}
}
gradle.properties에서 프로퍼티 가져오기
gradle.properties에서 프로퍼티는 project.properties를 통해 가져올 수 있습니다.
android {
// ...
defaultConfig {
// ...
buildConfigField "String", "BASE_URL", "\"${project.property("BASE_URL")}\""
}
// ...
}
ProductFlavors란?
productFlavors를 이용하면 동일한 프로젝트에서 여러 버전의 다른 앱을 만들 수 있습니다.
android {
// Specifies one flavor dimension.
flavorDimensions "version"
productFlavors {
dev {
dimension "version"
applicationIdSuffix ".dev"
versionNameSuffix "-dev"
}
stage {
dimension "version"
applicationIdSuffix ".stage"
versionNameSuffix "-stage"
}
live {
dimension "version"
applicationIdSuffix ".live"
versionNameSuffix "-live"
}
}
}
dev, stage, live 총 3가지의 productFlavor를 만들어주었습니다.
applicationIdSuffix를 추가해주면 applicationId에 suffix가 추가됩니다.
dev로 예를들면 .dev가 추가되어 applicationId는 com.seosh817.androidconfigs.dev.debug가 되어서 applicationId가 서로 다른 앱이 만들어지게 됩니다.
versionNameSuffix도 마찬가지로 versionName에 suffix가 추가되어 1.0.0-dev와 같이 선언됩니다.
위처럼 3가지 flavor를 추가하면 buildType x productFlavors로 총 6가지 Build Varaints가 구성됩니다.
devDebug
devRelease
stageDebug
stageRelease
liveDebug
liveRelease
productFlavors에 BuildConfigField 추가하기
productFlavor에도 값을 buildConfigField, manifestholders, resValue 모두 사용할 수 있습니다.
android {
productFlavors {
dev {
// 개발용
// ...
buildConfigField "String", "BASE_URL", "\"https://url.dev.com/\""
manifestPlaceholders = [ appLabel: "DevApp"]
resValue("string", "base_url", "BASE_URL")
}
stage {
// 사내 테스트용
// ...
buildConfigField "String", "BASE_URL", "\"https://url.stg.com/\""
manifestPlaceholders = [ appLabel: "StageApp"]
}
live {
// 실제 배포용
// ...
buildConfigField "String", "BASE_URL", "\"https://url.com/\""
manifestPlaceholders = [ appLabel: "LiveApp"]
}
}
}
Build Variant를 바꾸어 빌드해주면 BuildConfig 또한 현재 빌드에 맞춰서 바뀝니다.


public final class BuildConfig {
// ...
// Field from product flavor: dev
public static final String BASE_URL = "https://url.dev.com/";
}
applicationVariants를 통해 Build Variant들을 가져와서 BuildConfigField를 수정할 수도 있습니다.
android {
// ...
applicationVariants.all { variant ->
def BASE_URL = ""
if (variant.getName().contains("dev")) {
BASE_URL = "https://url.dev.com/"
} else if (variant.getName().contains("stage")) {
BASE_URL = "https://url.stg.com/"
} else if (variant.getName().contains("live")) {
BASE_URL = "https://url.com/"
}
variant.buildConfigField "String", "BASE_URL", "\"${BASE_URL}\""
}
}
소스 세트 추가
Source Set를 이용하면 Build Variants의 변경에 따라 코드와 resource를 다르게 설정할 수 있습니다.
기본적으로 안드로이드 스튜디오는 모든 Build Variants 간에 공유하는 main / source set를 생성합니다.
이렇게 공용으로 사용되는 source set 말고, 특정 BuildType, plroudctFlavor를 사용하는 BuildVariant에 사용하는 source set를 생성할 수 있습니다. 예를들면, 앱에서 기본적으로 사용하는 부분은 main / source set에 넣고 특정 flavor에서 다르게 사용하고 싶을 때 사용하면 됩니다.
예를들어, stage productFlavor에 kotlin 디렉토리를 만들고 싶다면 아래와 같이 진행하면 됩니다.
- Project 탭으로 바꿉니다.
- app/src로 마우스커서를 이동합니다.
- 오른쪽 클릭 후 New -> Directory를 선택합니다.
- Gradle SourceSets 메뉴 중 stage/kotlin을 선택해서 생성해줍니다.

감사합니다!