تثبيت الجوّال في Bazel

التطوير المكرّر السريع لنظام التشغيل Android

توضّح هذه الصفحة آلية عمل bazel mobile-install على التطوير المكرّر لنظام التشغيل Android بشكل أسرع. تصف مزايا هذا الأسلوب في مقابل تحديات طريقة تثبيت التطبيقات التقليدية.

الملخّص

لتثبيت التغييرات الصغيرة على تطبيق Android بسرعة كبيرة، نفِّذ ما يلي:

  1. ابحث عن قاعدة android_binary في التطبيق الذي تريد تثبيته.
  2. إيقاف Proguard عن طريق إزالة السمة proguard_specs.
  3. ضبط السمة multidex على native
  4. ضبط السمة dex_shards على 10
  5. اربط جهازك الذي يعمل بنظام ART (وليس Duvik) عبر USB ومكّن تصحيح أخطاء USB عليه.
  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.

إذا لم تكُن متأكّدًا، اطّلِع على المثال أو تواصَل معنا.

مقدمة

إحدى السمات الأكثر أهمية لسلسلة أدوات مطوّر البرامج هي السرعة: أن هناك عالمًا مختلفًا بين تغيير الرمز وعرضه في غضون ثانية والانتظار بضع ساعات في بعض الأحيان، قبل الحصول على أي ملاحظات حول ما إذا كانت التغييرات تؤدي إلى ما تتوقّعه.

وللأسف، تتطلّب سلسلة أدوات Android التقليدية لإنشاء ملف بتنسيق jpg .عدّة خطوات مترابطة ومتتابعة، وكل ذلك من أجل إنشاء تطبيق متوافق مع Android. أما في Google، فلم يكن انتظار خمس دقائق لإنشاء تغيير في سطر واحد أمرًا غير معتاد في المشاريع الكبيرة مثل "خرائط Google".

يطوّر bazel mobile-install التطوير المكرر لنظام التشغيل Android بشكل أسرع بكثير من خلال استخدام مزيج من تشذيب التغييرات وتقسيم العمل والتلاعب الذكي بأنظمة Android الداخلية، وكل ذلك بدون تغيير أي من رموز التطبيقات الخاصة بك.

مشاكل تثبيت التطبيقات التقليدية

يواجه إنشاء تطبيق متوافق مع Android بعض المشاكل، بما في ذلك:

  • جارٍ تنظيف البيانات. تم استدعاء &&dx"مرة واحدة بالضبط في الإصدار بشكل تلقائي ولا يمكنه معرفة كيفية إعادة استخدام العمل من إصدارات سابقة: فهو يتخلل كل طريقة مرة أخرى، على الرغم من تغيير طريقة واحدة فقط.

  • تحميل البيانات إلى الجهاز. لا يستخدم adb معدل نقل البيانات الكامل لاتصال USB 2.0، وقد يستغرق تحميل التطبيقات الأكبر وقتًا طويلاً. ويتم تحميل التطبيق بأكمله، حتى إذا تغيّرت أجزاء صغيرة فقط، مثل مورد أو طريقة واحدة، لذا يمكن أن يمثّل ذلك تأثيرًا سلبيًا كبيرًا.

  • محتوى مجمّع للرمز الأصلي أدخل Android Android ART، وهو وقت تشغيل جديد لنظام التشغيل Android، يجمع التطبيقات مسبقًا بدلاً من تجميعها في الوقت المناسب مثلDalvik. وهو ما يجعل التطبيقات أسرع بكثير من خلال وقت التثبيت الأطول. وتُعدّ هذه المفاضلة جيدة للمستخدمين نظرًا لأنهم يثبِّتون التطبيق عادةً مرة واحدة ويستخدمونه مرات عديدة، ولكنه يؤدي إلى بطء عملية التطوير، حيث يتم تثبيت التطبيق عدة مرات ويتم تشغيل كل إصدار لعدد كبير من المرات كحد أقصى.

نهج bazel mobile-install

bazel mobile-installيجري التحسينات التالية:

  • تقسيم جزء من الشاشة. بعد إنشاء رمز جافا للتطبيق، تقسِّم Bazel ملفات الصفوف إلى أجزاء بحجم متساوٍ وتستدعي dx بشكل منفصل. لم يتم استدعاء dx على الأجزاء التي لم تتغير منذ آخر إصدار.

  • نقل الملف الإضافي. تتم إزالة موارد Android وملفات .dex والمكتبات الأصلية من ملف .jpg الرئيسي ويتم تخزينها في دليل منفصل لتثبيت الجوّال. ويتيح هذا تحديث الرمز وموارد Android بشكل مستقل بدون إعادة تثبيت التطبيق بالكامل. وبالتالي، يستغرق نقل الملفات وقتًا أقل ولا تتم إعادة تجميع سوى ملفات .dex التي تم تغييرها على الجهاز.

  • تحميل أجزاء من التطبيق من خارج ملف .APK. يتم وضع تطبيق التنويه الموجز الصغير في ملف APK الذي يحمّل موارد Android ورمز Java والرمز الأصلي من دليل تثبيت الجهاز الجوّال على الجهاز، ثم ينقل التحكم إلى التطبيق الفعلي. وكل هذا شفاف للتطبيق، باستثناء حالات قليلة في الأقسام.

تقسيم جزء من الشاشة

ويمكن استخدام قاعدة التجزئة المقسّمة إلى حدّ معقول: بعد إنشاء ملفات .jar، تقسّمها أداة الأداة إلى ملفات .jar منفصلة وبحجم متساوٍ تقريبًا، ثم تستدعي dx الملفات التي تم تغييرها منذ الإصدار السابق. إنّ المنطق الذي يُحدِّد الأجزاء التي لا يمكن تحليلها هو نظام تشغيل معيّن لنظام التشغيل Android: إنّه يستخدم خوارزمية تقليم التغييرات العامة في البازلاء.

طلبت النسخة الأولى من خوارزمية التجزئة تقسيم ملفات .class أبجديًا، ثم قسّمت القائمة إلى أجزاء بحجم متساوٍ، ولكن ثبت أن هذا الأمر ليس مثاليًا: إذا تمت إضافة فئة أو إزالتها (حتى إذا كانت مدمجة أو مخفية)، فإن ذلك سيؤدي إلى تغيّر جميع الفئات أبجديًا مرة أخرى، ما يؤدي إلى إلغاء تقسيم هذه الأجزاء مرة أخرى. وبالتالي، تم تحديد تقسيم حِزم Java بدلاً من الصفوف الفردية. وهذا بطبيعة الحال لا يزال يؤدي إلى رفض العديد من الأجزاء إذا تمت إضافة حزمة جديدة أو إزالتها، ولكن أقل من إضافة فئة واحدة أو إزالتها.

يتم التحكم في عدد الأجزاء من خلال ملف BUILD (باستخدام السمة android_binary.dex_shards). في عالم مثالي، ستحدد Bazel تلقائيًا عدد الأجزاء على أفضل نحو، ولكن يجب أن تعرف Bazel حاليًا مجموعة الإجراءات (مثل الأوامر التي سيتم تنفيذها أثناء الإصدار) قبل تنفيذ أي منها، لذلك لا يمكنها تحديد العدد الأمثل من الأجزاء لأنها لا تعرف العدد الصحيح لدروس Java، وكلما زادت قوة الاتصال بالإنترنت، أصبح الاتصال أكثر تعقيدًا على الإنترنت. عادةً ما يتراوح موضع الحلويات بين 10 و50 جزءًا.

عملية نقل الملفات المتزايدة

بعد إنشاء التطبيق، تتمثّل الخطوة التالية في تثبيته، ويُفضّل أن يتم بذل قصارى جهدها. يتكون التثبيت من الخطوات التالية:

  1. تثبيت ملف APK. (عادةً ما يستخدم adb install)
  2. من خلال تحميل ملفات .dex وموارد Android والمكتبات الأصلية إلى دليل تثبيت الجوّال

ليس هناك زيادة كبيرة في الخطوة الأولى: يتم تثبيت التطبيق أم لا. تعتمد Bazel حاليًا على المستخدم للإشارة إلى ما إذا كان يجب تنفيذ هذه الخطوة من خلال خيار سطر الأوامر --incremental لأنه لا يمكن تحديد ذلك في جميع الحالات إذا كان الأمر ضروريًا.

في الخطوة الثانية، تتم مقارنة ملفات التطبيق من الإصدار بملف ملف على الجهاز يدرِج ملفات التطبيق على مجموعتها ومجموعتها الاختبارية. يتم تحميل أي ملفات جديدة إلى الجهاز، ويتم تحديث أي ملفات تم تغييرها، ويتم حذف أي ملفات تمت إزالتها من الجهاز. إذا لم يكن البيان موجودًا، سيُفترض أنّه يجب تحميل كل ملف.

يُرجى العِلم أنه من الممكن خداع خوارزمية التثبيت المتزايدة من خلال تغيير ملف على الجهاز، وليس مجموعها الاختباري في ملف البيان. يمكن حماية ذلك من خلال حساب المجموع الاختباري للملفات على الجهاز، إلا أن ذلك لا يُعتبر يستحق الزيادة على وقت التثبيت.

تطبيق Stub

تطبيق التنويه الموجز هو المكان السحري لتحميل المعالجات والرمز الأصلي وموارد Android من دليل mobile-install على الجهاز.

يتم تنفيذ التحميل الفعلي من خلال الفئة الفرعية BaseDexClassLoader وهو أسلوب موثَّق بشكل معقول. ويحدث ذلك قبل تحميل أي من فئات التطبيقات، بحيث يمكن وضع أي فئات تطبيقات موجودة في حزمة APK في دليل mobile-install على الجهاز لكي يتم تحديثها بدون adb install.

ويجب أن يحدث هذا قبل تحميل أي من فئات التطبيق، بحيث لا يلزم تضمين فئة تطبيق في ملف jpg. مما يعني أن إجراء تغييرات على هذه الفئات سيتطلب إعادة تثبيت كامل.

يمكن تحقيق ذلك من خلال استبدال الفئة Application المحدّدة في AndroidManifest.xml بتطبيق بديل. ويتحكم هذا في بدء تشغيل التطبيق، كما يعدّل أداة تحميل الصف ومدير الموارد بشكل مناسب في أقرب وقت (أداة الإنشاء) باستخدام انعكاس جافا على التفاصيل الداخلية لإطار عمل Android.

وتتمثّل وظيفة أخرى في التطبيق البديل في نسخ المكتبات الأصلية المثبتة من خلال الأجهزة الجوّالة إلى موقع آخر. وهذا ضروري لأنّ الرابط الديناميكي يحتاج إلى ضبط وحدة البت X على الملفات، وهو إجراء لا يمكن تنفيذه لأي موقع جغرافي لا يمكن أن يصل إليه adb غير جذر.

بعد الانتهاء من كل هذه الإجراءات، ينشئ تطبيق التنويه الموجز فئة Application الفعلية، مع تغيير كل الإشارات إلى التطبيق الفعلي ضمن إطار عمل Android.

النتائج

الأداء

بشكلٍ عام، يؤدي bazel mobile-install إلى زيادة سرعة المبنى في 4 أضعاف أو 10 أضعاف وتثبيت التطبيقات الكبيرة بعد إجراء تغيير بسيط.

تم حساب الأرقام التالية لبعض منتجات Google:

وهذا بالطبع يعتمد على طبيعة التغيير: إعادة التجميع بعد تغيير مكتبة أساسية تستغرق المزيد من الوقت.

القيود

لا تعمل الحيل التي يشغّلها تطبيق التنويه الموجز في كل الحالات. توضّح الحالات التالية الحالات التي لا تعمل فيها على النحو المتوقّع:

  • عند إرسال Context إلى الصف Application في ContentProvider#onCreate(). يتم استدعاء هذه الطريقة أثناء بدء تشغيل التطبيق قبل أن يتسنى لنا استبدال مثيل صف Application، لذلك، سيستمر ContentProvider في الإشارة إلى تطبيق التنويه الموجز بدلاً من التطبيق الحقيقي. ربما لا يكون هذا خطأ، لأنه لم يكن من المفترض أن يتم تنزيل Context كهذا، لكن يبدو أن هذا يحدث في عدد قليل من تطبيقات Google.

  • تتوفر الموارد التي تم تثبيتها من خلال bazel mobile-install فقط من داخل التطبيق. إذا تم الوصول إلى الموارد عن طريق تطبيقات أخرى عبر PackageManager#getApplicationResources()، ستكون هذه الموارد من آخر عملية تثبيت غير متزايدة.

  • الأجهزة التي لا تعمل بنظام ART. على الرغم من عمل تطبيق التنويه الموجز على Froyo والإصدارات الأحدث، هناك خطأ في Calvik يجعل التطبيق يعتقد أن التطبيق غير صحيح إذا تم توزيع الرمز على ملفات dex .متعددة في حالات معينة، على سبيل المثال، عند استخدام تعليقات Java توضيحية بطريقة محددة. طالما أن تطبيقك لا يحدد تلك الأخطاء، من المفترض أن يعمل مع Davik أيضًا (ولكن تجدر الإشارة إلى أن الدعم للإصدارات القديمة من Android ليس محور تركيزنا)