כדי לספק את חוויית המשתמש הטובה ביותר, כדאי לבצע אופטימיזציה של האפליקציה כדי שהיא תהיה קטנה ומהירה ככל האפשר. כלי האופטימיזציה של האפליקציות שלנו, שנקרא R8, מייעל את האפליקציה על ידי הסרת קוד ומשאבים שלא נמצאים בשימוש, כתיבה מחדש של קוד כדי לבצע אופטימיזציה של ביצועי זמן הריצה ועוד. למשתמשים שלכם, המשמעות היא:
- זמן הפעלה מהיר יותר
- צמצום השימוש בזיכרון
- שיפורים בביצועי העיבוד והזמן הריצה
- פחות מקרי ANR
סקירה כללית על אופטימיזציה של R8
קוד R8 משתמש בתהליך רב-שלבי כדי לבצע אופטימיזציה של האפליקציה מבחינת גודל ומהירות. בין הפעולות העיקריות:
כיווץ קוד (שידוע גם כ-tree shaking): R8 מזהה ומסיר קוד שלא ניתן להגיע אליו מהאפליקציה ומהתלות שלה בספריות. על ידי ניתוח נקודות הכניסה של האפליקציה (כמו
ActivitiesאוServicesשמוגדרים במניפסט), R8 יוצר גרף של קוד עם הפניות ומסיר כל מה שלא נשאר עם הפניות.אופטימיזציות לוגיות: R8 כותב מחדש את הקוד כדי לשפר את יעילות הביצוע ולהפחית את התקורה. בין הטכניקות העיקריות:
הוספת שורות קוד של שיטות: R8 מחליף אתר של קריאה לשיטה בגוף האמיתי של השיטה שנקראה. הפעולה הזו מבטלת את התקורה של קריאה לפונקציה ומאפשרת ל-R8 לבצע אופטימיזציות נוספות.
מיזוג מחלקות: R8 משלב קבוצות של מחלקות וממשקים למחלקה אחת. כך מצמצמים את מספר המחלקות באפליקציה, מפחיתים את העומס על הזיכרון ומשפרים את מהירות ההפעלה.
ערפול קוד (obfuscation) (שידוע גם כהקטנה): כדי להקטין את הגודל של קובץ ה-DEX, R8 מקצר את השמות של מחלקות, שדות ושיטות (לדוגמה,
com.example.MyActivityיכול להפוך ל-a.b.a).
החל מגרסה 8.12.0 של פלאגין של Android Gradle (AGP), R8 גם מבצע אופטימיזציה של משאבים כחלק משלבי האופטימיזציה שלו. מידע נוסף זמין במאמר בנושא כיווץ מקורות המידע בצורה אופטימלית.
הפעלת אופטימיזציה
כדי להפעיל את האופטימיזציה של האפליקציה, צריך להגדיר את isMinifyEnabled = true (לאופטימיזציה של הקוד) ואת isShrinkResources = true (לאופטימיזציה של המשאבים) בסקריפט הבנייה של האפליקציה release
build's ברמת האפליקציה, כמו שמוצג בקוד הבא. מומלץ להפעיל תמיד את שתי ההגדרות. מומלץ גם להפעיל את האופטימיזציה של האפליקציה רק בגרסה הסופית של האפליקציה שאתם בודקים לפני הפרסום – בדרך כלל בגרסת build להפצה – כי האופטימיזציות מאריכות את משך זמן של תהליך build של הפרויקט ויכולות להקשות על ניפוי הבאגים בגלל האופן שבו הן משנות את הקוד.
Kotlin
android { buildTypes { release { // Enables code-related app optimization. isMinifyEnabled = true // Enables resource shrinking. isShrinkResources = true proguardFiles( // Default file with automatically generated optimization rules. getDefaultProguardFile("proguard-android-optimize.txt"), ... ) ... } } ... }
Groovy
android { buildTypes { release { // Enables code-related app optimization. minifyEnabled = true // Enables resource shrinking. shrinkResources = true // Default file with automatically generated optimization rules. proguardFiles getDefaultProguardFile('proguard-android-optimize.txt') ... } } }
אופטימיזציה של כיווץ מקורות המידע כדי ליצור אפליקציות קטנות עוד יותר
בגרסה 8.12.0 של פלאגין של Android Gradle (AGP) מוצג כיווץ משאבים שעבר אופטימיזציה, שמטרתו לשלב אופטימיזציה של משאבים וקוד כדי ליצור אפליקציות קטנות ומהירות עוד יותר.
לפני האופטימיזציה של כיווץ מקורות המידע, Android Asset Packaging Tool (AAPT2) יצר כללי שמירה שטיפלו בכיווץ מקורות המידע בנפרד מהקוד, ולעתים קרובות שמרו על קוד או משאבים שלא הייתה אליהם גישה, או שהייתה הפניה הדדית ביניהם.
באמצעות אופטימיזציה של כיווץ מקורות המידע, מקורות המידע נחשבים כחלק מקוד התוכנית, ויוצרים את תרשים ההפניה. אם לא מתבצעת הפניה לאוסף של קוד או משאבים, הוא לא מוגן על ידי כלל שמירה, ואפשר להסיר אותו.
הפעלת כיווץ מקורות המידע הממוטב
כדי להפעיל את צינור הנתונים החדש והמשופר לכיווץ מקורות המידע בגרסה של AGP לפני 9.0.0, מוסיפים את הקוד הבא לקובץ gradle.properties של הפרויקט:
android.r8.optimizedResourceShrinking=true
אם אתם משתמשים ב-AGP 9.0.0 או בגרסה חדשה יותר, אתם לא צריכים להגדיר את android.r8.optimizedResourceShrinking=true. כיווץ מקורות המידע האופטימלי מופעל באופן אוטומטי כשמפעילים את isShrinkResources = true בתצורת ה-build.
אימות והגדרה של הגדרות האופטימיזציה של R8
כדי לאפשר ל-R8 להשתמש ביכולות האופטימיזציה המלאות שלו, צריך להסיר את השורה הבאה מקובץ gradle.properties של הפרויקט, אם היא קיימת:
android.enableR8.fullMode=false # Remove this line from your codebase.
שימו לב שהפעלת אופטימיזציה של אפליקציות מקשה על ההבנה של עקבות מחסנית, במיוחד אם R8 משנה את השמות של מחלקות או שיטות. כדי לקבל עקבות מחסנית שתואמות לקוד המקור, אפשר לעיין במאמר בנושא שחזור עקבות המחסנית המקוריות.
אם R8 מופעל, כדאי גם ליצור פרופילים להפעלה כדי לשפר עוד יותר את ביצועי ההפעלה.
אם הפעלתם אופטימיזציה של אפליקציות והיא גורמת לשגיאות, הנה כמה אסטרטגיות לפתרון הבעיות:
- הוספת כללי שמירה כדי להשאיר חלק מהקוד ללא שינוי.
- יישום הדרגתי של אופטימיזציות.
- כדאי לעדכן את הקוד כדי להשתמש בספריות שמתאימות יותר לאופטימיזציה.
אם אתם רוצים לייעל את מהירות ה-build, במאמר הגדרת אופן ההפעלה של R8 מוסבר איך להגדיר את R8 בהתאם לסביבה שלכם.
שינויים בהתנהגות של גרסאות AGP ו-R8
בטבלה הבאה מפורטות התכונות העיקריות שהוצגו בגרסאות שונות של פלאגין של Android Gradle (AGP) ושל R8 compiler.
| גרסת AGP | תכונות חדשות |
|---|---|
| 9.1 |
מחלקות שנארזות מחדש כברירת מחדל: R8 אורז מחדש מחלקות (מעביר אותן לחבילה ללא שם, ברמה העליונה) כדי לדחוס עוד יותר את קובץ ה-DEX, וכך אין צורך לציין את האפשרות -repackageclasses. מידע על אופן הפעולה של האפשרות הזו ועל אופן ההשבתה שלה זמין במאמר בנושא אפשרויות גלובליות.
|
| 9.0 |
כיווץ מקורות מידע שעבר אופטימיזציה: מופעל כברירת מחדל (נשלט באמצעות android.r8.optimizedResourceShrinking). כיווץ מקורות מידע שעבר אופטימיזציה עוזר לשלב כיווץ מקורות מידע עם פייפליין אופטימיזציית הקוד, וכך ליצור אפליקציות קטנות ומהירות יותר. התהליך הזה מזהה ומסיר משאבים שההפניה אליהם נעשית רק מקוד שלא נמצא בשימוש, כי הוא מבצע אופטימיזציה של הקוד ושל ההפניות למשאבים בו-זמנית. זהו שיפור משמעותי לעומת תהליכי האופטימיזציה הנפרדים הקודמים.האפשרות הזו שימושית במיוחד לאפליקציות שמשתפות משאבים וקוד משמעותיים בין קטגוריות שונות של גורמי צורה, עם שיפורים שנמדדו של יותר מ-50% בגודל האפליקציה. הקטנת הגודל מאפשרת הורדות קטנות יותר, התקנות מהירות יותר וחוויית משתמש טובה יותר עם הפעלה מהירה יותר, רינדור משופר ופחות שגיאות ANR. סינון כללים של ספריות: הוסר התמיכה באפשרויות גלובליות (לדוגמה, -dontobfuscate) בכללי צרכן של ספריות, והאפליקציות יסננו אותן. מידע נוסף מופיע במאמר בנושא הוספת אפשרויות גלובליות.בדיקות של ערכים ריקים (null) ב-Kotlin: אופטימיזציה כברירת מחדל (נשלטת באמצעות -processkotlinnullchecks). בגרסה הזו בוצעו גם שיפורים משמעותיים במהירות ה-build. מידע נוסף זמין במאמר בנושא הגדרות גלובליות להוספת אופטימיזציה.אופטימיזציה של חבילות ספציפיות: אפשר להשתמש ב- packageScope כדי לבצע אופטימיזציה של חבילות ספציפיות. התמיכה הזו ניסיונית. מידע נוסף זמין במאמר בנושא אופטימיזציה של חבילות שצוינו באמצעות packageScope.אופטימיזציה כברירת מחדל: הפסקנו לתמוך ב- getDefaultProguardFile("proguard-android.txt") כי הוא כולל את -dontoptimize, ומומלץ להימנע משימוש בו. במקום זאת, צריך להשתמש ב-"proguard-android-optimize.txt". אם אתם צריכים להשבית את האופטימיזציה באפליקציה באופן גלובלי, צריך להוסיף את הדגל באופן ידני לקובץ Proguard.
|
| 8.12 |
כיווץ מקורות המידע: נוספה תמיכה ראשונית (ההגדרה מושבתת כברירת מחדל. הפעלה של שימוש ב-isShrinkResources). כיווץ מקורות המידע פועל בשילוב עם R8 כדי לזהות ולהסיר משאבים לא בשימוש בצורה יעילה.Logcat retracing: Support for automatic retracing in the Android Studio Logcat window. |
| 8.6 |
שיפורים באיתור מקורות: כולל איתור מקורות לפי שם הקובץ ומספר השורה כברירת מחדל לכל הרמות של minSdk (בעבר נדרשה רמה של minSdk 26 ומעלה בגרסה 8.2).עדכון R8 עוזר לוודא שניתן לקרוא בקלות ובבירור את עקבות המחסנית (stack traces) מגרסאות obfuscated. בגרסה הזו שופר המיפוי של מספרי השורות וקבצי המקור, כך שקל יותר לכלים כמו Logcat ב-Android Studio לאתר באופן אוטומטי את מקור הקוד המקורי של קריסות. |
| 8.0 |
מצב מלא כברירת מחדל: המצב המלא של R8 מספק אופטימיזציה חזקה משמעותית. ההגדרה הזו מופעלת כברירת מחדל. אפשר לבטל את ההצטרפות באמצעות android.enableR8.fullMode=false.
|
| 7.0 |
מצב מלא זמין: השקנו את המצב הזה כתכונה אופציונלית באמצעות android.enableR8.fullMode=true. במצב מלא, המערכת מבצעת אופטימיזציות חזקות יותר על ידי הנחות מחמירות יותר לגבי האופן שבו הקוד משתמש בהשתקפות ובתכונות דינמיות אחרות. השימוש ב-ProGuard מקטין את גודל האפליקציה ומשפר את הביצועים, אבל יכול להיות שיהיה צורך להוסיף כללי שמירה כדי למנוע את הסרת הקוד הנדרש.
|