Android geliştirmede Product Flavor, ortak bir kod tabanından aynı uygulamanın birden çok varyantını oluşturmayı sağlayan bir Gradle mekanizmasıdır. Her flavor kendi applicationId'sine, kaynaklarına, bağımlılıklarına ve işlevselliğine sahip olabilir — örneğin, ücretsiz ve ücretli sürümler. Google Android Developers, 2025'e göre, Product Flavors, Build Variants sisteminin bir parçasıdır ve flavorDimensions aracılığıyla Build Types ile birleştirilir. Bu, Google Play'de birden çok uygulama sürümü yayınlamak için standart yaklaşımdır.
Önemli Noktalar
Product Flavor, android.productFlavors bloğu içinde bir ürün varyantını tanımlayan bir Gradle yapılandırmasıdır. Her flavor, applicationId, versionName, versionCode, minSdkVersion, targetSdkVersion, signingConfig ve defaultConfig'in diğer parametrelerini geçersiz kılabilir. Product Flavors'ın miktar sınırı yoktur: bir proje 2, 5 veya 10 flavor içerebilir — Gradle tüm kombinasyonları işler.
Product Flavor, kod tabanı yeniden kullanımı (codebase reuse) sorununu çözer — tek bir depodan birden çok farklı uygulama oluşturulması gerektiğinde. Tipik senaryolar: reklamlı ücretsiz sürüm ve reklamsız ücretli sürüm; sınırlı işlevselliğe sahip demo sürüm; kurumsal ve tüketici sürümleri; farklı müşteriler için white-label uygulamalar. Product Flavors olmadan, her sürüm ayrı bir projede tutulmalıdır, bu da %60-70 kod tekrarına yol açar.
Tarihsel olarak, Product Flavors, Android Gradle Plugin 0.9'da (2013) ant yapılandırmalarının yerini almak üzere ortaya çıktı. Bundan önce, geliştiriciler farklı sürümler için ayrı projeler veya derlemeden önce manuel kaynak değiştirme kullanıyordu. AGP'ye flavor'ların eklenmesi yaklaşımı birleştirdi ve standart haline getirdi. JetBrains, 2024 anketine göre, birden çok sürüme sahip Android projelerinin %78'i Product Flavors kullanırken, geri kalanı BuildConfig veya yansıma yoluyla manuel geçiş kullanmaktadır.
Build Type, derleme sürecini (hata ayıklamalı debug, optimizasyonlu release) yönetir. Product Flavor, derleme içeriğini (ücretli özellikler olmadan free, onlarla birlikte paid) yönetir. Build Type bir altyapı ayarıdır, Product Flavor ise bir ürün ayarıdır. Her iki kavram da diktir: free flavor'ın debug derlemesi, free flavor'ın release derlemesinden yalnızca derleme parametrelerinde farklılık gösterir, işlevsellikte değil. Product Flavor, hata ayıklayıcıyı devre dışı bırakmak için kullanılamaz — bu Build Type'ın işidir.
Flavor Dimensions, Product Flavors'ı bağımsız kategorilere gruplamak için bir mekanizmadır. Bir uygulamanın ücretsiz/ücretli sürümü ve ayrıca bir Amerikan/Avrupa bölgesi varsa, flavor'lar iki boyutta gruplanır: "tier" (free, paid) ve "region" (us, eu). Gradle, boyutların Kartezyen çarpımını oluşturur: freeUs, freeEu, paidUs, paidEu — 4 varyant. Boyutlar olmadan, Gradle dört flavor'ı tek bir düzlem olarak ele alır ve yalnızca biri seçilebilir.
Boyutlar, flavorDimensions bloğunda bir dize veya dize listesi olarak bildirilir. Boyutların sırası, source set'lerin önceliğini etkiler: ilk boyut en yüksek önceliğe sahiptir. A boyutu (tier) önce belirtilirse, kaynak çakışmaları durumunda src/free/, src/us/'u geçersiz kılar. Sıra ayrıca Varyant adının nasıl oluştuğunu da etkiler: önce ilk boyutun flavor'ları gelir, sonra ikinci boyut, sonra Build Type: freeUsDebug.
Boyut sayısı sınırlı değildir, ancak her yeni boyut Build Variants sayısını çarpar. 4 boyutu (her biri 2 flavor) ve 2 build type'ı olan bir proje için 2 × 2 × 2 × 2 × 2 = 32 varyant elde edersiniz. Pratik sınır 3 boyuttur (maksimum 8-12 varyant). Bunun ötesinde, Gradle yapılandırması yavaşlar ve Android Studio'daki Build Variants paneli okunamaz hale gelir.
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
}
}
}
// Sonuç: freeMinApi21, freeMinApi26, paidMinApi21, paidMinApi26
// Her × debug/release = 8 Build Variants
Bir Product Flavor oluşturmak için, android içine bir productFlavors bloğu eklenmeli, flavor adı ve parametreleri belirtilmelidir. Minimum flavor bildirimi, ad ve boyuttur. Diğer tüm parametreler defaultConfig'ten devralınır ve geçersiz kılınabilir. Flavor, applicationId, versionCode, testInstrumentationRunner dahil olmak üzere defaultConfig'i tamamen devralır.
Her flavor applicationId'yi geçersiz kılabilir — bu, aynı cihaza birden çok uygulama sürümünün aynı anda yüklenmesine olanak tanır. Örneğin, ücretsiz sürüm com.example.app.free, ücretli sürüm — com.example.app.paid olacaktır. applicationId geçersiz kılınmazsa, tüm flavor'lar aynı tanımlayıcıya sahip olur ve yan yana yüklenemezler. applicationId, bildirimdeki paketle eşleşmelidir (applicationIdSuffix kullanılmadığı sürece).
AGP 8+, build.gradle için Groovy yerine Kotlin DSL kullanılmasını önerir. Kotlin DSL, yapılandırmaya tür güvenli erişim sağlar: IDE parametre adlarını önerir, derleme zamanında türleri kontrol eder ve hataları vurgular. Product Flavors için Groovy'den Kotlin DSL'ye geçiş genellikle tırnak işaretlerini parantezlerle değiştirmeyi ve türler eklemeyi içerir. AGP geriye dönük uyumludur — her iki sözdizimi de aynı proje içinde paralel olarak çalışır.
// 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")
}
}
}
Her Product Flavor kendi source set'ini oluşturur — bir src/<flavorName>/ dizini. Bu dizin, geçersiz kılınan kaynakları, kaynak dosyalarını ve bildirimi içerebilir. Flavor source set'i, main'in üzerinde bir katman görevi görür: src/free/res/ dosyaları, aynı ada sahip src/main/res/ dosyalarını geçersiz kılar. Bu, ana kodu değiştirmeden her flavor için farklı dizeler, simgeler, renkler ve düzenler olmasını sağlar.
Java/Kotlin sınıflarını geçersiz kılmak için iki yaklaşım vardır: flavor'a özgü uygulama (her flavor'da soyut bir sınıf uygulama) ve BuildConfig alanı (kodda dallanma). İlk yaklaşım daha temizdir: main'de bir arayüz veya soyut sınıf tanımlar ve src/free/ ve src/paid/'de somut uygulamalar oluşturursunuz. Derleme sırasında yalnızca geçerli flavor'ın uygulaması derlenir. Bu, aynı anda avantajlar sağlar: daha küçük APK boyutu (ücretli kod ücretsiz sürüme girmez) ve güvenlik (yanlışlıkla ücretli bir işlevi çağırmak imkansızdır).
Bir flavor source set'indeki AndroidManifest.xml değiştirmez, ana bildirimle birleşir. Birleştirme, Android kurallarına uyar: aynı öğedeki yinelenen öznitelikler geçersiz kılınır, benzersiz olanlar eklenir. Örneğin, ana bildirim INTERNET iznini bildiriyor ve free bildirmiyorsa, internet izni kalır. Ancak tools:node="replace", belirli bir flavor için tüm bildirim bloğunu değiştirmeye olanak tanır. Bu, farklı flavor'lar farklı izinler gerektirdiğinde (ücretli için SD kart yazma, ücretsiz için kamera) kullanışlıdır.
<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>
Tipik bir senaryo düşünelim: free — reklamlar ve temel özellikler içeren bir sürüm, paid — reklamsız, genişletilmiş işlevsellikle. Ücretsiz sürüm için applicationId "com.example.app.free" olarak ayarlanır, ücretli için — "com.example.app.paid". Her iki sürüm de aynı cihaza aynı anda yüklenebilir, çünkü applicationId, Android sistemindeki uygulamanın benzersiz tanımlayıcısıdır.
Mimari olarak, ayrım arayüz + flavor uygulaması yoluyla oluşturulur. Ana source set'te, PaymentService arayüzü bildirilir. src/free/'de, AdMob aracılığıyla ödeme öncesinde bir reklam gösteren bir uygulama bulunur. src/paid/'de — doğrudan ödeme ağ geçidine giden bir uygulama. PaymentService'i kullanan kod, hangi uygulamanın yüklendiğini bilmez — bu derleme zamanında çözülür. Bu yaklaşım, geliştirici yanlışlıkla çağırsa bile abonelik yönetimi kodunun ücretsiz sürüme girmemesini garanti eder.
Bağımlılıkların dahil edilmesi/hariç tutulması nedeniyle farklı flavor'lar için APK boyutu 5-15 MB farklılık gösterebilir. Belirli bir flavor'dan bir kitaplığı hariç tutmak için build.gradle'da flavor'a özgü bağımlılıklar kullanın: freeImplementation 'com.google.android.gms:play-services-ads:23.0.0'. Bu bağımlılık yalnızca ücretsiz varyant için eklenir ve ücretli sürümün boyutunu artırmaz. Paylaşılan bağımlılıklar için implementation kullanın — tüm flavor'lar bunları içerir.
// 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)
}
}
Çok modüllü projelerde, kitaplık modüllerinin kendi Product Flavors'ı olmayabilir, bu da bir sorun yaratır: kitaplık bir kez (release olarak) derlenirken, flavor'lı uygulama modülü kitaplığı karşılık gelen varyantla bekler. AGP 8.1'den itibaren, kitaplıklar publishing.multipleVariants bloğu aracılığıyla birden çok varyant yayınlayabilir — bu, kitaplığın tüm flavor varyantlarının tek bir maven deposunda yayınlanmasını sağlar ve uygulama modülü otomatik olarak doğru olanı seçer.
Alternatif bir yaklaşım, kitaplıkta uygulama modülüyle aynı flavorDimensions ve productFlavors'ı bildirmektir. AGP, bir boyut içinde tam ad eşleştirmesiyle flavor'ları otomatik olarak eşleştirir. Kitaplıktaki flavor adı uygulamadaki adla eşleşirse, AGP tutarlı varyantlar oluşturur. Bakım kolaylığı için, ortak flavor tanımlarının bir Convention Plugin'e çıkarılması önerilir — projenin tüm modüllerine uygulanan bir Gradle eklentisi.
Yayınlanması amaçlanmayan kitaplıklar (iç modüller) için, flavor'ları kök projenin build.gradle'si aracılığıyla senkronize etmek yeterlidir. Gradle, tüm alt projelere yapılandırma uygulamaya izin veren subprojects yöntemini sağlar. Ancak, subprojects'te çok fazla yapılandırmanın yapılandırma aşamasını yavaşlattığını unutmayın. Convention Plugins kullanılması önerilir — bunlar bir kez derlenir ve yeniden kullanılır, yapılandırma süresini %15-30 oranında azaltır.
Sıkça Sorulan Sorular
Miktar sınırı yoktur, ancak her boyut Build Variants sayısını çarpar. Bir boyutta 4 flavor + 2 build type = 8 varyant. İki boyutta 4 + 4 = 16 varyant. 3'ten fazla boyut ve toplam 10-12'den fazla varyant kullanılmaması önerilir.
Evet, source set src/<flavor>/AndroidManifest.xml aracılığıyla. Bildirim, ana bildirimle birleşir. Tüm bloğu değiştirmek için tools:node="replace" kullanın. Örneğin, belirli bir flavor için uygulama etiketini veya izinleri değiştirin.
<flavorName>Implementation yapılandırmasını kullanın. Örnek: freeImplementation 'com.google.android.gms:play-services-ads:23.0.0'. Bu bağımlılık yalnızca ücretsiz varyant oluşturulurken dahil edilir. Ücretli için: paidImplementation. Ortak bağımlılıklar implementation aracılığıyla belirtilir.
Product Flavor ürün sürümünü (free, paid, demo) tanımlar, Build Type derleme yöntemini (debug, release) tanımlar. Flavor'lar applicationId, versionName, kaynakları geçersiz kılabilir. Build Type debuggable, minification, signing'i kontrol eder. Her ikisi de diktir ve Build Variant'ta birleşir.
Evet, Product Flavors kısıtlama olmaksızın Compose ile çalışır. Farklı flavor'lar, source set'ler veya soyut sınıf uygulamaları aracılığıyla farklı Compose ekranlarına sahip olabilir. Ayrıca flavor'a özgü Compose bağımlılıkları ekleyebilirsiniz: freeImplementation 'androidx.compose.ui:ui-tooling'.
Özet
Anahtar teslim bir mobil uygulama geliştireceğiz
IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.
Ayrıca okuyun