Android के लिए, तेज़ी से इटरेटिव डेवलपमेंट
इस पेज पर, यह बताया गया है कि bazel mobile-install की मदद से, Android के लिए इटरेटिव डेवलपमेंट को ज़्यादा तेज़ी से कैसे किया जा सकता है. इसमें, ऐप्लिकेशन इंस्टॉल करने के पारंपरिक तरीके की चुनौतियों के मुकाबले, इस तरीके के फ़ायदों के बारे में बताया गया है.
खास जानकारी
Android ऐप्लिकेशन में छोटे-छोटे बदलावों को बहुत तेज़ी से इंस्टॉल करने के लिए, यह तरीका अपनाएं:
- वह ऐप्लिकेशन ढूंढें जिसे आपको इंस्टॉल करना है. इसके लिए,
android_binaryनियम का इस्तेमाल करें. proguard_specsएट्रिब्यूट हटाकर, Proguard को बंद करें.multidexएट्रिब्यूट कोnativeपर सेट करें.dex_shardsएट्रिब्यूट को10पर सेट करें.- अपने डिवाइस को यूएसबी के ज़रिए ART (Dalvik नहीं) पर कनेक्ट करें और उस पर यूएसबी डीबग करने की सुविधा चालू करें.
bazel mobile-install :your_targetचलाएं. ऐप्लिकेशन शुरू होने में, सामान्य से थोड़ा ज़्यादा समय लगेगा.- कोड या Android के संसाधनों में बदलाव करें.
bazel mobile-install --incremental :your_targetचलाएं.- अब आपको ज़्यादा इंतज़ार नहीं करना पड़ेगा.
Bazel के लिए, कमांड लाइन के कुछ विकल्प यहां दिए गए हैं. ये विकल्प आपके काम आ सकते हैं:
--adbसे Bazel को यह पता चलता है कि उसे कौनसा adb बाइनरी इस्तेमाल करना है--adb_argकी कमांड लाइन में, अतिरिक्त आर्ग्युमेंट जोड़ने के लिएadbका इस्तेमाल किया जा सकता है. इसका एक फ़ायदा यह है कि अगर आपके वर्कस्टेशन से एक से ज़्यादा डिवाइस कनेक्ट हैं, तो यह चुना जा सकता है कि आपको कौनसा डिवाइस इंस्टॉल करना है है:bazel mobile-install --adb_arg=-s --adb_arg=<SERIAL> :your_target--start_appसे ऐप्लिकेशन अपने-आप शुरू हो जाता है
अगर आपको कोई समस्या आ रही है, तो उदाहरण देखें या हमसे संपर्क करें.
परिचय
डेवलपर के टूलचेन की सबसे अहम खूबियों में से एक है, तेज़ी से काम करना. कोड में बदलाव करने और उसे एक सेकंड के अंदर चलते हुए देखने में काफ़ी अंतर होता है. इसके अलावा, यह भी हो सकता है कि बदलावों के मुताबिक काम होने की पुष्टि करने के लिए, आपको मिनटों या घंटों तक इंतज़ार करना पड़े.
दुर्भाग्य से, .apk बनाने के लिए Android के पारंपरिक टूलचेन में, एक के बाद एक कई चरण शामिल होते हैं. Android ऐप्लिकेशन बनाने के लिए, इन सभी चरणों को पूरा करना ज़रूरी है. Google में, Google Maps जैसे बड़े प्रोजेक्ट में, एक लाइन के बदलाव को बनाने में पांच मिनट लगने की समस्या आम थी.
bazel mobile-install की मदद से, Android के लिए इटरेटिव डेवलपमेंट को ज़्यादा तेज़ी से किया जा सकता है. इसके लिए, बदलावों को कम करने, काम को बांटने, और Android के इंटरनल को बेहतर तरीके से मैनेज करने के तरीकों का इस्तेमाल किया जाता है. इन तरीकों का इस्तेमाल करने के लिए, आपको अपने ऐप्लिकेशन के कोड में कोई बदलाव नहीं करना पड़ता.
ऐप्लिकेशन इंस्टॉल करने के पारंपरिक तरीके में आने वाली समस्याएं
Android ऐप्लिकेशन बनाने में कुछ समस्याएं आती हैं. इनमें ये समस्याएं शामिल हैं:
Dexing. डिफ़ॉल्ट रूप से, "dx" को बिल्ड में सिर्फ़ एक बार लागू किया जाता है. साथ ही, यह पिछले बिल्ड के काम को दोबारा इस्तेमाल नहीं कर सकता. यह हर तरीके को फिर से dex करता है. भले ही, सिर्फ़ एक तरीका बदला गया हो.
डिवाइस पर डेटा अपलोड करना. adb, यूएसबी 2.0 कनेक्शन की पूरी बैंडविथ का इस्तेमाल नहीं करता. साथ ही, बड़े ऐप्लिकेशन को अपलोड करने में ज़्यादा समय लग सकता है. पूरा ऐप्लिकेशन अपलोड किया जाता है. भले ही, उसके सिर्फ़ छोटे-छोटे हिस्सों में बदलाव किया गया हो. जैसे, कोई संसाधन या कोई एक तरीका. इसलिए, यह एक बड़ी समस्या हो सकती है.
नेटिव कोड में कंपाइल करना. Android L में ART को पेश किया गया था. यह Android का नया रनटाइम है. यह ऐप्लिकेशन को Dalvik की तरह, सिर्फ़ रनटाइम में कंपाइल करने के बजाय, पहले से कंपाइल करता है. इससे ऐप्लिकेशन ज़्यादा तेज़ी से काम करते हैं. हालांकि, इन्हें इंस्टॉल करने में ज़्यादा समय लगता है. यह लोगों के लिए फ़ायदेमंद है, क्योंकि वे आम तौर पर किसी ऐप्लिकेशन को एक बार इंस्टॉल करते हैं और उसका कई बार इस्तेमाल करते हैं. हालांकि, इससे डेवलपमेंट की प्रोसेस धीमी हो जाती है, क्योंकि ऐप्लिकेशन को कई बार इंस्टॉल किया जाता है और हर वर्शन को ज़्यादा से ज़्यादा कुछ बार चलाया जाता है.
bazel mobile-install का तरीका
bazel mobile-install की मदद से, ये सुधार किए जा सकते हैं:
शार्डिंग के ज़रिए dexing. ऐप्लिकेशन का Java कोड बनाने के बाद, Bazel क्लास फ़ाइलों को लगभग बराबर साइज़ के हिस्सों में बांटता है और उन पर अलग-अलग
dxलागू करता है. जिन शार्ड में पिछले बिल्ड के बाद से कोई बदलाव नहीं हुआ है उन परdxलागू नहीं किया जाता.इंक्रीमेंटल फ़ाइल ट्रांसफ़र. Android के संसाधन, .dex फ़ाइलें, और नेटिव लाइब्रेरी को मुख्य .apk से हटा दिया जाता है. साथ ही, इन्हें mobile-install डायरेक्ट्री में अलग से सेव किया जाता है. इससे पूरे ऐप्लिकेशन को फिर से इंस्टॉल किए बिना, कोड और Android के संसाधनों को अलग-अलग अपडेट किया जा सकता है. इसलिए, फ़ाइलों को ट्रांसफ़र करने में कम समय लगता है. साथ ही, डिवाइस पर सिर्फ़ उन .dex फ़ाइलों को फिर से कंपाइल किया जाता है जिनमें बदलाव किया गया है.
.apk के बाहर से ऐप्लिकेशन के हिस्सों को लोड करना. .apk में एक छोटा स्टब ऐप्लिकेशन डाला जाता है. यह डिवाइस पर मौजूद mobile-install डायरेक्ट्री से Android के संसाधन, Java कोड, और नेटिव कोड लोड करता है. इसके बाद, कंट्रोल को असली ऐप्लिकेशन पर ट्रांसफ़र कर देता है. यह सब ऐप्लिकेशन के लिए पारदर्शी होता है. हालांकि, यहां बताए गए कुछ खास मामलों में ऐसा नहीं होता.
शार्डिंग के ज़रिए dexing
शार्डिंग के ज़रिए dexing की प्रोसेस आसान है: .jar फ़ाइलें बनने के बाद, एक
टूल
उन्हें लगभग बराबर साइज़ की अलग-अलग .jar फ़ाइलों में बांटता है. इसके बाद, उन फ़ाइलों पर
dx लागू करता है जिनमें पिछले बिल्ड के बाद से बदलाव किया गया है. यह तय करने की प्रोसेस कि किन शार्ड को dex करना है, Android के लिए खास नहीं है. इसके लिए, Bazel के सामान्य बदलावों को कम करने वाले एल्गोरिद्म का इस्तेमाल किया जाता है.
शार्डिंग एल्गोरिद्म के पहले वर्शन में, .class फ़ाइलों को वर्णमाला के क्रम में रखा जाता था. इसके बाद, सूची को बराबर साइज़ के हिस्सों में बांटा जाता था. हालांकि, यह तरीका सही नहीं था. अगर कोई क्लास जोड़ी या हटाई जाती थी (चाहे वह नेस्टेड हो या एनॉनिमस), तो वर्णमाला के क्रम में उसके बाद आने वाली सभी क्लास एक-एक करके शिफ़्ट हो जाती थीं. इससे उन शार्ड को फिर से dex करना पड़ता था. इसलिए, अलग-अलग क्लास के बजाय, Java पैकेज को शार्ड करने का फ़ैसला लिया गया. ज़ाहिर है कि अगर कोई नया पैकेज जोड़ा या हटाया जाता है, तो इससे अब भी कई शार्ड को dex करना पड़ता है. हालांकि, ऐसा किसी एक क्लास को जोड़ने या हटाने के मुकाबले कम बार होता है.
शार्ड की संख्या को BUILD फ़ाइल से कंट्रोल किया जाता है. इसके लिए, android_binary.dex_shards एट्रिब्यूट का इस्तेमाल किया जाता है. आदर्श स्थिति में, Bazel अपने-आप यह तय कर लेगा कि कितने शार्ड सबसे सही हैं. हालांकि, Bazel को फ़िलहाल कोई भी कार्रवाई (उदाहरण के लिए, बिल्ड के दौरान लागू किए जाने वाले निर्देश) लागू करने से पहले, उसके बारे में पता होना चाहिए. इसलिए, यह शार्ड की सही संख्या तय नहीं कर सकता, क्योंकि इसे यह नहीं पता कि ऐप्लिकेशन में आखिर में कितनी Java क्लास होंगी. आम तौर पर, जितने ज़्यादा शार्ड होंगे, बिल्ड और इंस्टॉलेशन उतना ही तेज़ होगा. हालांकि, ऐप्लिकेशन शुरू होने में उतना ही ज़्यादा समय लगेगा, क्योंकि डाइनैमिक लिंकर को ज़्यादा काम करना पड़ेगा. आम तौर पर, 10 से 50 शार्ड सबसे सही होते हैं.
इंक्रीमेंटल फ़ाइल ट्रांसफ़र
ऐप्लिकेशन बनाने के बाद, अगला चरण उसे इंस्टॉल करना है. कोशिश करें कि इसे कम से कम मेहनत में इंस्टॉल किया जाए. इंस्टॉल करने के लिए, यह तरीका अपनाएं:
- .apk इंस्टॉल करना (आम तौर पर,
adb installका इस्तेमाल करके) - .dex फ़ाइलें, Android के संसाधन, और नेटिव लाइब्रेरी को mobile-install डायरेक्ट्री में अपलोड करना
पहले चरण में, ज़्यादा इंक्रीमेंटैलिटी नहीं होती. ऐप्लिकेशन या तो इंस्टॉल होता है या नहीं. Bazel फ़िलहाल उपयोगकर्ता पर निर्भर करता है कि उसे --incremental कमांड लाइन विकल्प के ज़रिए यह बताना होगा कि उसे यह चरण पूरा करना है या नहीं. इसकी वजह यह है कि Bazel, हर मामले में यह तय नहीं कर सकता कि यह ज़रूरी है या नहीं.
दूसरे चरण में, बिल्ड से ऐप्लिकेशन की फ़ाइलों की तुलना, डिवाइस पर मौजूद मेनिफ़ेस्ट फ़ाइल से की जाती है. इस फ़ाइल में, डिवाइस पर मौजूद ऐप्लिकेशन की फ़ाइलों और उनके चेकसम की सूची होती है. डिवाइस पर नई फ़ाइलें अपलोड की जाती हैं, बदली गई फ़ाइलें अपडेट की जाती हैं, और हटाई गई फ़ाइलें डिवाइस से मिटा दी जाती हैं. अगर मेनिफ़ेस्ट मौजूद नहीं है, तो यह मान लिया जाता है कि हर फ़ाइल को अपलोड करना ज़रूरी है.
ध्यान दें कि डिवाइस पर किसी फ़ाइल में बदलाव करके, इंक्रीमेंटल इंस्टॉलेशन एल्गोरिद्म को धोखा दिया जा सकता है. हालांकि, मेनिफ़ेस्ट में उसके चेकसम में बदलाव नहीं किया जा सकता. डिवाइस पर मौजूद फ़ाइलों का चेकसम कंप्यूट करके, इससे बचा जा सकता था. हालांकि, यह माना गया कि इंस्टॉलेशन में लगने वाले समय में बढ़ोतरी के मुकाबले, यह फ़ायदेमंद नहीं है.
स्टब ऐप्लिकेशन
स्टब ऐप्लिकेशन की मदद से, डिवाइस पर मौजूद mobile-install डायरेक्ट्री से dexes, नेटिव कोड, और Android के संसाधन लोड किए जाते हैं.
BaseDexClassLoader को सबक्लास करके, असली लोडिंग लागू की जाती है. यह एक अच्छी तरह से दस्तावेज़ वाली तकनीक है. यह ऐप्लिकेशन की किसी भी क्लास के लोड होने से पहले होता है, ताकि apk में मौजूद किसी भी ऐप्लिकेशन क्लास को डिवाइस पर मौजूद mobile-install डायरेक्ट्री में रखा जा सके. इससे adb install के बिना, उन्हें अपडेट किया जा सकता है.
यह ऐप्लिकेशन की किसी भी क्लास के लोड होने से पहले होना चाहिए, ताकि .apk में कोई ऐप्लिकेशन क्लास न हो. इसका मतलब है कि उन क्लास में बदलाव करने के लिए, पूरे ऐप्लिकेशन को फिर से इंस्टॉल करना होगा.
इसे Application क्लास को
AndroidManifest.xml में बताए गए
स्टब ऐप्लिकेशन से बदलकर पूरा किया जाता है. ऐप्लिकेशन शुरू होने पर, यह कंट्रोल लेता है. साथ ही, Android फ़्रेमवर्क के इंटरनल पर Java रिफ़्लेक्शन का इस्तेमाल करके, क्लास लोडर और रिसोर्स मैनेजर को सबसे पहले (इसके कंस्ट्रक्टर) सही तरीके से बदलता है.
स्टब ऐप्लिकेशन, mobile-install से इंस्टॉल की गई नेटिव लाइब्रेरी को किसी दूसरी जगह पर कॉपी भी करता है. यह ज़रूरी है, क्योंकि डाइनैमिक लिंकर को फ़ाइलों पर X बिट सेट करने की ज़रूरत होती है. ऐसा किसी भी ऐसी जगह के लिए नहीं किया जा सकता जिसे नॉन-रूट adb से ऐक्सेस किया जा सकता है.
ये सभी काम पूरे होने के बाद, स्टब ऐप्लिकेशन असली Application क्लास को इंस्टैंशिएट करता है. साथ ही, Android फ़्रेमवर्क में खुद के सभी रेफ़रंस को असली ऐप्लिकेशन में बदल देता है.
नतीजे
परफ़ॉर्मेंस
आम तौर पर, bazel mobile-install की मदद से, बड़े ऐप्लिकेशन में छोटा बदलाव करने के बाद, उन्हें बनाने और इंस्टॉल करने की स्पीड 4 से 10 गुना बढ़ जाती है.
Google के कुछ प्रॉडक्ट के लिए, ये आंकड़े कंप्यूट किए गए थे:
ज़ाहिर है कि यह बदलाव की प्रकृति पर निर्भर करता है. बेस लाइब्रेरी में बदलाव करने के बाद, उसे फिर से कंपाइल करने में ज़्यादा समय लगता है.
सीमाएं
स्टब ऐप्लिकेशन के तरीके, हर मामले में काम नहीं करते. यहां कुछ ऐसे मामले दिए गए हैं जिनमें यह उम्मीद के मुताबिक काम नहीं करता:
जब
ContextकोContentProvider#onCreate()मेंApplicationक्लास में कास्ट किया जाता है. इस तरीके को ऐप्लिकेशन शुरू होने के दौरान कॉल किया जाता है. इससे पहले कि हमेंApplicationक्लास के इंस्टेंस को बदलने का मौका मिले. इसलिए,ContentProviderअसली ऐप्लिकेशन के बजाय, स्टब ऐप्लिकेशन को रेफ़र करेगा. माना जा सकता है कि यह कोई गड़बड़ी नहीं है, क्योंकि आपकोContextको इस तरह डाउनकास्ट नहीं करना चाहिए. हालांकि, Google के कुछ ऐप्लिकेशन में ऐसा होता है.bazel mobile-installसे इंस्टॉल किए गए संसाधन, सिर्फ़ ऐप्लिकेशन के अंदर से उपलब्ध होते हैं. अगरPackageManager#getApplicationResources()के ज़रिए, अन्य ऐप्लिकेशन इन संसाधनों को ऐक्सेस करते हैं, तो ये संसाधन, पिछले नॉन-इंक्रीमेंटल इंस्टॉलेशन से होंगे.ऐसे डिवाइस जो ART पर काम नहीं करते. स्टब ऐप्लिकेशन, Froyo और उसके बाद के वर्शन पर अच्छी तरह से काम करता है. हालांकि, Dalvik में एक गड़बड़ी है. इसकी वजह से, कुछ मामलों में यह मानता है कि ऐप्लिकेशन सही नहीं है. उदाहरण के लिए, जब Java एनोटेशन का इस्तेमाल किसी खास तरीके से किया जाता है, तो ऐप्लिकेशन का कोड कई .dex फ़ाइलों में डिस्ट्रिब्यूट हो जाता है. जब तक आपका ऐप्लिकेशन इन गड़बड़ियों को ट्रिगर नहीं करता, तब तक यह Dalvik के साथ भी काम करेगा. हालांकि, ध्यान दें कि हमारा फ़ोकस, Android के पुराने वर्शन के लिए सहायता उपलब्ध कराना नहीं है