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 की कमांड लाइन में अतिरिक्त आर्ग्युमेंट जोड़ने के लिए किया जा सकता है. इसका एक उपयोगी ऐप्लिकेशन यह चुनना है कि अगर आपके वर्कस्टेशन से एक से ज़्यादा डिवाइस कनेक्ट हैं, तो उस डिवाइस को इंस्टॉल करना है: bazel mobile-install --adb_arg=-s --adb_arg=<SERIAL> :your_target
  • --start_app ऐप्लिकेशन अपने-आप चालू कर देता है

किसी तरह का संदेह होने पर, उदाहरण देखें या हमसे संपर्क करें.

शुरुआती जानकारी

डेवलपर के टूलचेन की सबसे अहम विशेषताओं में से एक है स्पीड: कोड को बदलने और उसे एक सेकंड के अंदर चलने और कुछ ही मिनटों तक इंतज़ार करने के बाद कई बार कुछ घंटों तक इंतज़ार करना पड़ता है. इससे पहले कि आपको सुझाव मिले कि बदलाव आपके काम कर रहे हैं या नहीं.

माफ़ करें, .apk बनाने के लिए पारंपरिक Android टूलचेन में कई मोनोलिथिक, क्रम में चलने वाले चरण होते हैं और Android ऐप्लिकेशन बनाने के लिए ये सभी चरण पूरे करने होते हैं. Google Maps जैसे बड़े प्रोजेक्ट में, सिंगल-लाइन बदलाव बनाने के लिए पांच मिनट इंतज़ार करना आम बात है.

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

ऐप्लिकेशन को इंस्टॉल करने के पुराने तरीके से जुड़ी समस्याएं

Android ऐप्लिकेशन बनाने में कुछ समस्याएं आ रही हैं, जैसे:

  • डेक्सिंग. डिफ़ॉल्ट रूप से, "dx" को बिल्ड में सिर्फ़ एक बार शुरू किया जाता है और इसे पिछले बिल्ड के काम को फिर से इस्तेमाल करने का तरीका नहीं पता होता: इसमें हर तरीके को फिर से शामिल किया जाता है, भले ही सिर्फ़ एक तरीका बदला गया हो.

  • डिवाइस पर डेटा अपलोड करना. adb, यूएसबी 2.0 कनेक्शन की पूरी बैंडविड्थ का इस्तेमाल नहीं करता. साथ ही, बड़े ऐप्लिकेशन अपलोड होने में ज़्यादा समय ले सकते हैं. पूरे ऐप्लिकेशन को अपलोड किया जाता है, भले ही उसके कुछ हिस्सों में ही बदलाव हुए हों, जैसे कि कोई संसाधन या कोई एक तरीका. इसलिए, यह एक बड़ी समस्या हो सकती है.

  • नेटिव कोड का कंपाइलेशन. Android L ने ART को पेश किया, जो एक नया Android रनटाइम है. इसमें, Dalvik की तरह ऐप्लिकेशन का डेटा समय-समय पर इकट्ठा करने के बजाय, पहले से एक साथ इकट्ठा किया जाता है. इससे ऐप्लिकेशन बहुत तेज़ी से इंस्टॉल होते हैं और इंस्टॉल करने में ज़्यादा समय लगता है. उपयोगकर्ता के लिए यह एक अच्छा विकल्प है, क्योंकि वे किसी ऐप्लिकेशन को एक बार इंस्टॉल करते हैं और कई बार इस्तेमाल करते हैं. हालांकि, इससे ऐप्लिकेशन इंस्टॉल होने की रफ़्तार धीमी हो जाती है और कोई ऐप्लिकेशन कई बार इंस्टॉल किया जाता है और हर वर्शन कई बार चलाया जाता है.

bazel mobile-install का तरीका

bazel mobile-installये सुधार करता है:

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

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

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

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

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

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

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

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

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

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

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

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

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

Stub ऐप्लिकेशन

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

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

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

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

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

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

नतीजे

परफ़ॉर्मेंस

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

नीचे दिए गए नंबरों की गिनती Google के कुछ प्रॉडक्ट के लिए की गई थी:

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

सीमाएं

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

  • जब Context को ContentProvider#onCreate() की Application क्लास में कास्ट किया जाता है. इस तरीके को ऐप्लिकेशन के शुरू होने के दौरान कॉल किया जाता है. ऐसा, हमें Application क्लास के इंस्टेंस को बदलने का मौका मिलने से पहले दिया जाता है. इसलिए, ContentProvider अब भी असली के बजाय स्टब ऐप्लिकेशन का रेफ़रंस देगा. यकीनन, यह कोई गड़बड़ी नहीं है, क्योंकि आपके लिए Context को इस तरह से बंद नहीं किया गया है, लेकिन ऐसा लगता है कि ऐसा Google के कुछ ही ऐप्लिकेशन में होता है.

  • bazel mobile-install ने जो संसाधन इंस्टॉल किए हैं वे सिर्फ़ ऐप्लिकेशन में उपलब्ध होते हैं. अगर संसाधनों को PackageManager#getApplicationResources() के ज़रिए दूसरे ऐप्लिकेशन से ऐक्सेस किया जाता है, तो ये संसाधन आखिरी नॉन-इंक्रीमेंटल इंस्टॉल होंगे.

  • वे डिवाइस जो ART नहीं चला रहे हैं. हालांकि, Froyo और इसके बाद के वर्शन पर stub ऐप्लिकेशन अच्छी तरह से काम करता है, Delvik में एक गड़बड़ी है जो बताती है कि अगर ऐप्लिकेशन का कोड कुछ खास मामलों में कई .dex फ़ाइलों पर डिस्ट्रिब्यूट किया गया है, तो यह ऐप्लिकेशन सही नहीं है. उदाहरण के लिए, जब Java की जानकारी का किसी खास तरीके से इस्तेमाल किया जाता है. जब तक आपका ऐप्लिकेशन इन बग को गुदगुना नहीं रहा, तब तक उसे Delvik के साथ काम करना चाहिए (ध्यान दें, यह सिर्फ़ हमारा फ़ोकस नहीं है कि पुराने Android वर्शन पर काम किया जाए)