Gradle बिल्ड की खास जानकारी

Gradle बिल्ड सिस्टम का इस्तेमाल करके, आम तौर पर Android ऐप्लिकेशन बनाए जाते हैं. बिल्ड को कॉन्फ़िगर करने के तरीके के बारे में ज़्यादा जानने से पहले, हम बिल्ड के पीछे के कॉन्सेप्ट के बारे में जानेंगे. इससे आपको पूरे सिस्टम को समझने में मदद मिलेगी.

बिल्ड क्या होता है?

बिल्ड सिस्टम, आपके सोर्स कोड को एक्ज़ीक्यूटेबल ऐप्लिकेशन में बदल देता है. बिल्ड में अक्सर कई टूल शामिल होते हैं. इनका इस्तेमाल आपके ऐप्लिकेशन या लाइब्रेरी का विश्लेषण करने, उसे कंपाइल करने, लिंक करने, और पैकेज करने के लिए किया जाता है. Gradle, इन निर्देशों को व्यवस्थित करने और चलाने के लिए, टास्क पर आधारित तरीका इस्तेमाल करता है.

टास्क में ऐसे निर्देश शामिल होते हैं जो इनपुट को आउटपुट में बदलते हैं. प्लग इन, टास्क और उनके कॉन्फ़िगरेशन तय करते हैं. अपने बिल्ड में प्लगिन लागू करने से, उसके टास्क रजिस्टर हो जाते हैं. साथ ही, इनपुट और आउटपुट का इस्तेमाल करके, उन्हें एक साथ जोड़ दिया जाता है. उदाहरण के लिए, अपनी बिल्ड फ़ाइल में Android Gradle प्लगिन (एजीपी) लागू करने से, APK या Android लाइब्रेरी बनाने के लिए ज़रूरी सभी टास्क रजिस्टर हो जाएंगे. java-library प्लग इन की मदद से, Java सोर्स कोड से jar फ़ाइल बनाई जा सकती है. Kotlin और अन्य भाषाओं के लिए भी इसी तरह के प्लग इन मौजूद हैं. हालांकि, अन्य प्लग इन का मकसद प्लग इन को बेहतर बनाना है. उदाहरण के लिए, protobuf प्लगिन का मकसद, एजीपी या java-library जैसे मौजूदा प्लगिन में protobuf की सुविधा जोड़ना है.

Gradle, कॉन्फ़िगरेशन के बजाय कन्वेंशन को प्राथमिकता देता है. इसलिए, प्लग इन में डिफ़ॉल्ट रूप से अच्छी वैल्यू पहले से मौजूद होंगी. हालांकि, डिक्लेरेटिव डोमेन-स्पेसिफ़िक लैंग्वेज (डीएसएल) का इस्तेमाल करके, बिल्ड को और कॉन्फ़िगर किया जा सकता है. डीएसएल को इस तरह डिज़ाइन किया गया है कि आप यह तय कर सकें कि आपको क्या बनाना है, न कि उसे कैसे बनाना है. प्लग इन में मौजूद लॉजिक, "कैसे" को मैनेज करता है. यह कॉन्फ़िगरेशन, आपके प्रोजेक्ट (और सब-प्रोजेक्ट) में मौजूद कई बिल्ड फ़ाइलों में बताया गया है.

टास्क के इनपुट, फ़ाइलें और डायरेक्ट्री हो सकते हैं. साथ ही, Java टाइप (इंटीजर, स्ट्रिंग या कस्टम क्लास) के तौर पर एन्कोड की गई अन्य जानकारी भी हो सकती है. आउटपुट सिर्फ़ डायरेक्ट्री या फ़ाइलें हो सकती हैं, क्योंकि उन्हें डिस्क पर लिखना होता है. एक टास्क के आउटपुट को दूसरे टास्क के इनपुट से जोड़ने पर, टास्क एक-दूसरे से लिंक हो जाते हैं. इससे एक टास्क को दूसरे टास्क से पहले चलाना पड़ता है.

Gradle, आपकी बिल्ड फ़ाइलों में आर्बिट्रेरी कोड और टास्क डिक्लेरेशन लिखने की सुविधा देता है. हालांकि, इससे टूल के लिए आपके बिल्ड को समझना और आपके लिए उसे मैनेज करना ज़्यादा मुश्किल हो सकता है. उदाहरण के लिए, प्लगिन में मौजूद कोड के लिए टेस्ट लिखे जा सकते हैं, लेकिन बिल्ड फ़ाइलों में नहीं. इसके बजाय, आपको बिल्ड लॉजिक और टास्क के एलान को प्लग इन तक सीमित रखना चाहिए. ये प्लग इन आपने या किसी और ने तय किए हों. साथ ही, आपको यह एलान करना चाहिए कि आपको अपनी बिल्ड फ़ाइलों में उस लॉजिक का इस्तेमाल कैसे करना है.

Gradle बिल्ड चलने पर क्या होता है?

Gradle बिल्ड तीन चरणों में चलते हैं. इनमें से हर फ़ेज़, कोड के अलग-अलग हिस्सों को एक्ज़ीक्यूट करता है. ये हिस्से, आपकी बिल्ड फ़ाइलों में तय किए जाते हैं.

  • शुरुआत से यह तय होता है कि बिल्ड में कौनसे प्रोजेक्ट और सब-प्रोजेक्ट शामिल हैं. साथ ही, इससे आपकी बिल्ड फ़ाइलों और लागू किए गए प्लग इन वाले क्लासपाथ सेट अप होते हैं. यह फ़ेज़, सेटिंग फ़ाइल पर फ़ोकस करता है. इसमें उन प्रोजेक्ट के बारे में बताया जाता है जिन्हें बिल्ड करना है. साथ ही, उन जगहों के बारे में बताया जाता है जहां से प्लग इन और लाइब्रेरी फ़ेच करनी हैं.
  • कॉन्फ़िगरेशन, हर प्रोजेक्ट के लिए टास्क रजिस्टर करता है. साथ ही, उपयोगकर्ता की बिल्ड स्पेसिफ़िकेशन लागू करने के लिए, बिल्ड फ़ाइल को एक्ज़ीक्यूट करता है. यह समझना ज़रूरी है कि आपके कॉन्फ़िगरेशन कोड के पास, एक्ज़ीक्यूशन के दौरान जनरेट किए गए डेटा या फ़ाइलों का ऐक्सेस नहीं होगा.
  • एक्ज़ीक्यूशन आपके ऐप्लिकेशन को असल में "बनाने" का काम करता है. कॉन्फ़िगरेशन का आउटपुट, टास्क का डायरेक्टेड असाइक्लिक ग्राफ़ (डीएजी) होता है. यह उपयोगकर्ता के अनुरोध किए गए सभी ज़रूरी बिल्ड चरणों को दिखाता है. ये चरण, कमांड लाइन पर दिए गए टास्क या बिल्ड फ़ाइलों में डिफ़ॉल्ट रूप से दिए गए टास्क होते हैं. यह ग्राफ़, टास्क के बीच के संबंध को दिखाता है. यह संबंध, टास्क के एलान में साफ़ तौर पर बताया गया होता है या उसके इनपुट और आउटपुट पर आधारित होता है. अगर किसी टास्क का इनपुट, किसी दूसरे टास्क का आउटपुट है, तो उसे दूसरे टास्क के बाद ही चलाया जाना चाहिए. यह फ़ेज़, पुराने टास्क को ग्राफ़ में तय किए गए क्रम में चलाता है. अगर पिछली बार टास्क चलाने के बाद से उसके इनपुट में कोई बदलाव नहीं हुआ है, तो 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 में इन्हें "मॉड्यूल" भी कहा जाता है) में मॉड्यूलर भी किया जा सकता है. इनका इस्तेमाल डिपेंडेंसी के तौर पर भी किया जा सकता है. हर सबप्रोजेक्ट से आउटपुट (जैसे, jar) जनरेट होते हैं. इनका इस्तेमाल सबप्रोजेक्ट या आपके टॉप-लेवल प्रोजेक्ट कर सकते हैं. इससे बिल्ड टाइम को बेहतर बनाया जा सकता है. इसके लिए, यह पता लगाया जाता है कि किन हिस्सों को फिर से बनाने की ज़रूरत है. साथ ही, ऐप्लिकेशन में ज़िम्मेदारियों को बेहतर तरीके से अलग किया जा सकता है.

हम बिल्ड डिपेंडेंसी जोड़ें में, डिपेंडेंसी तय करने के तरीके के बारे में ज़्यादा जानकारी देंगे.

बिल्ड के वैरिएंट

Android ऐप्लिकेशन बनाते समय, आम तौर पर आपको कई वैरिएंट बनाने होंगे. वैरिएंट में अलग-अलग कोड होते हैं या उन्हें अलग-अलग विकल्पों के साथ बनाया जाता है. साथ ही, वे बिल्ड टाइप और ऐप्लिकेशन टाइप से बने होते हैं.

बिल्ड टाइप के हिसाब से, बिल्ड के विकल्प अलग-अलग होते हैं. डिफ़ॉल्ट रूप से, एजीपी "रिलीज़" और "डीबग" बिल्ड टाइप सेट अप करता है. हालांकि, इनमें बदलाव किया जा सकता है और ज़्यादा बिल्ड टाइप जोड़े जा सकते हैं. जैसे, स्टेजिंग या इंटरनल टेस्टिंग के लिए.

डीबग के लिए बिल्ड, आपके ऐप्लिकेशन को छोटा या अस्पष्ट नहीं बनाता. इससे ऐप्लिकेशन को तेज़ी से बनाया जा सकता है और सभी सिंबल को पहले जैसा ही रखा जा सकता है. यह ऐप्लिकेशन को "डीबग करने लायक" के तौर पर भी मार्क करता है. साथ ही, इसे सामान्य डीबग कुंजी के साथ साइन करता है और डिवाइस पर इंस्टॉल की गई ऐप्लिकेशन फ़ाइलों को ऐक्सेस करने की अनुमति देता है. इससे ऐप्लिकेशन को चलाते समय, फ़ाइलों और डेटाबेस में सेव किए गए डेटा को एक्सप्लोर किया जा सकता है.

रिलीज़ के लिए तैयार बिल्ड, ऐप्लिकेशन को ऑप्टिमाइज़ करता है और रिलीज़ पासकोड से उस पर साइन करता है. साथ ही, इंस्टॉल की गई ऐप्लिकेशन फ़ाइलों को सुरक्षित रखता है.

ऐप्लिकेशन टाइप का इस्तेमाल करके, ऐप्लिकेशन के लिए शामिल किए गए सोर्स और डिपेंडेंसी वैरिएंट को बदला जा सकता है. उदाहरण के लिए, हो सकता है कि आपको अपने ऐप्लिकेशन के लिए "डेमो" और "फ़ुल" फ़्लेवर बनाने हों या फिर "मुफ़्त" और "पैसे चुकाकर" फ़्लेवर बनाने हों. "मुख्य" सोर्स सेट डायरेक्ट्री में अपना सामान्य सोर्स लिखें. इसके बाद, फ़्लेवर के नाम वाले सोर्स सेट में सोर्स को बदलें या जोड़ें.

एजीपी, बिल्ड टाइप और ऐप्लिकेशन टाइप के हर कॉम्बिनेशन के लिए वैरिएंट बनाता है. अगर आपने फ़्लेवर तय नहीं किए हैं, तो वैरिएंट के नाम बिल्ड टाइप के हिसाब से रखे जाते हैं. अगर दोनों को तय किया जाता है, तो वैरिएंट का नाम <flavor><Buildtype> रखा जाता है. उदाहरण के लिए, release और debug जैसे बिल्ड टाइप और demo और full जैसे फ़्लेवर के साथ, एजीपी ये वैरिएंट बनाएगा:

  • demoRelease
  • demoDebug
  • fullRelease
  • fullDebug

अगले चरण

अब आपने बिल्ड के कॉन्सेप्ट देख लिए हैं, तो अपने प्रोजेक्ट में Android बिल्ड स्ट्रक्चर पर एक नज़र डालें.