bazel मोबाइल-इंस्टॉल

Android के लिए, तेज़ी से इटरेटिव डेवलपमेंट

इस पेज पर, यह बताया गया है कि bazel mobile-install की मदद से, Android के लिए इटरेटिव डेवलपमेंट को ज़्यादा तेज़ी से कैसे किया जा सकता है. इसमें, ऐप्लिकेशन इंस्टॉल करने के पारंपरिक तरीके की चुनौतियों के मुकाबले, इस तरीके के फ़ायदों के बारे में बताया गया है.

खास जानकारी

Android ऐप्लिकेशन में छोटे-छोटे बदलावों को बहुत तेज़ी से इंस्टॉल करने के लिए, यह तरीका अपनाएं:

  1. उस ऐप्लिकेशन का android_binary नियम ढूंढें जिसे आपको इंस्टॉल करना है.
  2. proguard_specs एट्रिब्यूट हटाकर, Proguard को बंद करें.
  3. multidex एट्रिब्यूट को native पर सेट करें.
  4. dex_shards एट्रिब्यूट को 10 पर सेट करें.
  5. अपने डिवाइस को यूएसबी के ज़रिए ART (Dalvik नहीं) पर कनेक्ट करें और उस पर यूएसबी डीबग करने की सुविधा चालू करें.
  6. bazel mobile-install :your_target चलाएं. ऐप्लिकेशन शुरू होने में, सामान्य से थोड़ा ज़्यादा समय लगेगा.
  7. कोड या Android के संसाधनों में बदलाव करें.
  8. bazel mobile-install --incremental :your_target चलाएं.
  9. अब आपको ज़्यादा इंतज़ार नहीं करना पड़ेगा.

Bazel के लिए, कमांड लाइन के कुछ विकल्प यहां दिए गए हैं. ये विकल्प आपके काम आ सकते हैं:

  • --adb से Bazel को यह पता चलता है कि उसे कौनसी adb बाइनरी का इस्तेमाल करना है
  • --adb_arg की कमांड लाइन में, अतिरिक्त आर्ग्युमेंट जोड़ने के लिए adb का इस्तेमाल किया जा सकता है. इसका एक फ़ायदा यह है कि अगर आपके वर्कस्टेशन से एक से ज़्यादा डिवाइस कनेक्ट हैं, तो यह चुना जा सकता है कि आपको किस डिवाइस पर ऐप्लिकेशन इंस्टॉल करना है: to if you have multiple devices connected to your workstation: 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 में ये सुधार किए गए हैं:

  • शार्डेड डेक्सिंग. ऐप्लिकेशन का Java कोड बनाने के बाद, Bazel क्लास फ़ाइलों को लगभग बराबर साइज़ के हिस्सों में बांटता है और उन पर अलग-अलग dx लागू करता है. जिन हिस्सों में पिछले बिल्ड के बाद से कोई बदलाव नहीं हुआ है उन पर dx लागू नहीं किया जाता.

  • इंक्रीमेंटल फ़ाइल ट्रांसफ़र. Android के संसाधन, .dex फ़ाइलें, और नेटिव लाइब्रेरी, मुख्य .apk से हटा दी जाती हैं. इन्हें mobile-install की अलग डायरेक्ट्री में सेव किया जाता है. इससे पूरे ऐप्लिकेशन को रीइंस्टॉल किए बिना, कोड और Android के संसाधनों को अलग-अलग अपडेट किया जा सकता है. इसलिए, फ़ाइलों को ट्रांसफ़र करने में कम समय लगता है. साथ ही, डिवाइस पर सिर्फ़ उन .dex फ़ाइलों को फिर से कंपाइल किया जाता है जिनमें बदलाव किया गया है.

  • .apk के बाहर से ऐप्लिकेशन के हिस्सों को लोड करना. .apk में एक छोटा स्टब ऐप्लिकेशन डाला जाता है. यह डिवाइस पर मौजूद mobile-install डायरेक्ट्री से Android के संसाधन, Java कोड, और नेटिव कोड लोड करता है. इसके बाद, कंट्रोल को असली ऐप्लिकेशन पर ट्रांसफ़र कर देता है. यह सब ऐप्लिकेशन के लिए पारदर्शी होता है. हालांकि, कुछ खास मामलों में ऐसा नहीं होता. इनके बारे में यहां बताया गया है.

शार्डेड डेक्सिंग

शार्डेड डेक्सिंग का तरीका आसान है: .jar फ़ाइलें बनने के बाद, एक टूल उन्हें लगभग बराबर साइज़ की अलग-अलग .jar फ़ाइलों में बांटता है. इसके बाद, उन फ़ाइलों पर dx लागू करता है जिनमें पिछले बिल्ड के बाद से बदलाव किया गया है. यह तय करने की लॉजिक कि किन हिस्सों को dex करना है, Android के लिए खास नहीं है. यह सिर्फ़ Bazel के सामान्य बदलावों को कम करने वाले एल्गोरिदम का इस्तेमाल करता है.

शार्डिंग एल्गोरिदम के पहले वर्शन में, .class फ़ाइलों को वर्णमाला के क्रम में रखा जाता था. इसके बाद, सूची को बराबर साइज़ के हिस्सों में बांटा जाता था. हालांकि, यह तरीका सही नहीं था: अगर कोई क्लास जोड़ी या हटाई जाती थी (चाहे वह नेस्टेड हो या एनॉनिमस), तो वर्णमाला के क्रम में उसके बाद आने वाली सभी क्लास एक-एक करके शिफ़्ट हो जाती थीं. इससे उन हिस्सों को फिर से dex करना पड़ता था. इसलिए, यह तय किया गया कि अलग-अलग क्लास के बजाय, Java पैकेज को शार्ड किया जाए. ज़ाहिर है कि अगर कोई नया पैकेज जोड़ा या हटाया जाता है, तो इससे अब भी कई हिस्सों को dex करना पड़ता है. हालांकि, ऐसा किसी एक क्लास को जोड़ने या हटाने के मुकाबले कम बार होता है.

BUILD फ़ाइल (जिसमें android_binary.dex_shards एट्रिब्यूट का इस्तेमाल किया जाता है) से, हिस्सों की संख्या को कंट्रोल किया जाता है. आदर्श स्थिति में, Bazel अपने-आप यह तय कर लेगा कि कितने हिस्से सबसे सही हैं. हालांकि, Bazel को फ़िलहाल किसी भी कार्रवाई को करने से पहले, कार्रवाइयों के सेट (उदाहरण के लिए, बिल्ड के दौरान लागू किए जाने वाले निर्देश) के बारे में पता होना चाहिए. इसलिए, यह हिस्सों की सही संख्या तय नहीं कर सकता, क्योंकि इसे यह नहीं पता कि ऐप्लिकेशन में आखिर में कितनी Java क्लास होंगी. आम तौर पर, जितने ज़्यादा हिस्से होंगे, बिल्ड और इंस्टॉलेशन उतना ही तेज़ होगा. हालांकि, ऐप्लिकेशन शुरू होने में उतना ही ज़्यादा समय लगेगा, क्योंकि डाइनैमिक लिंकर को ज़्यादा काम करना पड़ेगा. आम तौर पर, 10 से 50 हिस्से सबसे सही होते हैं.

इंक्रीमेंटल फ़ाइल ट्रांसफ़र

ऐप्लिकेशन बनाने के बाद, अगला चरण उसे इंस्टॉल करना है. कोशिश करें कि इसे कम से कम मेहनत में इंस्टॉल किया जाए. इंस्टॉल करने में ये चरण शामिल हैं:

  1. .apk इंस्टॉल करना (आम तौर पर, adb install का इस्तेमाल करके)
  2. .dex फ़ाइलें, Android के संसाधन, और नेटिव लाइब्रेरी को mobile-install डायरेक्ट्री में अपलोड करना

पहले चरण में, ज़्यादा इंक्रीमेंटैलिटी नहीं होती: ऐप्लिकेशन या तो इंस्टॉल होता है या नहीं. Bazel फ़िलहाल उपयोगकर्ता पर निर्भर करता है कि वह --incremental कमांड लाइन विकल्प के ज़रिए यह बताए कि उसे यह चरण पूरा करना चाहिए या नहीं. इसकी वजह यह है कि वह हर मामले में यह तय नहीं कर सकता कि यह ज़रूरी है या नहीं.

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

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

स्टब ऐप्लिकेशन

स्टब ऐप्लिकेशन की मदद से, डिवाइस पर मौजूद mobile-install डायरेक्ट्री से dexes, नेटिव कोड, और Android के संसाधन लोड किए जाते हैं.

असल में, लोडिंग की प्रोसेस BaseDexClassLoader को सबक्लास करके लागू की जाती है. यह एक अच्छी तरह से दस्तावेज़ में बताई गई तकनीक है. यह ऐप्लिकेशन की किसी भी क्लास के लोड होने से पहले होता है, ताकि apk में मौजूद किसी भी ऐप्लिकेशन क्लास को डिवाइस पर मौजूद mobile-install डायरेक्ट्री में रखा जा सके. इससे उन्हें adb install के बिना अपडेट किया जा सकता है.

यह ऐप्लिकेशन की किसी भी क्लास के लोड होने से पहले होना चाहिए, ताकि किसी भी ऐप्लिकेशन क्लास को .apk में न रखना पड़े. इसका मतलब है कि उन क्लास में बदलाव करने के लिए, पूरे ऐप्लिकेशन को रीइंस्टॉल करना पड़ेगा.

AndroidManifest.xml में बताई गई Application क्लास को स्टब ऐप्लिकेशन से बदलकर, यह काम पूरा किया जाता है. जब ऐप्लिकेशन शुरू होता है, तो यह कंट्रोल लेता है. साथ ही, Android फ़्रेमवर्क के इंटरनल पर Java रिफ़्लेक्शन का इस्तेमाल करके, क्लास लोडर और रिसोर्स मैनेजर को सबसे पहले (इसके कंस्ट्रक्टर) में सही तरीके से बदलता है.

स्टब ऐप्लिकेशन, mobile-install से इंस्टॉल की गई नेटिव लाइब्रेरी को किसी दूसरी जगह पर कॉपी भी करता है. यह ज़रूरी है, क्योंकि डाइनैमिक लिंकर को फ़ाइलों पर X बिट सेट करने की ज़रूरत होती है. ऐसा किसी भी ऐसी जगह के लिए नहीं किया जा सकता जिसे नॉन-रूट adb से ऐक्सेस किया जा सकता है.

ये सभी काम पूरे होने के बाद, स्टब ऐप्लिकेशन असली Application क्लास को इंस्टैंशिएट करता है. साथ ही, Android फ़्रेमवर्क में खुद के सभी रेफ़रंस को असली ऐप्लिकेशन में बदल देता है.

नतीजे

परफ़ॉर्मेंस

आम तौर पर, bazel mobile-install की मदद से, बड़े ऐप्लिकेशन को बनाने और इंस्टॉल करने की स्पीड में चार से दस गुना बढ़ोतरी होती है. यह बढ़ोतरी, ऐप्लिकेशन में छोटे-मोटे बदलाव करने के बाद होती है.

Google के कुछ प्रॉडक्ट के लिए, ये आंकड़े कंप्यूट किए गए थे:

ज़ाहिर है कि यह बदलाव की प्रकृति पर निर्भर करता है: बेस लाइब्रेरी में बदलाव करने के बाद, फिर से कंपाइल करने में ज़्यादा समय लगता है.

सीमाएं

स्टब ऐप्लिकेशन की ट्रिक्स हर मामले में काम नहीं करतीं. यहां कुछ ऐसे मामले बताए गए हैं जिनमें यह उम्मीद के मुताबिक काम नहीं करता: