כברירת מחדל, R8 מבצע הרבה אופטימיזציות כדי לשפר את הביצועים והגודל, אבל יכול להיות שהאופטימיזציות לא יפעלו באפליקציה שלכם באופן מיידי. אם אתם מפעילים את R8 (או מפעילים את המצב המלא) באפליקציה גדולה בפעם הראשונה, נסו להטמיע אופטימיזציות באופן מצטבר: משביתים את ההסתרה באופן זמני ומפעילים את R8 בחלקים של הקוד בכל פעם, במקום בכל הקוד באפליקציה. מומלץ להשתמש בגישה המצטברת הזו במהלך הפיתוח המקומי, אבל אפשר להשתמש בה גם במהלך בדיקות בקרת איכות פנימיות או אפילו בסביבת הייצור כהשקה הדרגתית. השלבים המדויקים שתבצעו תלויים בלוח הזמנים הרצוי ובמידת האמון שלכם בבדיקה שלפני ההשקה.
הגבלת האופטימיזציות
R8 מבצע סוגים רבים של אופטימיזציות, כולל הסרה של קוד, כתיבת מחדש של קוד והסרה של משאבים. ריכזנו כאן כמה תיאורים ברמה גבוהה של סוגי האופטימיזציה:
- כיווץ קוד (או 'ניעור עץ'): הסרת קוד ללא הפניה
- ערפול קוד (או צמצום מזהה): קיצור השמות של המחלקות והשיטות
- אופטימיזציה: כתיבת קוד מחדש, למשל הטמעה בקוד (inline)
כדי לצמצם את הסיכוי לשגיאות, מומלץ להתחיל בהפעלה של חלק מהאופטימיזציות האלה.
הפעלת רעידת העץ בלבד
כיווץ קוד, שנקרא גם 'ניעור עץ', מסיר קוד שנראה שאין אליו הפניה. מומלץ להתחיל רק עם 'ניפוי עצים', כי זו השיטה הפשוטה ביותר.
כדי להפעיל רק את 'ניפוי עצים', מוסיפים את הקטע הבא לקובץ proguard-rules.pro
כדי להשבית את סוגי האופטימיזציה האחרים. חשוב להשבית את ההסתרה כי כך קל יותר לקרוא את נתוני המעקב אחר סטאק.
-dontobfuscate // Use temporarily to turn off identifier minification
-dontoptimize // Use temporarily to turn off optimization
בסופו של דבר, לא כדאי לשלוח את ההגדרה הזו, כי היא מגבילה באופן משמעותי את היכולת של R8 לבצע אופטימיזציה של הקוד. עם זאת, זוהי נקודת התחלה מצוינת כשמתחילים להשתמש ב-R8 בפעם הראשונה בקוד בסיס גדול שיש בו בעיות שצריך לתקן.
שימוש במצב תאימות
כברירת מחדל, R8 פועל במצב מלא. כשמפעילים את המצב המלא, הביצועים משתפרים באופן משמעותי והקובץ קטן יותר, אבל אפשר להשבית אותו באופן זמני ולהשתמש במקום זאת במצב תאימות כשמפעילים את המינימיזציה בפעם הראשונה.
כדי להשתמש במצב תאימות, צריך להשתמש בהגדרה הבאה בקובץ gradle.properties
:
android.enableR8.fullMode = false // Use temporarily to disable full mode
מפעילים את שאר האופטימיזציות
אחרי שתאשרו שהתכונה 'ניעור עצים' פועלת באפליקציה, תוכלו להסיר את ההגדרות הקודמות כדי להפעיל מחדש את הטשטוש, האופטימיזציה והמצב המלא של R8. חשוב לזכור שהערפול עלול להקשות על ניפוי הבאגים, ולכן מומלץ לטפל קודם בבעיות של ניעור העץ.
מידע נוסף על הסרת האובסופלציה של דוחות קריסה זמין במאמר 'שחזור של דוח הקריסה המקורי'.
הגבלת היקף האופטימיזציה
ב-build עם אופטימיזציה מלאה מתבצעת אופטימיזציה של כל הקוד בכל ספרייה ובכל חבילת קוד, ולכן בדרך כלל נתקלים בבעיות ב-R8 בפעם הראשונה שמפעילים אותו. אם נתקלתם בבעיה באופטימיזציה בחלק מסוים באפליקציה, אל תשביתו את R8 לגמרי, אחרת תאבדו את היתרונות בכל שאר החלקים. במקום זאת, כדאי להשבית את R8 באופן זמני רק בחלקים באפליקציה שגורמים לבעיות.
שימוש בכללי שמירה ברמת החבילה
מומלץ להשתמש בכללי שמירה ברמת החבילה כדי להשבית את R8 באופן זמני בחלקים מסוימים באפליקציה. תמיד כדאי לחזור ולתקן את בעיות האופטימיזציה האלה מאוחר יותר. בדרך כלל, זהו פתרון זמני לבעיות באזורים בעייתיים.
לדוגמה, אם חלק מהאפליקציה משתמש ב-Gson באופן נרחב וגורם לבעיות באופטימיזציה, התיקון האידיאלי הוא להוסיף עוד כללי שמירה ממוקדים או לעבור לפתרון codegen. עם זאת, כדי לבטל את החסימה של האופטימיזציה של שאר האפליקציה, אפשר להציב את הקוד שמגדיר את סוגי ה-Gson בחבילת משנה ייעודית ולהוסיף כלל כזה לקובץ proguard-rules.pro
:
-keep class com.myapp.json.** { *; }
אם בספרייה מסוימת שבה אתם משתמשים יש השתקפות לרכיבים פנימיים, תוכלו להוסיף כלל שמירה דומה לכל הספרייה. תצטרכו לבדוק את הקוד או את קובץ ה-JAR/AAR של הספרייה כדי למצוא את החבילה המתאימה לשמירה. שוב, לא מומלץ לשמור על המצב הזה לטווח ארוך, אבל הוא יכול לבטל את החסימה של האופטימיזציה של שאר האפליקציה:
-keep class com.somelibrary.** { *; }
הסרת כללי שמירה ברמת החבילה
אחרי שהאפליקציה פועלת כמו שצריך עם כללי שמירה ברמת החבילה, כדאי לחזור אחורה ולהוסיף כללי שמירה ממוקדים או להסיר את השימוש בהשתקפות או את הספרייה שדרכם נדרש כלל השמירה מלכתחילה.
לדוגמה, ב-AndroidX נהוג מאוד לשמור את כל הכללים שמרחיבים מחלקה מסוימת כדי לשמור רק על הכיתות הרלוונטיות. באופן כללי, יש לטרגט את ההשתקפות רק למחלקות או לשיטות שמרחיבות מחלקות מופשטות מסוימות, מטמיעות ממשקים מסוימים או למחלקות עם הערה ספציפית בסביבת זמן ריצה. כל אחת מהדרכים האלה נתמכת להגדרת כללי שמירה, כך שלא תצטרכו להגדיר כללי שמירה ברמת החבילה באפליקציה הסופית שעברה אופטימיזציה מלאה.