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

समस्या की शिकायत करें सोर्स देखें

Android के लिए बार-बार और तेज़ी से जानकारी पाना

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

खास जानकारी

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

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

Basel के लिए कुछ कमांड-लाइन विकल्प जो उपयोगी हो सकते हैं:

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

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

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

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

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

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

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

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

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

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

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

bazel mobile-install को अपनाने का तरीका

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Stub ऐप्लिकेशन

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

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

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

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

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