일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 |
- android
- Rxjava
- textfield
- Hilt
- livedata
- 암호학
- 백준
- Compose
- activity
- AWS
- ProGuard
- androidStudio
- GitHub
- Codeforces
- boj
- Python
- 코드포스
- 코루틴
- pandas
- MiTweet
- 쿠링
- Coroutines
- Kotlin
- Gradle
- architecture
- MyVoca
- TEST
- Coroutine
- 프로그래머스
- relay
- Today
- Total
이동식 저장소
[Android] Build variant 심화 본문
Product flavor 결합하기
Flavor를 여러 그룹으로 나눌 수 있다. 예를 들어 1) API 레벨에 따라 2) 체험판 여부에 따라 포함되는 코드를 다르게 하고 싶다면, flavor dimension을 여러 개 만들고 각 dimension에서 flavor를 하나씩 고르면 된다. 고등학교 확통 시간에 배웠던 윗도리 3개와 바지 4개를 입는 경우의 수와 비슷하다.
위의 예시를 gradle로 구현해 보자.
android {
...
buildTypes {
debug {...}
release {...}
}
// flavor 그룹. 모든 flavor는 적어도 하나의 flavor dimension에 속해야 한다.
// flavor를 고를 때 여기에 나열된 순서대로 고른다.
flavorDimensions "api", "mode"
productFlavors {
demo {
// mode 그룹에 속함
dimension "mode"
...
}
full {
dimension "mode"
...
}
// api flavors
minApi24 {
dimension "api"
minSdkVersion 24
// 기기가 최신 API 버전에 대응하는 앱을 찾을 수 있도록
// versionCode를 최신 API부터 내림차순으로 설정한다.
versionCode 30000 + android.defaultConfig.versionCode
versionNameSuffix "-minApi24"
...
}
minApi23 {
dimension "api"
minSdkVersion 23
versionCode 20000 + android.defaultConfig.versionCode
versionNameSuffix "-minApi23"
...
}
minApi21 {
dimension "api"
minSdkVersion 21
versionCode 10000 + android.defaultConfig.versionCode
versionNameSuffix "-minApi21"
...
}
}
}
...
Flavor를 분류하는 dimension 2개를 만들고, 각 dimension에 속하는 flavor를 선언하였다.
Build variant는 <product-flavor><build-type>
으로 만들어진다고 했다. 그런데 flavor dimension이 여러 개 존재하므로 <product-flavor>
부분은 다시 <api><mode>
로 나뉜다. 따라서 최종 build variant는 다음의 형식으로 만들어진다.
<api><mode><build-type>
이렇게까지 나누는 이유는 flavor 또는 build type에만 속하는 source set을 정의할 수 있기 때문이다. 앱의 핵심 부분은 main
에서 개발하고, API 레벨에 따라 구현이 다른 부분은 각 flavor의 source set에서 구현할 수 있다.
어, main
이라고? 그렇다. src
에 있는 그 main
맞다. 사실 여기 있는 폴더 각각이 모두 build variant이다. main
은 모든 build variant이 공유하는 코드를, test
는 local test 코드를 담고 있는 build variant인 것이다.

특정 조합만 무시하기
Flavor의 특정 조합이 불필요하다면, variantFilter
블럭 안에 무시하고 싶은 조합의 조건을 정의할 수 있다.
android {
...
buildTypes {...}
flavorDimensions "api", "mode"
productFlavors {
demo {...}
full {...}
minApi24 {...}
minApi23 {...}
minApi21 {...}
}
variantFilter { variant ->
def names = variant.flavors*.name
// Build type 이름 검사법: variant.buildType.name == "<buildType>"
if (names.contains("minApi21") && names.contains("demo")) {
// 무시
setIgnore(true)
}
}
}
...
Source set 정의하기
위에서 말했다시피 특정 flavor, build type, build variant별로 고유한 source set을 만들 수 있다. 공통 기능은 main
에서 개발하고, 선택적으로 제공되는 기능은 source set에서 개발할 수 있다. 디버깅 코드를 debug
의 source set에 작성한다던가.
Source set을 어디에 정의해야 하는지 궁금하다면 Gradle의 sourceSets
작업을 실행하자. Android Studio 오른쪽 위의 Gradle 탭을 누르고, 코끼리 버튼을 눌러 gradle sourceSets
를 입력하면 된다.

친절하게 알려준다.
main
----
Compile configuration: compile
build.gradle name: android.sourceSets.main
Java sources: [macrobenchmark\src\main\java]
Kotlin sources: [macrobenchmark\src\main\kotlin, macrobenchmark\src\main\java]
Manifest file: macrobenchmark\src\main\AndroidManifest.xml
Android resources: [macrobenchmark\src\main\res]
Assets: [macrobenchmark\src\main\assets]
AIDL sources: [macrobenchmark\src\main\aidl]
RenderScript sources: [macrobenchmark\src\main\rs]
JNI sources: [macrobenchmark\src\main\jni]
JNI libraries: [macrobenchmark\src\main\jniLibs]
Java-style resources: [macrobenchmark\src\main\resources]
주의: 하나의 폴더는 하나의 source set에만 속할 수 있다. 예를 들어 특정 코드를 test
와 androidTest
모두에서 사용할 수는 없다. Android Studio 내부 구현 자체가 그렇게 구현돼 있다고 한다.
Source set 탐색 순서
demoDebug
build variant를 빌드할 때, 다음의 순서대로 코드가 탐색된다.
demoDebug
(build variant)debug
(build type)demo
(product flavor)main
(main)
더 구체적인 source set이 우선한다고 보면 된다. 예를 들어 이름이 같은 파일이 demoDebug
와 debug
에 모두 존재한다면, demoDebug
의 클래스가 사용된다.
주의: 여러 build type에 이름이 같은 파일을 정의할 수는 있지만, build type과 main 모두에 정의해서는 안 된다.
Flavor dimension이 여러 개 존재한다면, 모든 flavor의 조합마다 source set을 정의해야 한다. 즉 모든 <product-flavor>
에 대응하는 source set이 존재해야 한다.
의존성 정의
라이브러리 등 의존성을 정의할 때 특정 build variant만 의존성을 사용하도록 할 수 있다. 예를 들어 의존성을debugImplementation
으로 정의하면, 해당 라이브러리는 debug
에서만 사용할 수 있다.
dependencies {
// "mylibrary" 모듈을 "free" flavor의 의존성으로 정의한다.
freeImplementation project(":mylibrary")
// 라이브러리를 "test"에서만 사용할 수 있게 정의한다.
testImplementation 'junit:junit:4.12'
// 라이브러리를 "androidTest"에서만 사용할 수 있게 정의한다.
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}
참고
빌드 변형 구성 | Android 개발자 | Android Developers
빌드 변형을 구성하여 단일 프로젝트에서 여러 버전의 앱을 만드는 방법을 알아보세요.
developer.android.com
'Primary > Android' 카테고리의 다른 글
[Android] 계정명이 한글일 때 test error 해결법 (0) | 2022.07.26 |
---|---|
[Android] Manifest 파일이란? (0) | 2022.07.25 |
[Android] 코드 경량화 시 Instrumented test가 실행되지 않는 오류 (0) | 2022.07.19 |
[Android] Build variant 기초 (0) | 2022.07.17 |
Android Runtime with ART, AOT, JIT, DEX (0) | 2022.07.12 |