כדי להפעיל אופטימיזציה של אפליקציות, צריך להשתמש בספריות שתואמות לאופטימיזציה של Android. אם ספרייה לא מוגדרת לביצוע אופטימיזציה ל-Android – לדוגמה, אם היא משתמשת בהשתקפות בלי לאגד כללי שמירה משויכים – יכול להיות שהיא לא מתאימה לאפליקציה ל-Android. בדף הזה נסביר למה ספריות מסוימות מתאימות יותר לביצוע אופטימיזציה של אפליקציות, ונציע טיפים כלליים שיעזרו לכם לבחור.
עדיפות ליצירת קוד על פני השתקפות
באופן כללי, כדאי לבחור בספריות שמשתמשות ביצירת קוד (codegen) במקום ברפלקציה. באמצעות codegen, האופטימיזטור יכול לקבוע בקלות רבה יותר איזה קוד נמצא בשימוש בפועל במהלך זמן הריצה ואיזה קוד ניתן להסיר. לפעמים קשה לדעת אם ספרייה משתמשת ב-codegen או ב-reflection, אבל יש כמה סימנים – אפשר לעיין בטיפים לקבלת עזרה.
מידע נוסף על codegen לעומת רפלקציה זמין במאמר אופטימיזציה לכותבי ספריות.
טיפים כלליים לבחירת ספריות
בעזרת הטיפים הבאים תוכלו לוודא שהספריות שלכם תואמות לאופטימיזציה של האפליקציה.
בדיקה של בעיות באופטימיזציה
כשאתם שוקלים להשתמש בספרייה חדשה, כדאי לעיין במעקב הבעיות של הספרייה ובדיונים באינטרנט כדי לבדוק אם יש בעיות שקשורות לצמצום או להגדרת אופטימיזציה של האפליקציה. אם כן, כדאי לנסות למצוא חלופות לספרייה הזו. חשוב לזכור:
- ספריות AndroidX וספריות כמו Hilt פועלות היטב עם אופטימיזציה של אפליקציות כי הן משתמשות ב-codegen במקום ב-reflection. כשהם משתמשים בהשתקפות, הם מספקים כללי שמירה מינימליים כדי לשמור רק את הקוד הנדרש.
- ספריות שרשור לעיתים קרובות משתמשות בהשתקפות כדי להימנע משימוש בקוד סטנדרטי בזמן יצירת אובייקטים או שרשור אותם. במקום שיטות שמבוססות על רפלקציה (כמו Gson ל-JSON), כדאי לחפש ספריות שמשתמשות ב-codegen כדי להימנע מהבעיות האלה. למשל, אפשר להשתמש במקום זאת ב-Kotlin Serialization.
- אם אפשר, כדאי להימנע משימוש בספריות שכוללות כללי שמירה ברמת החבילה. כללי שמירה ברמת החבילה יכולים לעזור לפתור שגיאות, אבל בסופו של דבר צריך לשפר את הכללים הרחבים כדי לשמור רק את הקוד הנדרש. למידע נוסף, קראו את המאמר הטמעת אופטימיזציות באופן מצטבר.
הפעלת אופטימיזציה אחרי הוספת ספרייה חדשה
כשאתם מוסיפים ספרייה חדשה, כדאי להפעיל את האופטימיזציה לאחר מכן ולבדוק אם יש שגיאות. אם יש שגיאות, מחפשים חלופות לספרייה הזו או כותבים כללי שמירה. אם ספרייה מסוימת לא תואמת לאופטימיזציה, צריך לדווח על באג בספרייה הזו.
הכללים מצטברים
חשוב לזכור שכללי השמירה הם מצטברים. כלומר, אי אפשר להסיר כללים מסוימים שכוללים יחסי תלות בספרייה, והם עשויים להשפיע על הידור של חלקים אחרים באפליקציה. לדוגמה, אם ספרייה כוללת כלל להשבתת אופטימיזציות של קוד, הכלל הזה משבית את האופטימיזציות בכל הפרויקט.
בדיקה של שימוש בהשתקפות (מתקדם)
יכול להיות שתוכלו לדעת אם ספרייה משתמשת בהשתקפות על ידי בדיקת הקוד שלה. אם הספרייה משתמשת בהשתקפות (reflection), צריך לבדוק שהיא מספקת כללי שמירה משויכים. סביר להניח שספרייה משתמשת בהשתקפות אם היא מבצעת את הפעולות הבאות:
- משתמשת בכיתות או ב-methods מחבילות
kotlin.reflect
אוjava.lang.reflect
- נעשה שימוש בפונקציות
Class.forName
אוclassLoader.getClass
- קריאת הערות בזמן הריצה, לדוגמה אם הקוד שומר ערך של הערה באמצעות
val value = myClass.getAnnotation()
אוval value = myMethod.getAnnotation()
ואז מבצע משהו באמצעותvalue
קריאה לשיטות באמצעות שם השיטה כמחרוזת, לדוגמה:
// Calls the private `processData` API with reflection myObject.javaClass.getMethod("processData", DataType::class.java) ?.invoke(myObject, data)
סינון של כללי שמירה לא תקינים (מתקדם)
כדאי להימנע משימוש בספריות עם כללי שמירה ששומרים קוד שצריך להסיר. עם זאת, אם אתם חייבים להשתמש בהם, תוכלו לסנן את הכללים כפי שמתואר בקוד הבא:
// If you're using AGP 8.4 and higher
buildTypes {
release {
optimization.keepRules {
it.ignoreFrom("com.somelibrary:somelibrary")
}
}
}
// If you're using AGP 7.3-8.3
buildTypes {
release {
optimization.keepRules {
it.ignoreExternalDependencies("com.somelibrary:somelibrary")
}
}
}
מקרה לדוגמה: למה Gson קורס עם אופטימיזציות
Gson היא ספריית שרשור (serialization) שגורמת לבעיות רבות באופטימיזציה של אפליקציות, כי היא משתמשת הרבה בהשתקפות (reflection). קטע הקוד הבא מראה איך משתמשים ב-Gson בדרך כלל, ויכול לגרום בקלות לקריסות במהלך זמן הריצה. שימו לב שכשמשתמשים ב-Gson כדי לקבל רשימה של אובייקטים מסוג User, לא קוראים למבנה ה-constructor או מעבירים מפעל לפונקציה fromJson()
. יצירת כיתות שהוגדרו על ידי האפליקציה או שימוש בהן ללא אחת מהאפשרויות הבאות יכולות להעיד על כך שספרייה מסוימת משתמשת בהשתקפות פתוחה:
- מחלקת אפליקציה שמטמיעה ספרייה, או ממשק או מחלקה רגילים
- פלאגין ליצירת קוד כמו KSP
class User(val name: String)
class UserList(val users: List<User>)
// This code runs in debug mode, but crashes when optimizations are enabled
Gson().fromJson("""[{"name":"myname"}]""", User::class.java).toString()
כש-R8 מנתח את הקוד הזה ולא רואה את UserList
או את User
שנוצרו במקום כלשהו, הוא יכול לשנות את השמות של השדות או להסיר קונסטרוקטורים שנראה שלא נעשה בהם שימוש, וכתוצאה מכך האפליקציה תקרוס. אם אתם משתמשים בספריות אחרות בדרכים דומות, כדאי לבדוק שהן לא יפריעו לאופטימיזציה של האפליקציה. אם הן כן מפריעות, כדאי להימנע מהן.
חשוב לדעת שגם Room וגם Hilt יוצרים סוגים שהוגדרו באפליקציה, אבל משתמשים ב-codegen כדי למנוע צורך ברפלקציה.