Android ऐप्लिकेशन आम तौर पर, Gradle बिल्ड सिस्टम का इस्तेमाल करके बनाए जाते हैं. हमारा सुझाव है कि कॉन्फ़िगरेशन की जानकारी देने से पहले, हम आपको बिल्ड के पीछे के सिद्धांतों के बारे में बताएं. इससे आपको सिस्टम को पूरी तरह से समझने में मदद मिलेगी.
बिल्ड क्या होता है?
बिल्ड सिस्टम, आपके सोर्स कोड को एक्ज़ीक्यूटेबल ऐप्लिकेशन में बदलता है. बिल्ड में अक्सर कई टूल शामिल होते हैं. इनका इस्तेमाल, आपके ऐप्लिकेशन या लाइब्रेरी का विश्लेषण करने, उसे कंपाइल करने, लिंक करने, और पैकेज करने के लिए किया जाता है. Gradle, इन कमांड को व्यवस्थित करने और चलाने के लिए, टास्क-आधारित अप्रोच का इस्तेमाल करता है.
टास्क में ऐसे निर्देश शामिल होते हैं जो इनपुट को आउटपुट में बदलते हैं. प्लगिन, टास्क और उनके कॉन्फ़िगरेशन तय करते हैं. किसी प्लगिन को अपनी बिल्ड प्रोसेस में शामिल करने पर, उसके टास्क रजिस्टर हो जाते हैं. साथ ही, उनके इनपुट और आउटपुट का इस्तेमाल करके उन्हें एक साथ जोड़ दिया जाता है. उदाहरण के लिए, अपनी बिल्ड फ़ाइल में Android Gradle प्लगिन (एजीपी) लागू करने से, APK या Android लाइब्रेरी बनाने के लिए ज़रूरी सभी टास्क रजिस्टर हो जाएंगे. java-library प्लगिन की मदद से, Java सोर्स कोड से जार बनाया जा सकता है. Kotlin और अन्य भाषाओं के लिए भी इसी तरह के प्लगिन उपलब्ध हैं. हालांकि, अन्य प्लगिन का इस्तेमाल प्लगिन को बढ़ाने के लिए किया जाता है. उदाहरण के लिए, protobuf प्लगिन को AGP या java-library जैसे मौजूदा प्लगिन में protobuf सपोर्ट जोड़ने के लिए बनाया गया है.
Gradle, कॉन्फ़िगरेशन के बजाय कन्वेंशन को प्राथमिकता देता है. इसलिए, प्लग इन में डिफ़ॉल्ट रूप से अच्छी वैल्यू शामिल होती हैं. हालांकि, डोमेन के हिसाब से तय की गई भाषा (डीएसएल) का इस्तेमाल करके, बिल्ड को और कॉन्फ़िगर किया जा सकता है. डीएसएल को इस तरह से डिज़ाइन किया गया है कि आपको यह बताने की ज़रूरत नहीं है कि इसे कैसे बनाना है. इसके बजाय, आपको यह बताना है कि क्या बनाना है. प्लगिन में मौजूद लॉजिक, "कैसे" को मैनेज करता है. यह कॉन्फ़िगरेशन, आपके प्रोजेक्ट (और सब-प्रोजेक्ट) में मौजूद कई बिल्ड फ़ाइलों में बताया गया है.
टास्क के इनपुट, फ़ाइलें और डायरेक्ट्री के साथ-साथ Java टाइप (पूर्णांक, स्ट्रिंग या कस्टम क्लास) के तौर पर एन्कोड की गई अन्य जानकारी भी हो सकते हैं. आउटपुट सिर्फ़ डायरेक्ट्री या फ़ाइलें हो सकती हैं, क्योंकि इन्हें डिस्क पर लिखा जाना होता है. किसी टास्क के आउटपुट को दूसरे टास्क के इनपुट में वायर करने से, दोनों टास्क एक-दूसरे से लिंक हो जाते हैं. इससे एक टास्क को दूसरे टास्क से पहले चलाना पड़ता है.
Gradle, आपकी बिल्ड फ़ाइलों में किसी भी कोड को लिखने और टास्क के बारे में बताने की सुविधा देता है. हालांकि, इससे टूल के लिए आपकी बिल्ड को समझना और आपके लिए उसे बनाए रखना मुश्किल हो सकता है. उदाहरण के लिए, प्लगिन में मौजूद कोड के लिए टेस्ट लिखे जा सकते हैं, लेकिन बिल्ड फ़ाइलों में नहीं. इसके बजाय, आपको बिल्ड लॉजिक और टास्क के एलान को प्लगिन तक सीमित रखना चाहिए. ये प्लगिन, आपने या किसी और ने तय किए हों. साथ ही, आपको यह एलान करना चाहिए कि आपको अपनी बिल्ड फ़ाइलों में उस लॉजिक का इस्तेमाल कैसे करना है.
Gradle बिल्ड के चलने पर क्या होता है?
Gradle बिल्ड तीन चरणों में चलते हैं. इनमें से हर फ़ेज़, कोड के अलग-अलग हिस्सों को एक्ज़ीक्यूट करता है. ये हिस्से, आपकी बिल्ड फ़ाइलों में तय किए जाते हैं.
- Initialization से यह तय होता है कि बिल्ड में कौनसे प्रोजेक्ट और सबप्रोजेक्ट शामिल किए जाएंगे. साथ ही, यह उन क्लासपाथ को सेट अप करता है जिनमें आपकी बिल्ड फ़ाइलें और लागू किए गए प्लगिन शामिल होते हैं. इस फ़ेज़ में, सेटिंग फ़ाइल पर फ़ोकस किया जाता है. इसमें, आपको उन प्रोजेक्ट के बारे में बताना होता है जिन्हें बनाना है. साथ ही, उन जगहों के बारे में बताना होता है जहां से प्लगिन और लाइब्रेरी फ़ेच करनी हैं.
- कॉन्फ़िगरेशन, हर प्रोजेक्ट के लिए टास्क रजिस्टर करता है. साथ ही, उपयोगकर्ता की बिल्ड स्पेसिफ़िकेशन लागू करने के लिए, बिल्ड फ़ाइल को एक्ज़ीक्यूट करता है. यह समझना ज़रूरी है कि आपके कॉन्फ़िगरेशन कोड के पास, एक्ज़ीक्यूशन के दौरान जनरेट हुए डेटा या फ़ाइलों का ऐक्सेस नहीं होगा.
- एक्ज़ीक्यूशन, आपके ऐप्लिकेशन को "बनाने" का काम करता है. कॉन्फ़िगरेशन का आउटपुट, टास्क का डायरेक्टेड एसाइक्लिक ग्राफ़ (डीएजी) होता है. यह ग्राफ़, सभी ज़रूरी बिल्ड चरणों को दिखाता है. ये चरण, उपयोगकर्ता ने अनुरोध किए थे. जैसे, कमांड लाइन पर दिए गए टास्क या बिल्ड फ़ाइलों में डिफ़ॉल्ट के तौर पर दिए गए टास्क. यह ग्राफ़, टास्क के बीच के संबंध को दिखाता है. यह संबंध, टास्क के एलान में साफ़ तौर पर बताया गया होता है या इसके इनपुट और आउटपुट पर आधारित होता है. अगर किसी टास्क का इनपुट, किसी दूसरे टास्क का आउटपुट है, तो उसे दूसरे टास्क के बाद चलना चाहिए. यह फ़ेज़, ग्राफ़ में तय किए गए क्रम में पुराने टास्क चलाता है. अगर किसी टास्क के इनपुट में आखिरी बार बदलाव के बाद से कोई बदलाव नहीं हुआ है, तो Gradle उसे छोड़ देगा.
ज़्यादा जानकारी के लिए, Gradle का बिल्ड लाइफ़साइकल देखें.
कॉन्फ़िगरेशन डीएसएल
Gradle, बिल्ड को कॉन्फ़िगर करने के लिए डोमेन-स्पेसिफ़िक लैंग्वेज (डीएसएल) का इस्तेमाल करता है. डिक्लेरेटिव अप्रोच में, सिलसिलेवार (अनिवार्य) निर्देश लिखने के बजाय, अपने डेटा के बारे में जानकारी देने पर फ़ोकस किया जाता है. Kotlin या Groovy का इस्तेमाल करके, अपनी बिल्ड फ़ाइलें लिखी जा सकती हैं. हालांकि, हमारा सुझाव है कि Kotlin का इस्तेमाल करें.
डीएसएल, डोमेन के विशेषज्ञों और प्रोग्रामर, दोनों के लिए किसी प्रोजेक्ट में योगदान देना आसान बनाते हैं. इसके लिए, वे एक छोटी भाषा तय करते हैं, जो डेटा को ज़्यादा नैचुरल तरीके से दिखाती है. Gradle प्लगिन, डीएसएल को बढ़ा सकते हैं, ताकि वे अपने टास्क के लिए ज़रूरी डेटा को कॉन्फ़िगर कर सकें.
उदाहरण के लिए, अपने बिल्ड के Android हिस्से को कॉन्फ़िगर करने का तरीका कुछ ऐसा दिख सकता है:
Kotlin
android { namespace = "com.example.app" compileSdk { version = release(36) { minorApiLevel = 1 } } // ... defaultConfig { applicationId = "com.example.app" minSdk { version = release(23) } targetSdk { version = release(36) } // ... } }
Groovy
android { namespace = 'com.example.app' compileSdk { version = release(36) { minorApiLevel = 1 } } // ... defaultConfig { applicationId = 'com.example.app' minSdk { version = release(23) } targetSdk { version = release(36) } // ... } }
पर्दे के पीछे, डीएसएल कोड इस तरह दिखता है:
fun Project.android(configure: ApplicationExtension.() -> Unit) {
...
}
interface ApplicationExtension {
var namespace: String?
fun compileSdk(configure: CompileSdkSpec.() -> Unit) {
...
}
val defaultConfig: DefaultConfig
fun defaultConfig(configure: DefaultConfig.() -> Unit) {
...
}
}
डीएसएल में हर ब्लॉक को एक फ़ंक्शन के तौर पर दिखाया जाता है. इसे कॉन्फ़िगर करने के लिए, यह एक लैम्डा लेता है. साथ ही, इसे ऐक्सेस करने के लिए, इसी नाम की एक प्रॉपर्टी लेता है. इससे आपकी बिल्ड फ़ाइलों में मौजूद कोड, डेटा स्पेसिफ़िकेशन की तरह लगता है.
बाहरी डिपेंडेंसी
Maven बिल्ड सिस्टम ने डिपेंडेंसी स्पेसिफ़िकेशन, स्टोरेज, और मैनेजमेंट सिस्टम पेश किया. लाइब्रेरी को रिपॉज़िटरी (सर्वर या डायरेक्ट्री) में सेव किया जाता है. इनमें मेटाडेटा भी शामिल होता है. जैसे, लाइब्रेरी का वर्शन और अन्य लाइब्रेरी पर निर्भरता. आपको यह तय करना होता है कि किन रिपॉज़िटरी में खोजना है और आपको निर्भरता के किन वर्शन का इस्तेमाल करना है. इसके बाद, बिल्ड सिस्टम उन्हें बिल्ड के दौरान डाउनलोड करता है.
Maven आर्टफ़ैक्ट की पहचान, ग्रुप के नाम (कंपनी, डेवलपर वगैरह), आर्टफ़ैक्ट के नाम (लाइब्रेरी का नाम) और उस आर्टफ़ैक्ट के वर्शन से की जाती है. इसे आम तौर पर group:artifact:version के तौर पर दिखाया जाता है.
इस तरीके से, बिल्ड मैनेजमेंट को काफ़ी हद तक बेहतर बनाया जा सकता है. आपको अक्सर ऐसी रिपॉज़िटरी को "Maven रिपॉज़िटरी" कहते हुए सुना होगा. हालांकि, यह सब इस बात पर निर्भर करता है कि आर्टफ़ैक्ट को कैसे पैकेज किया जाता है और पब्लिश किया जाता है. इन रिपॉज़िटरी और मेटाडेटा का इस्तेमाल, Gradle जैसे कई बिल्ड सिस्टम में किया गया है. साथ ही, Gradle इन रिपॉज़िटरी में पब्लिश कर सकता है. सार्वजनिक रिपॉज़िटरी को सभी के साथ शेयर किया जा सकता है, ताकि सभी लोग उसका इस्तेमाल कर सकें. वहीं, कंपनी की रिपॉज़िटरी में इंटरनल डिपेंडेंसी को कंपनी के अंदर ही रखा जाता है.
अपने प्रोजेक्ट को सबप्रोजेक्ट में मॉड्यूलर बनाया जा सकता है. इन्हें Android Studio में "मॉड्यूल" भी कहा जाता है. इनका इस्तेमाल डिपेंडेंसी के तौर पर भी किया जा सकता है. हर सबप्रोजेक्ट, आउटपुट (जैसे कि जार) जनरेट करता है. इनका इस्तेमाल सबप्रोजेक्ट या टॉप-लेवल प्रोजेक्ट कर सकते हैं. इससे यह पता चलता है कि किन हिस्सों को फिर से बनाना है. इससे बिल्ड टाइम को बेहतर बनाया जा सकता है. साथ ही, ऐप्लिकेशन में ज़िम्मेदारियों को बेहतर तरीके से अलग किया जा सकता है.
हम बिल्ड डिपेंडेंसी जोड़ें में, डिपेंडेंसी तय करने के तरीके के बारे में ज़्यादा जानकारी देंगे.
बिल्ड के वैरिएंट
Android ऐप्लिकेशन बनाते समय, आम तौर पर आपको कई वैरिएंट बनाने होते हैं. वैरिएंट में अलग-अलग कोड होते हैं या उन्हें अलग-अलग विकल्पों के साथ बनाया जाता है. साथ ही, ये बिल्ड टाइप और प्रॉडक्ट फ़्लेवर से मिलकर बने होते हैं.
बिल्ड टाइप, बताए गए बिल्ड विकल्पों से अलग-अलग होते हैं. डिफ़ॉल्ट रूप से, AGP "release" और "debug" बिल्ड टाइप सेट अप करता है. हालांकि, इन्हें बदला जा सकता है और ज़्यादा बिल्ड टाइप जोड़े जा सकते हैं. जैसे, स्टेजिंग या इंटरनल टेस्टिंग के लिए.
डीबग बिल्ड, आपके ऐप्लिकेशन को छोटा या अस्पष्ट नहीं करता है. इससे ऐप्लिकेशन को तेज़ी से बनाया जा सकता है और सभी सिंबल को पहले जैसा रखा जा सकता है. यह ऐप्लिकेशन को "डीबग किया जा सकता है" के तौर पर भी मार्क करता है. साथ ही, इसे सामान्य डीबग कुंजी से साइन करता है और डिवाइस पर इंस्टॉल किए गए ऐप्लिकेशन की फ़ाइलों को ऐक्सेस करने की सुविधा चालू करता है. इससे ऐप्लिकेशन चलाते समय, फ़ाइलों और डेटाबेस में सेव किए गए डेटा को एक्सप्लोर किया जा सकता है.
रिलीज़ बिल्ड, ऐप्लिकेशन को ऑप्टिमाइज़ करता है. साथ ही, उसे आपके रिलीज़ पासकोड से साइन करता है. इसके अलावा, यह इंस्टॉल किए गए ऐप्लिकेशन की फ़ाइलों को सुरक्षित रखता है.
प्रॉडक्ट फ़्लेवर का इस्तेमाल करके, ऐप्लिकेशन के लिए शामिल किए गए सोर्स और डिपेंडेंसी वैरिएंट बदले जा सकते हैं. उदाहरण के लिए, हो सकता है कि आपको अपने ऐप्लिकेशन के लिए "डेमो" और "फ़ुल" वर्शन बनाने हों या "मुफ़्त" और "पैसे चुकाकर इस्तेमाल किया जाने वाला" वर्शन बनाना हो. अपने सामान्य सोर्स को "main" source set डायरेक्ट्री में लिखें. इसके बाद, फ़्लेवर के नाम वाले सोर्स सेट में सोर्स को बदलें या जोड़ें.
AGP, बिल्ड टाइप और प्रॉडक्ट फ़्लेवर के हर कॉम्बिनेशन के लिए वैरिएंट बनाता है. अगर फ़्लेवर तय नहीं किए जाते हैं, तो वैरिएंट के नाम, बिल्ड टाइप के हिसाब से रखे जाते हैं. अगर आपने दोनों को तय किया है, तो वैरिएंट का नाम <flavor><Buildtype> होगा. उदाहरण के लिए, बिल्ड टाइप release और debug, और फ़्लेवर demo और full के साथ, AGP ये वैरिएंट बनाएगा:
demoReleasedemoDebugfullReleasefullDebug
अगले चरण
अब जब आपने बिल्ड के कॉन्सेप्ट देख लिए हैं, तो अपने प्रोजेक्ट में Android बिल्ड स्ट्रक्चर देखें.