Bỏ qua để đến nội dung

Build Variants

Build Variants cho phép bạn tạo nhiều phiên bản khác nhau của ứng dụng từ một codebase duy nhất. Mỗi variant có thể có code, resources, và cấu hình riêng.

flowchart TD
subgraph "Build Types"
D[debug]
R[release]
end
subgraph "Product Flavors"
DE[demo]
FU[full]
end
subgraph "Build Variants"
DD[demoDebug]
DR[demoRelease]
FD[fullDebug]
FR[fullRelease]
end
D --> DD
D --> FD
R --> DR
R --> FR
DE --> DD
DE --> DR
FU --> FD
FU --> FR
Thành phần Mô tả Ví dụ
Build Type Cách build ứng dụng debug, release, staging
Product Flavor Phiên bản nội dung demo, full, free, paid
Build Variant Kết hợp type + flavor demoDebug, fullRelease

Build Types định nghĩa cách Gradle build và package ứng dụng. Mặc định Android Studio tạo 2 build types:

android {
buildTypes {
debug {
// Debug được cấu hình mặc định: debuggable = true
applicationIdSuffix = ".debug"
versionNameSuffix = "-debug"
// Không minify để build nhanh
isMinifyEnabled = false
}
release {
isMinifyEnabled = true
isShrinkResources = true
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
// Custom build type
create("staging") {
// Kế thừa từ debug
initWith(getByName("debug"))
applicationIdSuffix = ".staging"
versionNameSuffix = "-staging"
// Môi trường staging
buildConfigField("String", "API_URL", "\"https://staging.api.com\"")
}
}
}
Thuộc tính Mô tả Mặc định Debug Mặc định Release
isDebuggable Cho phép attach debugger true false
isMinifyEnabled Bật code shrinking (R8) false false
isShrinkResources Loại bỏ resources không dùng false false
applicationIdSuffix Suffix cho applicationId
versionNameSuffix Suffix cho versionName
signingConfig Signing configuration debug keystore (cần cấu hình)

💡 Mẹo: Debug build được tự động sign với debug keystore. Release build cần cấu hình signing riêng.


Product Flavors tạo các phiên bản khác nhau của ứng dụng với nội dung hoặc tính năng khác nhau.

android {
// Bắt buộc: Khai báo flavor dimensions
flavorDimensions += "version"
productFlavors {
create("demo") {
dimension = "version"
applicationIdSuffix = ".demo"
versionNameSuffix = "-demo"
// Custom build config fields
buildConfigField("Boolean", "IS_DEMO", "true")
buildConfigField("Int", "MAX_ITEMS", "10")
}
create("full") {
dimension = "version"
buildConfigField("Boolean", "IS_DEMO", "false")
buildConfigField("Int", "MAX_ITEMS", "Integer.MAX_VALUE")
}
}
}
// Trong code Kotlin
if (BuildConfig.IS_DEMO) {
showDemoLimitation()
}
val maxItems = BuildConfig.MAX_ITEMS

⚠️ Quan trọng: Để sử dụng BuildConfig, phải bật buildFeatures.buildConfig = true trong build.gradle.kts.


Khi có nhiều “chiều” khác nhau cho product flavors, sử dụng flavor dimensions:

android {
flavorDimensions += listOf("version", "api")
productFlavors {
// Dimension: version
create("demo") {
dimension = "version"
applicationIdSuffix = ".demo"
}
create("full") {
dimension = "version"
}
// Dimension: api
create("minApi24") {
dimension = "api"
minSdk = 24
}
create("minApi28") {
dimension = "api"
minSdk = 28
}
}
}

Gradle tạo variants từ tất cả combinations:

demoMinApi24Debug
demoMinApi24Release
demoMinApi28Debug
demoMinApi28Release
fullMinApi24Debug
fullMinApi24Release
fullMinApi28Debug
fullMinApi28Release

Ví dụ thực tế: App với môi trường Dev/Prod

Phần tiêu đề “Ví dụ thực tế: App với môi trường Dev/Prod”
android {
namespace = "com.example.myapp"
compileSdk = 35
defaultConfig {
applicationId = "com.example.myapp"
minSdk = 24
targetSdk = 35
versionCode = 1
versionName = "1.0.0"
}
buildFeatures {
buildConfig = true
}
flavorDimensions += "environment"
productFlavors {
create("dev") {
dimension = "environment"
applicationIdSuffix = ".dev"
versionNameSuffix = "-dev"
// Môi trường development
buildConfigField("String", "API_BASE_URL", "\"https://dev.api.example.com\"")
buildConfigField("String", "API_KEY", "\"dev_api_key_123\"")
buildConfigField("Boolean", "ENABLE_LOGGING", "true")
// Resource values
resValue("string", "app_name", "MyApp Dev")
}
create("staging") {
dimension = "environment"
applicationIdSuffix = ".staging"
versionNameSuffix = "-staging"
buildConfigField("String", "API_BASE_URL", "\"https://staging.api.example.com\"")
buildConfigField("String", "API_KEY", "\"staging_api_key_456\"")
buildConfigField("Boolean", "ENABLE_LOGGING", "true")
resValue("string", "app_name", "MyApp Staging")
}
create("prod") {
dimension = "environment"
buildConfigField("String", "API_BASE_URL", "\"https://api.example.com\"")
buildConfigField("String", "API_KEY", "\"prod_api_key_789\"")
buildConfigField("Boolean", "ENABLE_LOGGING", "false")
resValue("string", "app_name", "MyApp")
}
}
buildTypes {
debug {
isMinifyEnabled = false
}
release {
isMinifyEnabled = true
isShrinkResources = true
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
}
NetworkModule.kt
object NetworkModule {
val retrofit: Retrofit = Retrofit.Builder()
.baseUrl(BuildConfig.API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.apply {
if (BuildConfig.ENABLE_LOGGING) {
client(
OkHttpClient.Builder()
.addInterceptor(HttpLoggingInterceptor().setLevel(Level.BODY))
.build()
)
}
}
.build()
}

Mỗi variant có thể có source code và resources riêng:

app/src/
├── main/ # Common source
│ ├── java/
│ └── res/
├── debug/ # Debug build type specific
│ └── java/
├── release/ # Release build type specific
├── dev/ # Dev flavor specific
│ ├── java/
│ └── res/
├── prod/ # Prod flavor specific
│ └── res/
└── devDebug/ # Dev + Debug combination
└── java/
Variant source set > Build type > Flavor > main

Ví dụ với variant devDebug:

  1. src/devDebug/ (nếu có)
  2. src/debug/
  3. src/dev/
  4. src/main/

Loại bỏ các variants không cần thiết:

android {
flavorDimensions += listOf("version", "api")
productFlavors {
create("demo") { dimension = "version" }
create("full") { dimension = "version" }
create("minApi24") { dimension = "api" }
create("minApi28") { dimension = "api" }
}
}
// Filter variants
androidComponents {
beforeVariants { variantBuilder ->
// Loại bỏ demo + minApi28 combinations
if (variantBuilder.productFlavors.containsAll(
listOf("version" to "demo", "api" to "minApi28"))
) {
variantBuilder.enable = false
}
}
}

Cấu hình signing cho từng build type:

android {
signingConfigs {
// Debug đã có sẵn, không cần khai báo
create("release") {
storeFile = file("keystore/release.jks")
storePassword = System.getenv("KEYSTORE_PASSWORD")
keyAlias = System.getenv("KEY_ALIAS")
keyPassword = System.getenv("KEY_PASSWORD")
}
}
buildTypes {
release {
signingConfig = signingConfigs.getByName("release")
// ...
}
}
}

🚨 Chú ý: KHÔNG commit passwords vào source control! Sử dụng environment variables hoặc local.properties.

build.gradle.kts
import java.util.Properties
val localProperties = Properties().apply {
val localPropertiesFile = rootProject.file("local.properties")
if (localPropertiesFile.exists()) {
load(localPropertiesFile.inputStream())
}
}
android {
signingConfigs {
create("release") {
storeFile = file(localProperties.getProperty("RELEASE_STORE_FILE", ""))
storePassword = localProperties.getProperty("RELEASE_STORE_PASSWORD", "")
keyAlias = localProperties.getProperty("RELEASE_KEY_ALIAS", "")
keyPassword = localProperties.getProperty("RELEASE_KEY_PASSWORD", "")
}
}
}

  1. Mở panel Build Variants (View → Tool Windows → Build Variants)
  2. Chọn variant cho mỗi module
  3. Click Sync nếu cần

Hoặc build từ command line:

Terminal window
# Build variant cụ thể
./gradlew assembleDevDebug
./gradlew assembleProdRelease
# Build tất cả variants của một type
./gradlew assembleDebug
./gradlew assembleRelease
# Build AAB
./gradlew bundleProdRelease

Concept Mục đích Ví dụ
Build Type Cách build (debug settings, minification) debug, release, staging
Product Flavor Phiên bản ứng dụng demo/full, free/paid, dev/prod
Flavor Dimension Nhóm các flavors version, api, environment
Build Variant Build type + Flavor(s) demoDebug, prodRelease
Source Set Code/resources cho variant src/demo/, src/debug/