פיתוח חוזר מהיר ל-Android
בדף הזה מתואר אופן הפעולה המהיר של
bazel mobile-install
ב-Android. הוא מתאר את היתרונות של הגישה הזו לעומת
האתגרים של שיטת התקנת האפליקציות המסורתית.
סיכום
כדי להתקין שינויים קטנים באפליקציה ל-Android במהירות רבה, מבצעים את הפעולות הבאות:
- מוצאים את הכלל
android_binary
של האפליקציה שרוצים להתקין. - השבתה של Proguard על ידי הסרת המאפיין
proguard_specs
. - יש להגדיר את המאפיין
multidex
לערךnative
. - יש להגדיר את המאפיין
dex_shards
לערך10
. - מחברים את המכשיר המופעל באמצעות ART (ולא Davik) ב-USB ומפעילים אותו לניפוי באגים.
- מקצה
bazel mobile-install :your_target
. הפעלת האפליקציה תהיה מעט איטית יותר מהרגיל. - עורכים את הקוד או את המשאבים של Android.
- מקצה
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
מופעלת באופן אוטומטי
במקרה של ספק, אפשר לעיין בדוגמה או ליצור איתנו קשר.
מבוא
אחד מהמאפיינים החשובים ביותר של כלי פיתוח הוא מהירות: יש עולם של הבדלים בין שינוי הקוד לבין הצגתו תוך שנייה אחת. בנוסף, לפעמים צריך להמתין שעות עד לקבלת משוב שיעזור לך להבין אם השינויים שביצעת מניבים את התוצאות הרצויות.
למרבה הצער, כלי הכלים המסורתי של Android לבניית .APK כרוך בצעדים מונוליטיים רבים, ברצף, ובכל השלבים האלו יש לבצע כדי לבנות אפליקציה ל-Android. ב-Google, המתנה של חמש דקות לבניית שינוי בשורה אחת לא הייתה חריגה מפרויקטים גדולים יותר כגון מפות Google.
bazel mobile-install
משפרת את ההתפתחות של מערכת Android ב-Android במהירות רבה יותר,
על ידי שימוש בשילוב של גיזום שינויים, גרימת עבודה, ומניפולציה חכמה
של הפנימיות של Android, והכל מבלי לשנות את הקוד של האפליקציה שלך.
בעיות בהתקנת האפליקציה המסורתית
יש כמה בעיות ביצירה של אפליקציית Android, כולל:
מתבצע חילוץ. כברירת מחדל, "dx" מופעל בדיוק פעם אחת במסגרת ה-build ולא ידוע לו איך לעשות שימוש חוזר ביצירה מגרסאות קודמות: הוא מבטל שוב את כל השיטות, למרות ששיטה אחת בלבד שונתה.
העלאת נתונים למכשיר. adb לא משתמשת ברוחב הפס המלא של חיבור USB 2.0, ואפליקציות העלאה גדולות יותר עשויות להימשך זמן רב. האפליקציה כולה מועלה, גם אם רק חלקים קטנים השתנו, למשל, משאב או שיטה אחת, כך שמדובר בצוואר בקבוק גדול.
אוסף עם קוד מקורי. Android L השיק את זמן ה-ART, זמן ריצה חדש של Android, שאוסף אפליקציות מראש, במקום להרכיב אותן בזמן אמת, כמו Dalvik. פעולה זו מאפשרת אפליקציות מהירות הרבה יותר בעלות של זמן התקנה ארוך יותר. זו שיטה טובה למשתמשים, כי הם בדרך כלל מתקינים אפליקציה פעם אחת ומשתמשים בה הרבה פעמים, אבל התוצאה היא התפתחות איטית יותר שבה האפליקציה מותקנת הרבה פעמים, וכל גרסה מופעלת כמה פעמים לכל היותר.
הגישה של bazel mobile-install
bazel mobile-install
ניתן לבצע את השיפורים הבאים:
הסרת דקים קעורים. אחרי שבנה את קוד Java של האפליקציה, Bazel חותכת את קובצי הכיתה לחלקים שווים בגודלה ומפעילה אותם בנפרד ב-
dx
.dx
לא מופעל בפיצולים שלא השתנו מאז ה-build האחרון.העברת קבצים מצטברת. משאבי Android, קובצי .dex וספריות ם מקוריות מוסרים מה- .APK הראשי ונשמרים בספרייה נפרדת להתקנה. כך ניתן לעדכן משאבים וקוד Android באופן עצמאי בלי להתקין מחדש את האפליקציה כולה. לכן, העברת הקבצים לוקחת פחות זמן, ורק קובצי ה-.dex שהשתנו והוחרגו במכשיר.
המערכת טוענת חלקים מהאפליקציה מחוץ ל-APK. אפליקציית Stub קטנה
הסרת שברים
יצירת שבירת מקטעים פשוטה היא סבירה: אחרי שיוצרים את קובצי ה- צ'אט .כלי מחתוך אותם לקובצי .tar קטנים בערך זהה ואז מפעיל dx
בקבצים שהשתנו מאז הבנייה הקודמת. הלוגיקה
שקובעת איזה מקטע לפלחים אינה ספציפית ל-Android: היא רק משתמשת
באלגוריתם הגיזום הכללי של Bazel.
הגרסה הראשונה של אלגוריתם הפיצול פשוט קבעה סדר בקובצי ה-.class בסדר אלפביתי, ולאחר מכן חתוכה את הרשימה לחלקים שווים, אבל כתוצאה מכך הסיווג לא היה אופטימלי: אם נוספה או הוסרה כיתה (גם אם היא מקוננת או אנונימית), היא תגרום לשינוי כל הכיתות בסדר אלפביתי. לכן הוחלט לחתוך חבילות Java במקום כיתות בודדות. כמובן שהפעולה הזו גורמת לפיצול של הרבה מקטעים אם מוסיפים או מסירים חבילה חדשה, אבל זה הרבה פחות מהוספה או הסרה של כיתה אחת.
מספר הפיצולים נקבע על ידי קובץ ה-BUILD (באמצעות המאפיין android_binary.dex_shards
). בעולם אידיאלי, Bazel
קבעה באופן אוטומטי כמה פלחים בדרך כלל, השביל המתוק הוא בין 10 ל-50 פיצולים.
העברת קובץ מצטבר
אחרי שתיצרו את האפליקציה, השלב הבא הוא להתקין אותה, עם מאמץ מינימלי. ההתקנה מורכבת מהשלבים הבאים:
- התקנת קובץ ה- .APK (בדרך כלל באמצעות
adb install
) - העלאת קובצי ה-dex., המשאבים ל-Android והספריות המותאמות לספריית ההתקנה בנייד
אין עלייה מצטברת בשלב הראשון: האפליקציה מותקנת או לא. בשלב הזה, Bazel מסתמכת על המשתמש כדי לציין אם היא צריכה לבצע את השלב הזה דרך האפשרות של שורת הפקודה --incremental
, מאחר שהיא לא יכולה
לקבוע בכל המקרים אם יש צורך.
בשלב השני, מתבצעת השוואה בין הקבצים של האפליקציה ב-build לבין קובץ המניפסט במכשיר שבו מצוין אילו קובצי אפליקציה נמצאים במכשיר וכן את סיכום החיובים שלהם. קבצים חדשים יועלו למכשיר, כל הקבצים שהשתנו יעודכנו, וקבצים שהוסרו יימחקו מהמכשיר. אם המניפסט לא קיים, ההנחה היא שצריך להעלות כל קובץ.
שימו לב שניתן להטעות את אלגוריתם ההתקנה המצטבר על ידי שינוי קובץ במכשיר, אבל לא את סיכום הביקורת במניפסט. ניתן היה להגן עליה על ידי חישוב סכום הביקורת של הקבצים במכשיר, אבל נקבע כי לא כדאי להגדיל את זמן ההתקנה.
אפליקציית Stub
אפליקציית Stub היא הקסם לטעינת טעינה של ה-dexs, הקוד המקורי ומשאבי Android מספריית mobile-install
במכשיר.
הטעינה בפועל מיושם על ידי סיווג משנה BaseDexClassLoader
והיא טכניקה מתועדת באופן סביר. השמירה הזו מתרחשת לפני טעינת כל הכיתות של האפליקציה, כך שכל מחלקה של אפליקציה שנמצאת ב-APK נמצאת בספרייה של mobile-install
במכשיר, כדי שניתן יהיה לעדכן אותה ללא adb install
.
צריך לעשות זאת לפני שכל הכיתות של האפליקציה נטענות, כך שמחלקה של האפליקציה לא צריכה להיות באפליקציה. כלומר, כדי לבצע שינויים בכיתות האלה צריך להתקין מחדש באופן מלא.
ניתן לעשות זאת על ידי החלפת מחלקת Application
שצוינה ב-AndroidManifest.xml
באפליקציית stub. אפשרות זו קובעת מתי האפליקציה מופעלת, ומתאימה את הכלי לטעינת כיתות
ואת מנהל המשאבים בהתאם לרגע המוקדם ביותר (הבונה שלו) באמצעות שיקוף Java בפנים הפנימי של מסגרת Android.
דבר נוסף שאפליקציית ה-stub עושה הוא להעתיק את הספריות המקוריות שהותקנו על ידי התקנה בנייד למיקום אחר. ההרשאה הזו הכרחית
כי כדי ליצור את הקישור הדינמי צריך להיות מוגדר לקובץ X
, ואי אפשר לעשות זאת בכל מיקום שנגיש באמצעות adb
שאינו ברמה הבסיסית (root).
לאחר השלמת כל הפעולות האלה, אפליקציית stub תיצור את המחלקה Application
בפועל ותשנה את כל ההפניות לעצמו לאפליקציה
של עצמו במסגרת Android.
תוצאות
ביצועים
באופן כללי, הפעולה של bazel mobile-install
מזרזת את קצב הבנייה של פי 4 עד פי 10
וההתקנה של אפליקציות גדולות מתבצעת אחרי שינוי קטן.
המספרים הבאים מחושבים עבור כמה מוצרי Google:
כמובן ששינוי זה תלוי בטבעו של השינוי: ההידור מחדש לאחר החלפת הספרייה הבסיסית נמשך זמן רב יותר.
מגבלות
הטריקים שאפליקציית stub משחקת לא פועלת בכל המקרים. המקרים הבאים מדגישים היכן הוא לא פועל כמצופה:
בזמן העברה של
Context
לכיתהApplication
ב-ContentProvider#onCreate()
. השיטה הזו נקראת במהלך ההפעלה של האפליקציה לפני שיש לנו אפשרות להחליף את המכונה של המחלקהApplication
, ולכןContentProvider
עדיין יתייחס לאפליקציית ה-stub במקום האמיתי. אין ספק שמדובר בבאג, כי אין כוונה להוריד את הערך שלContext
כך, אבל נראה שזה קורה בכמה אפליקציות ב-Google.מקורות המידע שהותקנו על ידי
bazel mobile-install
זמינים רק מתוך האפליקציה. אם אפליקציות אחרות ניגשות לאפליקציה דרךPackageManager#getApplicationResources()
, המשאבים האלה יהיו מההתקנה האחרונה שלא נוספה.מכשירים שאינם מפעילים את ART. אפליקציית stub פועלת היטב ב-Froyo ואילך, ויש בה באג שטוען שהאפליקציה שגויה אם הקוד שלה מחולק למספר קובצי .dex במקרים מסוימים, למשל, כאשר הערות Java משמשות באופן ספציפי. כל עוד האפליקציה לא מדגימה את הבאגים, היא אמורה לפעול עם Davik, עם זאת, (שימו לב שהתמיכה בגרסאות ישנות של Android אינה תואמת בדיוק את המיקוד שלנו).