توسعه سریع تکراری برای اندروید
این صفحه توضیح میدهد که چگونه bazel mobile-install
توسعه تکراری اندروید را بسیار سریعتر میکند. مزایای این رویکرد در مقابل چالشهای روش نصب برنامه سنتی را شرح میدهد.
خلاصه
برای نصب سریع تغییرات کوچک در یک برنامه اندروید، موارد زیر را انجام دهید:
- قانون
android_binary
برنامه ای را که می خواهید نصب کنید پیدا کنید. - Proguard را با حذف ویژگی
proguard_specs
کنید. - ویژگی
multidex
را رویnative
تنظیم کنید. - ویژگی
dex_shards
را روی10
قرار دهید. - دستگاه خود را در حال اجرا ART (نه Dalvik) از طریق USB وصل کنید و اشکال زدایی USB را روی آن فعال کنید.
-
bazel mobile-install :your_target
. راه اندازی اپلیکیشن کمی کندتر از حد معمول خواهد بود. - کد یا منابع اندروید را ویرایش کنید.
-
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. مستلزم بسیاری از مراحل یکپارچه و متوالی است و همه اینها برای ساختن یک برنامه اندروید باید انجام شوند. در گوگل، پنج دقیقه منتظر ماندن برای ایجاد تغییر تک خطی در پروژه های بزرگتر مانند Google Maps غیرعادی نبود.
bazel mobile-install
با استفاده از ترکیبی از هرس تغییر، تقسیم کار، و دستکاری هوشمندانه داخلی اندروید، همه بدون تغییر کد برنامه، توسعه تکراری اندروید را بسیار سریعتر می کند.
مشکلات نصب برنامه سنتی
ساخت برنامه اندروید دارای مشکلاتی است، از جمله:
دکسینگ. بهطور پیشفرض، «dx» دقیقاً یکبار در بیلد فراخوانی میشود و نمیداند چگونه از کارهای بیلدهای قبلی استفاده مجدد کند: هر متد را دوباره حذف میکند، حتی اگر فقط یک متد تغییر کرده باشد.
در حال آپلود اطلاعات در دستگاه adb از پهنای باند کامل اتصال USB 2.0 استفاده نمی کند و برنامه های بزرگتر زمان زیادی را برای آپلود نیاز دارند. کل برنامه آپلود میشود، حتی اگر فقط بخشهای کوچکی تغییر کرده باشد، به عنوان مثال، یک منبع یا یک روش واحد، بنابراین این میتواند یک گلوگاه بزرگ باشد.
کامپایل به کد بومی Android L ART را معرفی کرد، یک زمان اجرا اندروید جدید، که برنامهها را بهجای کامپایل کردن آنها بهموقع مانند Dalvik، زودتر از موعد مقرر جمعآوری میکند. این باعث می شود برنامه ها با هزینه نصب طولانی تر سریعتر شوند. این یک معاوضه خوب برای کاربران است زیرا آنها معمولاً یک برنامه را یک بار نصب می کنند و بارها از آن استفاده می کنند، اما در جایی که یک برنامه بارها نصب می شود و هر نسخه حداکثر چند بار اجرا می شود منجر به توسعه کندتر می شود.
رویکرد bazel mobile-install
bazel mobile-install
پیشرفت های زیر را انجام می دهد:
دکسینگ خرد شده پس از ساخت کد جاوا برنامه، Bazel فایل های کلاس را به قطعات تقریباً مساوی تقسیم می کند و
dx
را به طور جداگانه بر روی آنها فراخوانی می کند.dx
در قسمت هایی که از آخرین ساخت تغییر نکرده اند فراخوانی نمی شود.انتقال فایل افزایشی منابع Android، فایلهای .dex و کتابخانههای بومی از apk. اصلی حذف میشوند و در یک فهرست راهنمای نصب موبایل جداگانه ذخیره میشوند. این امکان به روز رسانی کد و منابع اندروید را به طور مستقل بدون نصب مجدد کل برنامه فراهم می کند. بنابراین، انتقال فایلها زمان کمتری میبرد و فقط فایلهای .dex که تغییر کردهاند دوباره بر روی دستگاه کامپایل میشوند.
بارگیری بخشهایی از برنامه از خارج از apk. یک برنامه خرد کوچک در apk. قرار داده می شود که منابع Android، کد جاوا و کد بومی را از فهرست راهنمای نصب موبایل روی دستگاه بارگیری می کند، سپس کنترل را به برنامه واقعی منتقل می کند. همه اینها برای برنامه شفاف است، به جز در چند مورد گوشه ای که در زیر توضیح داده شده است.
دکسینگ خرد شده
دکس کردن خرد شده به طور منطقی ساده است: هنگامی که فایلهای jar ساخته میشوند، ابزاری آنها را به فایلهای jar مجزا با اندازه تقریبا مساوی تقسیم میکند، سپس dx
را بر روی فایلهایی که از ساخت قبلی تغییر کردهاند فراخوانی میکند. منطقی که تعیین میکند کدام خردهها را dex کنیم، مختص اندروید نیست: فقط از الگوریتم تغییر کلی هرس Bazel استفاده میکند.
اولین نسخه از الگوریتم به اشتراک گذاری به سادگی فایل های .class را بر اساس حروف الفبا مرتب کرد، سپس لیست را به قسمت هایی با اندازه مساوی تقسیم کرد، اما ثابت شد که این کمتر از حد مطلوب است: اگر یک کلاس اضافه یا حذف شود (حتی یک کلاس تودرتو یا ناشناس)، باعث میشود همه کلاسهای بعد از آن بر اساس حروف الفبا یک بار جابجا شوند و در نتیجه دوباره آن خردهها حذف شوند. بنابراین، تصمیم گرفته شد که بستههای جاوا را به جای کلاسهای فردی خرد کنیم. البته، اگر یک بسته جدید اضافه یا حذف شود، این باز هم منجر به حذف کردن بسیاری از خردهها میشود، اما این کار بسیار کمتر از افزودن یا حذف یک کلاس واحد است.
تعداد خرده ها توسط فایل BUILD (با استفاده از ویژگی android_binary.dex_shards
) کنترل می شود. در یک دنیای ایدهآل، Bazel به طور خودکار تعیین میکند که چند تکه بهترین هستند، اما Bazel در حال حاضر باید مجموعه اقدامات (مثلاً دستوراتی که در طول ساخت باید اجرا شوند) را قبل از اجرای هر یک از آنها بداند، بنابراین نمیتواند تعداد بهینه را تعیین کند. به دلیل اینکه نمی داند چند کلاس جاوا در نهایت در برنامه وجود خواهد داشت. به طور کلی، هر چه تعداد قطعات بیشتر باشد، ساخت و نصب سریعتر انجام میشود، اما راهاندازی اپلیکیشن کندتر میشود، زیرا لینکر پویا باید کار بیشتری انجام دهد. لکه شیرین معمولا بین 10 تا 50 خرده است.
انتقال فایل افزایشی
پس از ساخت اپلیکیشن، مرحله بعدی نصب آن ترجیحا با کمترین تلاش ممکن است. نصب شامل مراحل زیر است:
- نصب apk. (معمولاً با استفاده از
adb install
) - آپلود فایلهای .dex، منابع Android و کتابخانههای بومی در فهرست راهنمای نصب موبایل
در مرحله اول افزایش زیادی وجود ندارد: برنامه یا نصب شده است یا خیر. Bazel در حال حاضر به کاربر متکی است تا نشان دهد که آیا باید این مرحله را از طریق گزینه --incremental
command line انجام دهد، زیرا در همه موارد نمی تواند تعیین کند که آیا لازم است یا خیر.
در مرحله دوم، فایلهای برنامه از بیلد با یک فایل مانیفست روی دستگاه مقایسه میشوند که فایلهای برنامه روی دستگاه و چکسامهای آنها را فهرست میکند. هر فایل جدیدی در دستگاه آپلود می شود، هر فایلی که تغییر کرده است به روز می شود و هر فایلی که حذف شده است از دستگاه حذف می شود. اگر مانیفست وجود نداشته باشد، فرض بر این است که هر فایلی باید آپلود شود.
توجه داشته باشید که میتوان الگوریتم نصب افزایشی را با تغییر یک فایل در دستگاه فریب داد، اما نه چکسوم آن را در مانیفست. میتوان با محاسبه چکسوم فایلهای روی دستگاه از این امر محافظت کرد، اما به نظر میرسد که ارزش افزایش زمان نصب را ندارد.
اپلیکیشن Stub
برنامه خرد جایی است که جادوی بارگیری دکس ها، کدهای بومی و منابع اندروید از دایرکتوری mobile-install
روی دستگاه اتفاق می افتد.
بارگذاری واقعی با زیر کلاس بندی BaseDexClassLoader
پیاده سازی می شود و یک تکنیک کاملاً مستند است. این قبل از بارگیری هر یک از کلاسهای برنامه اتفاق میافتد، به طوری که کلاسهای برنامهای که در apk هستند را میتوان در فهرست راهنمای mobile-install
روی دستگاه قرار داد تا بدون adb install
بهروزرسانی شوند.
این باید قبل از بارگیری هر یک از کلاس های برنامه اتفاق بیفتد، به طوری که هیچ کلاس برنامه ای نیازی به حضور در apk. نیست که به این معنی است که تغییرات در آن کلاس ها نیاز به نصب مجدد کامل دارد.
این کار با جایگزین کردن کلاس Application
مشخص شده در AndroidManifest.xml
با برنامه خرد انجام می شود. هنگامی که برنامه راه اندازی می شود، این کنترل را به دست می گیرد و بارگیری کلاس و مدیر منابع را به طور مناسب در اولین لحظه (سازنده آن) با استفاده از بازتاب جاوا در قسمت داخلی چارچوب اندروید تغییر می دهد.
یکی دیگر از کارهایی که اپلیکیشن خرد انجام می دهد این است که کتابخانه های بومی نصب شده توسط موبایل نصب شده را در مکان دیگری کپی می کند. این امر ضروری است زیرا پیوند دهنده پویا نیاز به تنظیم بیت 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 و نسخه های بعدی به خوبی کار می کند، Dalvik یک اشکال دارد که باعث می شود اگر کد آن در چندین فایل .dex در موارد خاص توزیع شود، برای مثال، زمانی که حاشیه نویسی جاوا به روش خاصی استفاده می شود، فکر می کند که برنامه نادرست است. . تا زمانی که برنامه شما این اشکالات را برطرف نکند، باید با Dalvik نیز کار کند (اما توجه داشته باشید که پشتیبانی از نسخه های قدیمی اندروید دقیقاً تمرکز ما نیست)