इस लेख में, हम Android में मल्टी-लाइब्रेरी प्रोजेक्ट्स के बारे में बात करने जा रहे हैं। यह कुछ असाधारण नहीं है, लेकिन कुछ असामान्य भी नहीं है।
आप अपने काम की लाइन में मल्टी-लाइब्रेरी प्रोजेक्ट्स का सामना कर सकते हैं, या आप बेहतर संरचना और संगठन के लिए अपनी लाइब्रेरी को सब-मॉड्यूल में बदलने की तलाश में हो सकते हैं। चाहे जो भी मामला हो, आपको गोता लगाने से पहले अपने सामने क्या है, इसके बारे में अच्छी तरह से पता होना चाहिए।
Android में अपनी खुद की लाइब्रेरी लिखना साफ-सुथरा है। आपको कुछ कोड लिखने का मौका मिलता है जो अन्य डेवलपर्स (या यहां तक कि स्वयं) की मदद कर सकता है।
चूंकि लाइब्रेरी अपने आप में एक स्टैंडअलोन प्रोजेक्ट नहीं हो सकतीं, वे आमतौर पर हमेशा एक एप्लिकेशन के साथ एक प्रोजेक्ट में जोड़ी जाती हैं। यह लाइब्रेरी विकसित करने को एक सरल प्रक्रिया बनाने की अनुमति देता है जहां आप एक फीचर जोड़ते हैं/एक बग ठीक करते हैं और फिर आप इसे सीधे उस एप्लिकेशन के साथ टेस्ट कर सकते हैं जो आपके पास प्रोजेक्ट में है। इस प्रकार, अनुकरण करते हुए (स्थानीय तरीके से) एक डेवलपर आपकी लाइब्रेरी को कैसे एकीकृत करेगा।
लेकिन, क्या होगा यदि आपकी लाइब्रेरी आपके द्वारा विकसित की जा रही किसी अन्य लाइब्रेरी पर निर्भर करती है?
यदि आप इससे अवगत नहीं हैं, तो आपको पता होना चाहिए कि एक लाइब्रेरी (aar पढ़ें) अपने भीतर दूसरी स्थानीय लाइब्रेरी को समाहित नहीं कर सकती। यह दूरस्थ रूप से लाइब्रेरी पर निर्भर कर सकती है (डिपेंडेंसी के माध्यम से), लेकिन किसी स्थानीय चीज़ पर नहीं।
यह Android में समर्थित नहीं है, और जबकि वर्षों में कुछ समाधान सामने आए (FatAar), ये हमेशा समस्या का समाधान नहीं करते और अद्यतन नहीं हैं। यहां तक कि एक Google Issue Tracker भी है जो इस सुविधा का अनुरोध करता है जो काफी समय से खुला है और समुदाय से बहुत ध्यान आकर्षित कर रहा है। लेकिन आइए पहचानें कि हम कौन सी दीवारें तोड़ सकते हैं और कौन सी नहीं।
कल्पना करें कि आपकी प्रोजेक्ट पदानुक्रम इस तरह दिखती है:
-- App | -- OuterLib | --- InnerLib तो, चूंकि InnerLib आपके मूल प्रोजेक्ट का हिस्सा नहीं हो सकती, यह कहाँ रह सकती है? और आप स्थानीय रूप से काम करते हुए InnerLib के अंदर सुविधाओं को विकसित करने में कैसे सक्षम होंगे?
हम इन सवालों का जवाब इस लेख में देंगे।
Git Submodule
अधिकांश तकनीकी समस्याओं के लिए, हमेशा केवल एक समाधान नहीं होता है। आमतौर पर, अधिक होते हैं, लेकिन प्रत्येक समाधान की अपनी कमियां होती हैं। यह सब इस सवाल का है कि दिन के अंत में आप किन कमियों के साथ रहने में अधिक सहज हैं।
हमारे पहले सवाल का जवाब देने के लिए, InnerLib कहाँ रह सकती है, हमारे पास कई विकल्प हैं:
- InnerLib को हमारे मूल प्रोजेक्ट का सबमॉड्यूल बनाएं
- InnerLib को अपना रिमोट डिपेंडेंसी बनाएं
यदि आप Git में सबमॉड्यूल से अवगत नहीं हैं, तो Git का दस्तावेज़ीकरण उनसे परिचित होने के लिए एक अच्छी जगह है। इससे उद्धृत (पहला पैराग्राफ):
अक्सर ऐसा होता है कि एक प्रोजेक्ट पर काम करते समय, आपको इसके भीतर से दूसरे प्रोजेक्ट का उपयोग करने की आवश्यकता होती है। 👉 शायद यह एक लाइब्रेरी है जिसे किसी तीसरे पक्ष ने विकसित किया है या जिसे आप अलग से विकसित कर रहे हैं और कई पैरेंट प्रोजेक्ट में उपयोग कर रहे हैं। 👈 इन परिदृश्यों में एक आम समस्या उत्पन्न होती है: आप दोनों प्रोजेक्ट को अलग मानना चाहते हैं फिर भी एक का उपयोग दूसरे के भीतर से करने में सक्षम होना चाहते हैं।
यह पैराग्राफ हमें दिखाता है कि यह ठीक हमारा उपयोग का मामला है। सबमॉड्यूल का उपयोग करने के इसके लाभ हैं। आपका सारा कोड एक ही स्थान पर है, प्रबंधन करना आसान है, और स्थानीय रूप से विकसित करना आसान है।
लेकिन सबमॉड्यूल की कुछ कमजोरियां हैं। एक यह तथ्य है कि आपको हमेशा पता होना चाहिए कि आपका सबमॉड्यूल किस शाखा की ओर इशारा कर रहा है। एक परिदृश्य की कल्पना करें जहां आप अपने मुख्य रिपॉजिटरी में एक रिलीज शाखा पर हैं और आपका सब-मॉड्यूल एक फीचर शाखा पर है। यदि आप नोटिस नहीं करते हैं, तो आप अपने कोड का एक संस्करण किसी ऐसी चीज़ के साथ जारी करते हैं जो प्रोडक्शन के लिए तैयार नहीं है। वूप्स।
अब एक डेवलपर्स की टीम के भीतर इसके बारे में सोचें। एक लापरवाह गलती महंगी हो सकती है।
यदि पहला विकल्प आपके लिए समस्याग्रस्त लगता है, तो अपनी लाइब्रेरी को दूसरे रिपॉजिटरी में होस्ट करना आपका दूसरा विकल्प है। रिपॉजिटरी सेट करना काफी सरल है, लेकिन अब आप स्थानीय रूप से कैसे काम करते हैं?
स्थानीय रूप से काम करना
अब जब हमने अपना प्रोजेक्ट ठीक से सेट कर लिया है, तो हमारे पास शायद हमारे OuterLib build.gradle फाइल में इस तरह की एक लाइन होगी:
dependencies { implementation 'url_to_remote_inner_lib_repository' } हम डेवलपमेंट चक्र को कुशल और काम करने में आसान कैसे बना सकते हैं? यदि हम InnerLib में कुछ फीचर विकसित करते हैं, तो हम OuterLib में चीजों को कैसे टेस्ट करते हैं? या हमारे एप्लिकेशन में?
एक समाधान जो सामने आ सकता है वह है हमारे InnerLib को स्थानीय रूप से हमारे OuterLib प्रोजेक्ट में आयात करना, जबकि OuterLib प्रोजेक्ट में InnerLib को .gitignored रखा जाता है। आप Android Studio में बाएं हाथ के साइड मेनू में प्रोजेक्ट के नाम पर राइट क्लिक करके और New → Module पर जाकर आसानी से ऐसा कर सकते हैं।
मॉड्यूल कैसे आयात करें (चरण 1)
फिर खुलने वाली विंडो में, आप नीचे बाएं कोने पर Import विकल्प चुन सकते हैं:
मॉड्यूल कैसे आयात करें (चरण 2)
यह अब तक आसान और सरल लगता है, लेकिन पकड़ क्या है?
हर बार जब आप InnerLib से संबंधित एक फाइल को संशोधित करते हैं, तो परिवर्तन InnerLib के अंदर प्रतिबिंबित नहीं होंगे क्योंकि इसे अनदेखा किया गया है। इसलिए, आपके द्वारा किए जाने वाले प्रत्येक परिवर्तन को InnerLib के अंदर होना चाहिए और फिर आपको OuterLib के अंदर इसे फिर से आयात करना होगा ताकि परिवर्तन दिखाई दें।
यह सही नहीं लगता। ऐसा करने का एक बेहतर तरीका होना चाहिए।
हमारे settings.gradle फाइल में बस कुछ लाइनों के साथ, हम यह सुनिश्चित कर सकते हैं कि जब हम InnerLib में परिवर्तन करते हैं तो हमारी फाइलें सिंक में रहें।
जब हमने InnerLib को अपने प्रोजेक्ट में आयात किया, तो Android Studio ने InnerLib की एक प्रति बनाई और इसे कैश किया। यही कारण है कि हमें InnerLib के अंदर किए गए हर बदलाव के लिए लाइब्रेरी को फिर से आयात करने की आवश्यकता थी। हम projectDir विशेषता का उपयोग करके Android Studio को बता सकते हैं कि फाइलों को कहां से संदर्भित करना है।
हमारा settings.gradle कुछ इस तरह दिख सकता है:
include ':outerLib', ':innerLib', ':app' अपने InnerLib को स्थानीय रूप से संदर्भित करने के लिए, हमें settings.gradle को इसमें बदलना होगा:
include ':outerLib', ':innerLib', ':app' project('innerLib').projectDir = new File('PATH_TO_INNER_LIB') इस दृष्टिकोण का उपयोग करके, हमारी InnerLib फाइलें हमारे कार्य निर्देशिका से जुड़ी होंगी, इसलिए हमारे द्वारा किया गया हर परिवर्तन तुरंत प्रतिबिंबित होगा।
लेकिन, हम OuterLib पर रिमोट संस्करण के साथ स्थानीय रूप से काम करते समय लचीलापन चाहेंगे। हमने ऊपर settings.gradle फाइल के अंदर जो लिखा है वह केवल हमें स्थानीय रूप से काम करने की अनुमति देगा और निश्चित रूप से हम उसे वैसे ही कमिट नहीं करना चाहते।
Maven Local
यदि ऊपर का दृष्टिकोण आपके साथ बिल्कुल सही नहीं बैठता है, तो एक अलग दृष्टिकोण है जिसे आप अपना सकते हैं। जैसे आप मेवेन के साथ अपनी लाइब्रेरी को सार्वजनिक रूप से प्रकाशित करेंगे, आप मेवेन लोकल के साथ स्थानीय रूप से भी वही काम कर सकते हैं। मेवेन लोकल रिपॉजिटरी का एक सेट है जो आपकी मशीन पर स्थानीय रूप से बैठता है।
नीचे आपके मशीन के ऑपरेटिंग सिस्टम के आधार पर mavenLocal के लिए पथ हैं:
- Mac → /Users/YOUR_USERNAME/.m2
- Linux → /home/YOUR_USERNAME/.m2
- Windows → C:\Users\YOUR_USERNAME.m2
संक्षेप में आप अपनी लाइब्रेरी को स्थानीय रूप से प्रकाशित कर सकते हैं और फिर इसे अपने प्रोजेक्ट में लिंक कर सकते हैं। इसे इस तरह करके, हम अपने प्रोजेक्ट को InnerLib से लिंक कर सकते हैं।
अपने प्रोजेक्ट में इस कॉन्फ़िगरेशन की अनुमति देने के लिए, हमें निम्नलिखित चीजें करने की आवश्यकता है:
- mavenLocal() को हमारे रिपॉजिटरी क्लॉज के अंदर रिपॉजिटरी के रूप में जोड़ें। यह हमारे प्रोजेक्ट को स्थानीय रूप से रिपॉजिटरी खोजने की क्षमता देने के लिए है
buildscript { repositories { mavenLocal() } } ... allprojects { repositories { mavenLocal() } } हमारे डिपेंडेंसी क्लॉज के अंदर हमारी कार्यान्वयन लाइन को बदलें ताकि हमारे InnerLib को संदर्भित किया जा सके जैसे कि हम इसे दूरस्थ रूप से संदर्भित कर रहे हैं
InnerLib को स्थानीय रूप से प्रकाशित करने के लिए, हम publishingLocally.gradle नामक एक फाइल बनाएंगे जिसमें निम्नलिखित होगा:
apply plugin: 'maven-publish' project.afterEvaluate { publishing { publications { library(MavenPublication) { setGroupId groupId //your library package setArtifactId artifactId version versionName //I.E. 1.0 artifact bundleDebugAar pom.withXml { def dependenciesNode = asNode().appendNode('dependencies') def dependencyNode = dependenciesNode.appendNode('dependency') dependencyNode.appendNode('groupId', 'your_group_id') dependencyNode.appendNode('artifactId', 'your_artificat_id') dependencyNode.appendNode('version', 'your_version') } } } } } - अपने एप्लिकेशन लेवल build.gradle फाइल के अंदर, लाइन जोड़ें:
apply from: '/.publishingLocally.gradle यदि यह विकल्प थोड़ा बहुत अच्छा लगता है, यह है। जबकि एक तरफ, हम चीजों को स्थानीय रूप से मूल रूप से विकसित कर सकते हैं जैसे कि हम एक रिमोट लाइब्रेरी के साथ काम कर रहे थे। दूसरी तरफ, यदि हम स्थानीय रूप से काम करते समय InnerLib के अंदर कोई बदलाव करते हैं, तो इसे फिर से स्थानीय रूप से प्रकाशित करना आवश्यक है। हालांकि यह एक महंगा कार्य नहीं है, यह बार-बार थकाऊ कार्य करने की आवश्यकता पैदा करता है।
स्थानीय और रिमोट रूप से काम करने का एक समाधान
हम हर बार जब हम स्थानीय रूप से कोई बदलाव करते हैं तो अपने InnerLib पैकेज को पुनः प्रकाशित करने की निरंतर आवश्यकता से बचना चाहते हैं। हमें यह पता लगाने की आवश्यकता है कि हमारे प्रोजेक्ट को उन परिवर्तनों से अवगत कैसे कराया जाए।
स्थानीय रूप से काम करने वाले अनुभाग में, हमने पता लगाया कि इसे कैसे करना है, लेकिन हमें settings.gradle फाइल को कमिट करने में समस्या थी। इस समस्या को हल करने के लिए ताकि हम अपने InnerLib के साथ स्थानीय और रिमोट दोनों तरह से काम कर सकें, हम एक पैरामीटर का उपयोग करेंगे जिसे हम अपने gradle.properties फाइल में परिभाषित करेंगे।
gradle.properties फाइल एक ऐसी जगह है जहां आप प्रोजेक्ट लेवल सेटिंग्स स्टोर कर सकते हैं जो आपके डेवलपमेंट एनवायरनमेंट को कॉन्फ़िगर करती हैं। यह सुनिश्चित करने में मदद करता है कि एक टीम के सभी डेवलपर्स के पास एक सुसंगत डेवलपमेंट एनवायरनमेंट है।
कुछ सेटिंग्स जिनसे आप परिचित हो सकते हैं जो इस फाइल के अंदर पाई जाती हैं, वे हैं AndroidX सपोर्ट (android.useAndroidX=true) या JVM आर्ग्यूमेंट्स (org.gradle.jvmargs=-Xmx1536m)।
हमारी स्थिति को हल करने में हमारी मदद करने के लिए, हम यहां एक पैरामीटर जोड़ सकते हैं जो इंगित करता है कि हम स्थानीय रूप से काम करना चाहते हैं या नहीं। कुछ इस तरह:
workingLocally = false
यह पैरामीटर हमें यह अंतर करने की क्षमता प्रदान करेगा कि हम किन सेटिंग्स के साथ काम कर रहे हैं, या तो स्थानीय रूप से या प्रोडक्शन कोड के साथ। पहले, आइए हम अपने settings.gradle फाइल में जो है उसे एक शर्त में लपेटकर बदलें जो जांचती है कि हमारा पैरामीटर सही है:
include ':outerLib', ':innerLib', ':app' if (workingLocally.booleanValue()) { project('innerLib').projectDir = new File('PATH_TO_INNER_LIB') }
इस तरह, हम प्रोजेक्ट को हमारी मशीन से स्थानीय रूप से हमारे InnerLib की फाइलें प्राप्त करने के लिए इंगित करते हैं।
एक और जगह जहां हमें अपना लॉजिक बदलने की आवश्यकता है वह है हमारी build.gradle फाइल। यहां, अपने डिपेंडेंसी ब्लॉक में लाइब्रेरी के लिए कोड को दूरस्थ रूप से प्राप्त करने के बजाय, हम इंगित कर सकते हैं कि हम इस पर स्थानीय रूप से निर्भर कर रहे हैं या नहीं।
dependencies { if (workingLocally.booleanValue()) { implementation 'innerLib' } else { implementation 'url_to_remote_repository' } }
⚠️ चेतावनी: जब आप स्थानीय रूप से काम कर रहे हों तो आपको कभी भी gradle.properties फाइल को कमिट नहीं करना चाहिए।
यात्रा लंबी थी और काफी थकाऊ लग सकती है। लेकिन अब हमारे पास मल्टीपल लाइब्रेरी प्रोजेक्ट पर स्थानीय और रिमोट रूप से काम करने के लिए एक फुल-प्रूफ सेटअप है।
यदि आपको कोई समस्या आती है या आप इस पर अपना विचार देना चाहते हैं, तो बेझिझक एक टिप्पणी छोड़ दें।
मुफ्त में कोड करना सीखें। freeCodeCamp का ओपन सोर्स पाठ्यक्रम 40,000 से अधिक लोगों को डेवलपर्स के रूप में नौकरी पाने में मदद कर चुका है। शुरू करें