일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- Compose
- Rxjava
- 백준
- AWS
- Kotlin
- activity
- Python
- Codeforces
- Hilt
- MiTweet
- GitHub
- 코드포스
- livedata
- TEST
- MyVoca
- android
- 쿠링
- boj
- 코루틴
- textfield
- 프로그래머스
- relay
- 암호학
- pandas
- Coroutines
- architecture
- Coroutine
- androidStudio
- ProGuard
- Gradle
- 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'
}
참고
'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 |