Product Flavor dalam pengembangan Android adalah mekanisme Gradle yang memungkinkan pembuatan beberapa varian dari satu aplikasi dari basis kode yang sama. Setiap flavor dapat memiliki applicationId, sumber daya, dependensi, dan fungsionalitas sendiri — misalnya, versi gratis dan berbayar. Menurut Google Android Developers, 2025, Product Flavors termasuk dalam sistem Build Variants dan digabungkan dengan Build Types melalui flavorDimensions. Ini adalah pendekatan standar untuk mempublikasikan beberapa versi aplikasi di Google Play.
Poin Penting
Product Flavor adalah konfigurasi Gradle di blok android.productFlavors yang mendeskripsikan varian produk. Setiap flavor dapat mengganti applicationId, versionName, versionCode, minSdkVersion, targetSdkVersion, signingConfig, dan parameter defaultConfig lainnya. Product Flavors tidak memiliki batasan jumlah: proyek dapat berisi 2, 5, 10 flavor — Gradle akan memproses semua kombinasi.
Product Flavor memecahkan masalah codebase reuse — ketika dari satu repositori perlu dibuat beberapa aplikasi yang berbeda. Skenario umum: versi gratis dengan iklan dan versi berbayar tanpa; versi demo dengan fungsionalitas terbatas; versi korporat dan konsumen; aplikasi white-label untuk klien berbeda. Tanpa Product Flavors, setiap versi harus dipertahankan di proyek terpisah, yang menyebabkan 60-70% duplikasi kode.
Secara historis, Product Flavors muncul di Android Gradle Plugin 0.9 (2013) sebagai pengganti konfigurasi ant. Sebelumnya, pengembang menggunakan proyek terpisah untuk versi berbeda atau penggantian sumber daya manual sebelum kompilasi. Pengenalan flavor di AGP menyatukan pendekatan tersebut dan menjadikannya standar. Menurut survei JetBrains, 2024, 78% proyek Android dengan beberapa versi menggunakan Product Flavors, sisanya — peralihan manual melalui BuildConfig atau reflection.
Build Type mengelola proses kompilasi (debug dengan debugging, release dengan optimasi). Product Flavor mengelola konten kompilasi (free tanpa fungsi berbayar, paid dengan fungsi tersebut). Build Type adalah konfigurasi infrastruktural, Product Flavor — konfigurasi produk. Kedua konsep bersifat ortogonal: kompilasi debug dari free-flavor berbeda dari kompilasi release free-flavor hanya dalam parameter kompilasi, bukan dalam fungsionalitas. Product Flavor tidak dapat digunakan untuk menonaktifkan debugger — itu adalah tugas Build Type.
Flavor Dimensions (dimensi) — mekanisme pengelompokan Product Flavors ke dalam kategori independen. Jika aplikasi memiliki versi gratis/berbayar dan secara terpisah wilayah Amerika/Eropa, flavour dikelompokkan ke dalam dua dimensi: „tier” (free, paid) dan „region” (us, eu). Gradle membuat produk kartesian dari dimensi: freeUs, freeEu, paidUs, paidEu — 4 varian. Tanpa dimensi, Gradle akan menganggap keempat flavour sebagai satu bidang dan hanya satu yang dapat dipilih.
Dimensi dideklarasikan di blok flavorDimensions sebagai string atau daftar string. Urutan dimensi memengaruhi prioritas source sets: dimensi pertama memiliki prioritas tertinggi. Jika dimensi A (tier) adalah yang pertama, maka src/free/ akan mengganti src/us/ jika terjadi konflik sumber daya. Urutan juga memengaruhi penamaan Variant: pertama flavor dari dimensi pertama, lalu kedua, lalu Build Type: freeUsDebug.
Jumlah dimensi tidak terbatas, tetapi setiap dimensi baru mengalikan jumlah Build Variants. Untuk proyek dengan 4 dimensi (masing-masing 2 flavour) dan 2 build types: 2 × 2 × 2 × 2 × 2 = 32 varian. Batas praktis — 3 dimensi (maksimal 8-12 varian). Lebih dari itu — konfigurasi Gradle melambat, dan panel Build Variants di Android Studio menjadi tidak terbaca.
android {
flavorDimensions "tier", "api"
productFlavors {
free {
dimension "tier"
applicationId "com.example.app.free"
versionNameSuffix "-free"
}
paid {
dimension "tier"
applicationId "com.example.app.paid"
}
minApi21 {
dimension "api"
minSdk 21
}
minApi26 {
dimension "api"
minSdk 26
}
}
}
// Hasil: freeMinApi21, freeMinApi26, paidMinApi21, paidMinApi26
// Masing-masing × debug/release = 8 Build Variants
Untuk membuat Product Flavor, perlu menambahkan blok productFlavors di dalam android, menentukan nama flavor dan parameternya. Deklarasi minimal flavor adalah nama dan dimension. Semua parameter lainnya diwarisi dari defaultConfig dan dapat diganti. Flavor mewarisi defaultConfig sepenuhnya, termasuk applicationId, versionCode, dan testInstrumentationRunner.
Setiap flavor dapat mengganti applicationId — ini memungkinkan instalasi beberapa versi aplikasi pada satu perangkat secara bersamaan. Misalnya, versi free akan menjadi com.example.app.free, dan paid — com.example.app.paid. Jika applicationId tidak diganti, semua flavour akan memiliki pengenal yang sama dan tidak dapat diinstal secara paralel. applicationId harus cocok dengan package di manifes (jika applicationIdSuffix tidak digunakan).
AGP 8+ merekomendasikan penggunaan Kotlin DSL sebagai pengganti Groovy untuk build.gradle. Kotlin DSL menyediakan akses type-safe ke konfigurasi: IDE menyarankan nama parameter, memeriksa tipe pada tahap kompilasi, dan menyoroti kesalahan. Migrasi dari Groovy ke Kotlin DSL untuk Product Flavors biasanya terdiri dari mengganti tanda kutip dengan tanda kurung dan menambahkan tipe. AGP kompatibel mundur — kedua sintaks berfungsi secara paralel dalam proyek yang sama.
// build.gradle.kts — Kotlin DSL
android {
flavorDimensions += "tier"
productFlavors {
register("free") {
dimension = "tier"
applicationId = "com.example.app.free"
versionNameSuffix = "-free"
buildConfigField("boolean", "IS_PREMIUM", "false")
}
register("paid") {
dimension = "tier"
applicationId = "com.example.app.paid"
versionNameSuffix = "-paid"
buildConfigField("boolean", "IS_PREMIUM", "true")
}
}
}
Setiap Product Flavor membuat source set sendiri — direktori src/<flavorName>/. Di direktori ini dapat ditempatkan sumber daya yang diganti, kode sumber, dan manifes. Source set flavor berfungsi sebagai lapisan di atas main: file dari src/free/res/ mengganti file dari src/main/res/ dengan nama yang sama. Ini memungkinkan string, ikon, warna, dan tata letak yang berbeda untuk setiap flavor tanpa mengubah kode utama.
Untuk mengganti kelas Java/Kotlin, ada dua pendekatan: flavor-specific implementation (implementasi kelas abstrak di setiap flavor) dan BuildConfig field (percabangan dalam kode). Pendekatan pertama lebih bersih: Anda mendefinisikan antarmuka atau kelas abstrak di main, dan implementasi konkret di src/free/ dan src/paid/. Saat kompilasi, hanya implementasi flavor saat ini yang dikompilasi. Ini memberikan keuntungan simultan: ukuran APK lebih kecil (kode berbayar tidak masuk ke versi free) dan keamanan (fungsi berbayar tidak dapat dipanggil secara tidak sengaja).
AndroidManifest.xml di source set flavor tidak menggantikan, tetapi digabungkan dengan manifes utama. Penggabungan terjadi sesuai aturan Android: atribut yang sama dalam satu elemen diganti, yang unik ditambahkan. Misalnya, jika di manifes utama izin INTERNET dideklarasikan, tetapi di free tidak, internet akan tetap ada. Namun tools:node="replace" memungkinkan penggantian seluruh blok manifes untuk flavor tertentu. Ini berguna ketika flavour yang berbeda memerlukan izin yang berbeda (menulis ke SD untuk paid, kamera untuk free).
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:label="Free App"
tools:replace="android:label">
</application>
</manifest>
Mari kita lihat skenario umum: free — versi dengan iklan dan fungsi dasar, paid — tanpa iklan, dengan fungsionalitas diperluas. Untuk versi free, applicationId „com.example.app.free” ditetapkan, untuk paid — „com.example.app.paid”. Kedua versi dapat diinstal pada perangkat yang sama secara bersamaan, karena applicationId adalah pengenal unik aplikasi di sistem Android.
Secara arsitektur, pemisahan didasarkan pada interface + flavor implementation. Di source set utama, antarmuka PaymentService dideklarasikan. Di src/free/ terdapat implementasi yang menampilkan iklan sebelum pembayaran melalui AdMob. Di src/paid/ — implementasi yang langsung menuju ke gateway pembayaran. Kode yang menggunakan PaymentService tidak tahu implementasi mana yang dimuat — ini diputuskan pada tahap kompilasi. Pendekatan semacam itu menjamin bahwa kode manajemen langganan tidak masuk ke versi free, bahkan jika pengembang secara tidak sengaja memanggilnya.
Ukuran APK untuk flavor berbeda dapat berbeda 5-15 MB karena penyertaan/pengecualian dependensi. Untuk mengecualikan pustaka dari flavor tertentu, gunakan flavor-specific dependencies di build.gradle: freeImplementation 'com.google.android.gms:play-services-ads:23.0.0'. Dependensi ini hanya akan ditambahkan untuk varian free dan tidak akan meningkatkan ukuran versi paid. Untuk dependensi bersama, gunakan implementation — ini disertakan di semua flavor.
// src/main/kotlin/com/example/payment/PaymentService.kt
interface PaymentService {
fun processOrder(amount: Double, callback: (PaymentResult) -> Unit)
}
// src/free/kotlin/.../FreePaymentService.kt
class FreePaymentService : PaymentService {
override fun processOrder(amount: Double, callback: (PaymentResult) -> Unit) {
AdManager.showInterstitial {
PaymentGateway.charge(amount, callback)
}
}
}
// src/paid/kotlin/.../PaidPaymentService.kt
class PaidPaymentService : PaymentService {
override fun processOrder(amount: Double, callback: (PaymentResult) -> Unit) {
PaymentGateway.charge(amount, callback)
}
}
Di proyek multi-modul, modul pustaka mungkin tidak memiliki Product Flavors sendiri, yang menimbulkan masalah: pustaka dikompilasi sekali (sebagai release), tetapi modul app dengan flavor mengharapkan pustaka dengan varian yang sesuai. Mulai AGP 8.1, pustaka dapat memublikasikan multiple variants melalui blok publishing.multipleVariants — ini memungkinkan publikasi semua varian flavor pustaka ke satu repositori maven, dan modul app akan secara otomatis memilih yang diperlukan.
Pendekatan alternatif — mendeklarasikan flavorDimensions dan productFlavors yang sama di pustaka seperti di modul app. AGP secara otomatis mencocokkan flavour berdasarkan kecocokan nama penuh dalam satu dimensi. Jika nama flavor di pustaka cocok dengan nama di app, AGP akan membuat varian yang konsisten. Untuk kemudahan pemeliharaan, disarankan untuk menempatkan definisi flavour umum di Convention Plugin — plugin Gradle yang diterapkan ke semua modul proyek.
Untuk pustaka yang tidak dimaksudkan untuk publikasi (modul internal), cukup menyinkronkan flavour melalui build.gradle proyek root. Gradle menyediakan metode subprojects yang memungkinkan penerapan konfigurasi ke semua subproyek. Namun perlu diingat bahwa konfigurasi yang terlalu besar di subprojects memperlambat fase konfigurasi. Disarankan menggunakan Convention Plugins — mereka dikompilasi sekali dan digunakan kembali, yang mengurangi waktu konfigurasi sebesar 15-30%.
Pertanyaan Umum
Tidak ada batasan jumlah, tetapi setiap dimensi mengalikan jumlah Build Variants. 4 flavour dalam satu dimensi + 2 build types = 8 varian. 4 + 4 dalam dua dimensi = 16 varian. Disarankan maksimal 3 dimensi dan 10-12 varian total.
Ya, melalui source set src/<flavor>/AndroidManifest.xml. Manifes digabungkan dengan manifes utama. Untuk mengganti seluruh blok, gunakan tools:node="replace". Misalnya, untuk mengubah label aplikasi atau izin untuk flavor tertentu.
Gunakan konfigurasi <flavorName>Implementation. Contoh: freeImplementation 'com.google.android.gms:play-services-ads:23.0.0'. Dependensi ini hanya akan disertakan saat kompilasi varian free. Untuk paid: paidImplementation. Dependensi bersama ditentukan melalui implementation.
Product Flavor menentukan versi produk (free, paid, demo), Build Type — metode kompilasi (debug, release). Flavour dapat mengganti applicationId, versionName, sumber daya. Build Type mengelola debuggable, minification, signing. Keduanya ortogonal dan digabungkan dalam Build Variant.
Ya, Product Flavors bekerja dengan Compose tanpa batasan. Flavor yang berbeda dapat memiliki layar Compose yang berbeda melalui source sets atau implementasi kelas abstrak. Juga dapat menambahkan dependensi Compose khusus flavor: freeImplementation 'androidx.compose.ui:ui-tooling'.
Ringkasan
Kami akan mengembangkan aplikasi seluler turnkey
IT Sectr membuat aplikasi iOS dan Android untuk startup dan bisnis sejak 2017. Kami akan memberi saran dan mengusulkan solusi terbaik.
Baca juga