Το Build Variant στην ανάπτυξη Android είναι ένας συνδυασμός build type και product flavor που καθορίζει πώς θα κατασκευαστεί το APK ή AAB: με ποιες παραμέτρους, πόρους και κώδικα. Κάθε παραλλαγή μεταγλώττισης αποτελεί μια ξεχωριστή διαμόρφωση Gradle με δικό της applicationId, κλειδιά υπογραφής και συμπεριλαμβανόμενες εξαρτήσεις. Σύμφωνα με το Google Android Developers, 2025, η σωστή ρύθμιση των Build Variants μειώνει τον χρόνο μεταγλώττισης έως 40% αποκλείοντας περιττούς πόρους για κάθε παραλλαγή. Το σύστημα παραλλαγών μεταγλώττισης αποτελεί τη βάση της διαχείρισης διαμόρφωσης στα σύγχρονα έργα Android.
Κύρια σημεία
Build Variant — είναι το αποτέλεσμα του συνδυασμού ενός Build Type και ενός Product Flavor. Εάν δεν έχει οριστεί Product Flavor στο έργο, το Build Variant συμπίπτει με το Build Type. Το Gradle δημιουργεί αυτόματα το πλήρες σύνολο παραλλαγών ως καρτεσιανό γινόμενο όλων των FlavorDimensions, Product Flavors και Build Types. Για παράδειγμα, για flavor free/paid και τύπους debug/release, θα δημιουργηθούν 8 παραλλαγές: freeDebug, freeRelease, paidDebug, paidRelease.
Κάθε Build Variant λαμβάνει το δικό του όνομα σε μορφή <Flavor><Type> με flavor κεφαλαίο γράμμα. Για αυτήν την παραλλαγή, το Gradle δημιουργεί ξεχωριστές εργασίες: assembleFreeDebug, installFreeDebug, bundleFreeRelease. Στο Android Studio, η εναλλαγή μεταξύ παραλλαγών είναι διαθέσιμη μέσω του πίνακα Build Variants (View → Tool Windows → Build Variants). Η επιλογή παραλλαγής επηρεάζει ποιος κώδικας μεταγλωττίζεται, ποιοι πόροι συμπεριλαμβάνονται και ποιο APK/AAB δημιουργείται.
Το σύστημα Build Variants λύνει τρεις βασικές εργασίες: διαχωρισμό διαμορφώσεων για διαφορετικά περιβάλλοντα (dev/staging/production), δημιουργία πολλαπλών εκδόσεων της εφαρμογής (free/paid) και A/B δοκιμή μεταγλωττίσεων. Χωρίς Build Variants, οι προγραμματιστές θα έπρεπε να εναλλάσσουν χειροκίνητα σημαίες και διαμορφώσεις, οδηγώντας σε σφάλματα ανθρώπινου παράγοντα. Σύμφωνα με έρευνα της Gradle Inc., 2024, η εφαρμογή Build Variants μειώνει τον αριθμό σφαλμάτων μεταγλώττισης κατά 60% σε έργα με τρία ή περισσότερα περιβάλλοντα ανάπτυξης.
AGP (Android Gradle Plugin) υπολογίζει όλους τους συνδυασμούς στη φάση διαμόρφωσης. Εάν το έργο έχει δύο διαστάσεις με δύο και τρία flavor αντίστοιχα, το Gradle θα δημιουργήσει 2 × 2 × 3 = 12 συνδυασμούς, πολλαπλασιαζόμενους με τον αριθμό Build Types (συνήθως 2). Κάθε συνδυασμός λαμβάνει ένα μοναδικό όνομα και σύνολο εργασιών. Το AGP προσθέτει αυτόματα source set για κάθε παραλλαγή: src/freeDebug/, src/paidRelease/, καθώς και γενικευμένα src/free/ και src/debug/. Προτεραιότητα ανάγνωσης πόρων: variant → flavor → type → main.
// Παράδειγμα: 4 Build Variants
// flavorDimensions "version", "server"
// version: demo, prod
// server: mock, live
// buildTypes: debug, release
// Σύνολο: 2 × 2 × 2 = 8 παραλλαγές
android {
flavorDimensions "version", "server"
productFlavors {
demo { dimension "version" }
prod { dimension "version" }
mock { dimension "server" }
live { dimension "server" }
}
}
Build Type καθορίζει πώς μεταγλωττίζεται η εφαρμογή — με πληροφορίες αποσφαλμάτωσης ή χωρίς, με βελτιστοποίηση ή χωρίς, με ποια υπογραφή. Product Flavor καθορίζει τι μεταγλωττίζεται — ποια έκδοση του προϊόντος. Build Type — είναι ο μηχανισμός μεταγλώττισης (debug, release, staging). Product Flavor — είναι η παραλλαγή προϊόντος (free, paid, enterprise, demo). Και οι δύο έννοιες είναι ορθογώνιες: οποιοδήποτε Build Type μπορεί να εφαρμοστεί σε οποιοδήποτε Product Flavor.
Το Build Type από προεπιλογή περιλαμβάνει debug (debuggable=true, minification=false, signing=debug.keystore) και release (debuggable=false, minification=true, signing=production.keystore). Το Product Flavor από προεπιλογή είναι ένα, χωρίς όνομα (ουσιαστικά main source set). Ο προγραμματιστής μπορεί να προσθέσει δικά του Build Types (π.χ. “staging” με debuggable=true και minification=true) και Product Flavors σε οποιονδήποτε αριθμό. Η διαφορά έγκειται επίσης στο ότι το Build Type δεν μπορεί να ομαδοποιηθεί σε διαστάσεις, ενώ το Product Flavor μπορεί.
Η βασική πρακτική διαφορά: το defaultConfig στο build.gradle εφαρμόζεται σε όλα τα Variants, αλλά μπορεί να παρακαμφθεί στα productFlavors και buildTypes. Το BuildConfigField που προστίθεται στο buildType είναι ορατό σε όλα τα flavor αυτού του τύπου, ενώ αυτό που προστίθεται στο productFlavor — σε όλους τους τύπους αυτού του flavor. Εάν το πεδίο ορίζεται και εκεί και εκεί — προτεραιότητα έχει το buildType (εφαρμόζεται τελευταίο στην αλυσίδα).
| Χαρακτηριστικό | Build Type | Product Flavor |
|---|---|---|
| Σκοπός | Πώς να μεταγλωττίσετε | Τι να μεταγλωττίσετε |
| Παραδείγματα | debug, release, staging | free, paid, demo, enterprise |
| Προεπιλογή | debug + release | ένα (main) |
| Source Set | src/debug/, src/release/ | src/free/, src/paid/ |
| Διαστάσεις | όχι | flavorDimensions |
| Εφαρμογή | μετά το flavor, παρακάμπτει | μετά το defaultConfig |
| BuildConfigField | παρακάμπτει το flavor | παρακάμπτει το defaultConfig |
Η ρύθμιση Build Variants πραγματοποιείται στο μπλοκ android του αρχείου build.gradle σε επίπεδο αρθρώματος. Πρώτα δηλώνονται τα buildTypes με τις παραμέτρους τους, στη συνέχεια τα flavorDimensions και productFlavors. Το Gradle δημιουργεί αυτόματα παραλλαγές βάσει αυτών των δηλώσεων. Κάθε παραλλαγή κληρονομεί το defaultConfig του αρθρώματος, παρακάμπτοντας καθορισμένα πεδία. Η σειρά δήλωσης επηρεάζει την προτεραιότητα: τα buildTypes εφαρμόζονται μετά τα productFlavors.
Για πρόσβαση σε ένα συγκεκριμένο Build Variant σε σενάρια Gradle, χρησιμοποιείται το android.applicationVariants (για άρθρωμα app) ή android.libraryVariants (για άρθρωμα βιβλιοθήκης). Αυτή είναι μια συλλογή στην οποία μπορεί να γίνει επανάληψη και να τροποποιηθεί η διαμόρφωση κάθε παραλλαγής κατά τον χρόνο διαμόρφωσης. Για παράδειγμα, μπορεί να προστεθεί προγραμματικά buildConfigField για όλες τις παραλλαγές που περιέχουν τη λέξη “demo”.
Το Android Gradle Plugin 8.x πρόσθεσε υποστήριξη για onVariants — ένα καθαρότερο API για τη ρύθμιση παραλλαγών μέσω λάμδα. Το παλιό API (variantOutput, variantFilter) έχει επισημανθεί ως καταργημένο. Συνιστάται η χρήση onVariants μαζί με onEach για αρθρώματα βιβλιοθήκης. Η μετεγκατάσταση από variantOutput σε onVariants — συνιστώμενο βήμα κατά την ενημέρωση AGP από 7.x σε 8.x.
android {
buildTypes {
debug {
debuggable true
minification false
signingConfig signingConfigs.debug
}
release {
debuggable false
minification true
proguardFiles "proguard-rules.pro"
signingConfig signingConfigs.release
}
staging {
debuggable true
minification true
versionNameSuffix "-staging"
}
}
flavorDimensions "tier", "region"
productFlavors {
free { dimension "tier" }
paid { dimension "tier" }
us { dimension "region" }
eu { dimension "region" }
}
}
android.onVariants { variant ->
if (variant.name.contains("Demo")) {
variant.setEnabled(false)
}
}
Κάθε Build Variant λαμβάνει τη δική του ιεραρχία source sets — καταλόγων με πηγαίο κώδικα, πόρους και manifest. Το source set βρίσκεται στο src/<variantName>/ (π.χ. src/freeDebug/) και μπορεί να περιέχει java/, res/, AndroidManifest.xml, assets/. Εάν ένα αρχείο υπάρχει στο source set της παραλλαγής, παρακάμπτει το αρχείο με το ίδιο όνομα από το κύριο source set (src/main/). Για πόρους λειτουργεί η συγχώνευση, όχι η αντικατάσταση — το σύστημα συνδυάζει πόρους από όλα τα ενεργά source sets, δίνοντας προτεραιότητα σε αυτά που είναι ειδικά για την παραλλαγή.
Τα source sets για Build Variant χτίζονται σε αλυσίδα: src/main/ → src/flavor/ → src/type/ → src/flavorType/. Για παράδειγμα, για paidRelease εφαρμόζεται πρώτα το main, μετά το paid, μετά το release, μετά το paidRelease. Κάθε επόμενο source set παρακάμπτει το προηγούμενο. Αυτό σημαίνει ότι το src/release/res/values/strings.xml θα παρακάμψει τις ίδιες συμβολοσειρές από το src/paid/, αλλά το src/paid/release/res/ είναι ακόμα πιο προτεραιότητας.
Η χρήση source sets για παραλλαγές — ο συνιστώμενος τρόπος προσαρμογής πόρων. Αντί να ελέγχετε το BuildConfig.FLAVOR στον κώδικα και να διακλαδώνετε τη λογική, μπορείτε απλά να τοποθετείτε διαφορετικά αρχεία σε διαφορετικά source sets. Για παράδειγμα, τα εικονίδια για τις εκδόσεις free και paid τοποθετούνται αντίστοιχα σε src/free/res/ και src/paid/res/, και το AndroidManifest με διαφορετικές άδειες — σε src/free/AndroidManifest.xml και src/paid/AndroidManifest.xml. Αυτό είναι καθαρότερο, ταχύτερο (οι πόροι μεταγλωττίζονται, δεν ελέγχονται κατά τον χρόνο εκτέλεσης) και ασφαλέστερο (δεν μπορεί να ενεργοποιηθεί κατά λάθος η πληρωμένη λειτουργικότητα στη δωρεάν έκδοση λόγω σφάλματος στον κώδικα).
Σε πολυαρθρωτικά έργα, κάθε άρθρωμα (βιβλιοθήκη) μπορεί να έχει τα δικά του Build Variants. Το AGP συγχρονίζει αυτόματα τις παραλλαγές: εάν το άρθρωμα app μεταγλωττίζει paidRelease, όλες οι εξαρτώμενες βιβλιοθήκες μεταγλωττίζονται επίσης στις παραλλαγές τους που αντιστοιχούν στο paidRelease. Το πρόβλημα προκύπτει όταν η βιβλιοθήκη δεν έχει product flavors, αλλά το άρθρωμα app έχει — τότε η βιβλιοθήκη μεταγλωττίζεται μία φορά (release ή debug ανάλογα με τον τύπο).
Για αρθρώματα βιβλιοθήκης, το Build Variant από προεπιλογή συμπίπτει με το Build Type του αρθρώματος app, καθώς οι βιβλιοθήκες δεν έχουν product flavors. Εάν η βιβλιοθήκη πρέπει να προσαρμοστεί στο flavor του αρθρώματος app, πρέπει να δηλωθούν τα ίδια flavorDimensions και productFlavors στη βιβλιοθήκη. Το AGP ταιριάζει το flavor με βάση την πλήρη αντιστοιχία ονόματος. Το Gradle συνιστά τον συγχρονισμό flavor μέσω της διαμόρφωσης δόμησης στο ριζικό έργο με subprojects ή Convention Plugins.
Από το AGP 8.1, οι βιβλιοθήκες μπορούν να δημοσιεύουν multiple variants — να δημοσιεύουν όλες τις παραλλαγές της βιβλιοθήκης ταυτόχρονα σε αποθετήριο maven. Αυτό λύνει το πρόβλημα όταν το άρθρωμα app χρησιμοποιεί paid flavor, αλλά η βιβλιοθήκη έχει δημοσιευτεί μόνο για free. Το multiple variants publishing (MVP) επιτρέπει στο εξαρτώμενο έργο να επιλέξει αυτόματα την απαιτούμενη παραλλαγή. Για ενεργοποίηση MVP, πρέπει να προστεθεί publishing { multipleVariants { ... } } στο build.gradle της βιβλιοθήκης.
Μερικές φορές είναι απαραίτητο να απενεργοποιηθεί μέρος των Build Variants — για παράδειγμα, εάν ο συνδυασμός mockRelease δεν έχει νόημα (ο διακομιστής mock δεν πρέπει να φτάσει στην παραγωγή). Το Gradle παρέχει variantFilter — ένα μπλοκ DSL στο οποίο μπορούν να ελεγχθούν οι ιδιότητες κάθε παραλλαγής και να απενεργοποιηθεί μέσω setIgnore(true). Το VariantFilter εφαρμόζεται στη φάση διαμόρφωσης, πριν από τη δημιουργία εργασιών, επομένως η απενεργοποιημένη παραλλαγή δεν δημιουργεί εργασίες assemble και install.
Το φιλτράρισμα είναι επίσης χρήσιμο για την επιτάχυνση της μεταγλώττισης. Εάν το έργο έχει 8 παραλλαγές και ο προγραμματιστής εργάζεται μόνο σε μία, οι υπόλοιπες 7 παραλλαγές εξακολουθούν να περνούν από τη διαμόρφωση (configuration phase). Με τη χρήση variantFilter, οι απενεργοποιημένες παραλλαγές δεν δημιουργούν εργασίες, μειώνοντας τον χρόνο διαμόρφωσης κατά 30-50% για έργα με 6+ διαστάσεις flavor. Στο CI/CD, οι παραλλαγές μπορούν να φιλτραριστούν δυναμικά μέσω παραμέτρων γραμμής εντολών -PbuildOnly=paidRelease.
android {
variantFilter { variant ->
// Απενεργοποιούμε το mock για release και το demo για production
def names = variant.flavors*.name
def isMock = names.contains("mock")
def isDemo = names.contains("demo")
def isRelease = variant.buildType.name == "release"
if ((isMock && isRelease) || (isDemo && !isMock)) {
variant.setIgnore(true)
}
}
}
// Δυναμικό φιλτράρισμα μέσω παραμέτρων
if (project.hasProperty("buildOnly")) {
def target = project.property("buildOnly")
android.variantFilter { variant ->
variant.setIgnore(variant.name != target)
}
}
Συχνές ερωτήσεις
Δεν υπάρχουν περιορισμοί, αλλά το Gradle δημιουργεί το καρτεσιανό γινόμενο όλων των flavor και τύπων. Εάν έχετε 3 διαστάσεις με 3 flavor και 3 build type — θα λάβετε 27 παραλλαγές. Πάρα πολλές παραλλαγές επιβραδύνουν τη διαμόρφωση. Συνιστώνται όχι περισσότερες από 10-12 παραλλαγές σε ένα άρθρωμα.
Τα flavorDimensions ομαδοποιούν τα Product Flavors σε ανεξάρτητους άξονες. Για παράδειγμα, διάσταση “tier” (free, paid) και “region” (us, eu). Χωρίς διαστάσεις, όλα τα flavor ανήκουν σε έναν άξονα και το Gradle θα επιλέξει μόνο ένα flavor από όλα (δεν μπορείτε να έχετε free+us και paid+eu ως ξεχωριστές παραλλαγές).
Στο μπλοκ productFlavor ή buildType, καθορίστε το applicationId. Για παράδειγμα, για την έκδοση free: free { applicationId "com.example.app.free" }. Στο manifest, χρησιμοποιήστε ${applicationId} — το Gradle θα αντικαταστήσει αυτόματα την τιμή. Αυτό επιτρέπει την εγκατάσταση και των δύο παραλλαγών σε μία συσκευή.
Στο iOS, το αντίστοιχο των Build Variants είναι ο συνδυασμός Scheme + Configuration. Τα Xcode Schemes διαμορφώνονται μέσω διαμορφώσεων Debug/Release με διαφορετικές παραμέτρους. Για πολλαπλές εκδόσεις (free/paid) χρησιμοποιούνται Build Configurations και Preprocessor Macros. Στο Android, η ιδέα είναι πιο επίσημα τυποποιημένη και ενσωματωμένη στο Gradle.
Ναι, κάθε παραλλαγή μπορεί να έχει διαφορετικό μέγεθος APK. Οι μεταγλωττίσεις debug περιλαμβάνουν πληροφορίες αποσφαλμάτωσης, SDK και μη υποστηριζόμενους πόρους. Οι μεταγλωττίσεις release με σμίκρυνση και συρρίκνωση πόρων δίνουν ελάχιστο μέγεθος. Το Product Flavor επίσης επηρεάζει: η δωρεάν έκδοση χωρίς πληρωμένες βιβλιοθήκες θα είναι μικρότερη από την πληρωμένη έκδοση κατά το μέγεθος αυτών των βιβλιοθηκών.
Σύνοψη
Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση
Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.
Διαβάστε επίσης