כשמפעילים אופטימיזציה של אפליקציות, התנהגות ברירת המחדל של הכלי Optimizer שונה בגרסאות שונות של R8.
- ב-DSL המעודכן שזמין מ-AGP 9.3 ואילך, צמצום המשאבים מופעל כברירת מחדל כשהאופטימיזציה מופעלת. שימו לב שעדיין יש תמיכה ב-DSL מדור קודם, שנדרשת בו אופטימיזציה של קוד ומשאבים כדי להפעיל אותו באופן מובהק.
בגרסאות קודמות ל-AGP 9.3, ההגדרה
isShrinkResources = trueמורה לאופטימיזציה להסיר משאבים שלא נמצאים בשימוש, וכך עוזרת להקטין את גודל האפליקציה. צמצום המשאבים פועל רק בשילוב עם צמצום הקוד, ולכן אם אתם מבצעים אופטימיזציה של משאבים, צריך להגדיר גם אתisMinifyEnabled = true.
AGP 9.3+ (Kotlin)
buildTypes {
release {
optimization {
enable = true // Enables code and resource optimizations.
}
}
}
AGP 9.3+ (Groovy)
buildTypes {
release {
optimization {
enable = true // Enables code and resource optimizations.
}
}
}
DSL מדור קודם (Kotlin)
buildTypes {
release {
isMinifyEnabled = true
isShrinkResources = true
...
}
}
DSL מדור קודם (Groovy)
buildTypes {
release {
minifyEnabled = true
shrinkResources = true
...
}
}
אם רוצים לשמור או למחוק משאבים ספציפיים, צריך ליצור קובץ XML keep במשאבי הפרויקט, למשל res/raw/keep_my_package.xml. קובץ ה-Keep כולל את הרכיבים הבאים:
-
<resources>tag – מכיל את כל רכיבי משאבי הצאצא ואת המאפיינים keep/discard. - מאפיין
tools:keep– מקבל רשימה מופרדת בפסיקים של שמות משאבים שמזהים משאבים שצריך לשמור - מאפיין
tools:discard– מקבל רשימה מופרדת בפסיקים של שמות משאבים שמזהים משאבים שצריך להשליך
אפשר להשתמש בכוכבית כתו כללי לחיפוש כדי להפנות לכמה משאבים באותה תיקייה, למשל:
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"
tools:keep="@layout/l_used*_c,@layout/l_used_a,@layout/l_used_b*"
tools:discard="@layout/unused2" />
יכול להיות שייראה לכם מיותר לציין אילו משאבים להשליך, במקום למחוק אותם, אבל השלכת משאבים יכולה להיות שימושית כשמשתמשים בגרסאות שונות של build.
טירגוט של וריאציות ספציפיות של גרסאות Build
כדי להסיר משאבים רק בחלק מווריאנטים של ה-build, מעבירים את כל המשאבים לספריית הפרויקט המשותפת, ואז יוצרים קובץ keep_my_package_build_variant.xml שונה לכל וריאנט build בספריית המשאבים של הווריאנט. בקובץ keep, מציינים באופן ידני משאבים להסרה כשמשאב מסוים נראה בשימוש בקוד (ולכן לא מוסר על ידי הכלי לכיווץ), אבל אתם יודעים שהוא לא ישמש בפועל לווריאנט build הנתון.
הסרה של משאבים חלופיים שלא בשימוש
האופטימיזציה מסירה רק משאבים שלא מוזכרים בקוד האפליקציה, כלומר היא לא מסירה משאבים חלופיים להגדרות שונות של המכשיר.
כדי להסיר קובצי משאבים חלופיים שהאפליקציה לא צריכה, משתמשים במאפיין resConfigs של Android Gradle בקובץ build.gradle של מודול האפליקציה.
לדוגמה, אם אתם משתמשים בספרייה שכוללת משאבי שפה (כמו Google Play Services), האפליקציה שלכם כוללת את כל מחרוזות השפה המתורגמות להודעות בספריות האלה, גם אם שאר האפליקציה מתורגמת לאותן שפות וגם אם לא. כדי לשמור רק את השפות שהאפליקציה תומכת בהן באופן רשמי, צריך לציין את השפות האלה באמצעות המאפיין resConfigs.
כל המשאבים של שפות שלא צוינו יוסרו.
בקטעי הקוד הבאים אפשר לראות איך מגבילים את משאבי השפה לאנגלית ולצרפתית בלבד:
android {
defaultConfig {
...
resourceConfigurations.addAll(listOf("en", "fr"))
}
}
או
android {
defaultConfig {
...
resConfigs "en", "fr"
}
}
כשמפרסמים אפליקציה בפורמט Android App Bundle (AAB), כברירת מחדל, רק השפות שהוגדרו במכשיר של המשתמש מורדות כשהמשתמש מתקין את האפליקציה. באופן דומה, רק משאבים שתואמים לצפיפות המסך של המכשיר וספריות מקוריות שתואמות ל-ABI של המכשיר נכללים בהורדה. מידע נוסף זמין במאמר הפעלה מחדש או השבתה של סוגים של חבילות APK להגדרות.
באפליקציות מדור קודם שמופצות עם חבילות APK (שנוצרו לפני אוגוסט 2021), אפשר להתאים אישית את צפיפות המסך או את משאבי ה-ABI שייכללו בחבילת ה-APK על ידי יצירת כמה חבילות APK שמיועדות לתצורות שונות של מכשירים.
מניעת התנגשויות כשממזגים משאבים
כברירת מחדל, פלאגין של Android Gradle (AGP) ממזג משאבים עם שמות זהים, כמו משאבי drawable עם אותו שם שנמצאים בתיקיות משאבים שונות.
ההתנהגות הזו לא נשלטת על ידי מאפיין shrinkResources ואי אפשר להשבית אותה כי היא נחוצה כדי למנוע שגיאות כשכמה מקורות כוללים את השם שהקוד מתייחס אליו.
מיזוג משאבים מתרחש רק כששני קבצים או יותר חולקים שם, סוג ומסווג משאבים זהים. AGP בוחר את הקובץ שהוא מזהה כבחירה הטובה ביותר מבין הכפילויות (על סמך סדר עדיפויות שמתואר בהמשך) ומעביר רק את המשאב הזה ל-AAPT להפצה בארטיפקט הסופי של ה-build.
החיפוש של משאבים כפולים ב-AGP מתבצע במיקומים הבאים:
- משאבים ראשיים שמשויכים לקבוצת המקורות הראשית, בדרך כלל נמצאים בתיקייה
src/main/res/ - שכבות-על של וריאנטים, מסוג ה-build ומטעמי ה-build
- יחסי תלות בפרויקט הספרייה
AGP ממזג משאבים כפולים לפי סדר העדיפות הבא:
לדוגמה, אם משאב כפול מופיע גם במשאבים הראשיים וגם בגרסת build, Gradle בוחר את המשאב בגרסת ה-build.
אם משאבים זהים מופיעים באותו מקור, Gradle לא יכול למזג אותם ומוציא שגיאה במיזוג המשאבים. זה יכול לקרות אם מגדירים כמה קבוצות של מקורות במאפיין sourceSet של קובץ המודול build.gradle, למשל, אם גם src/main/res/ וגם src/main/res2/ מכילים משאבים זהים.
פתרון בעיות בכיווץ מקורות המידע
כשמצמצמים משאבים, בחלון Build מוצג סיכום של המשאבים שהוסרו מהאפליקציה. (כדי להציג פלט טקסט מפורט מ-Gradle, לוחצים על Toggle view בצד ימין של החלון). לדוגמה:
:android:shrinkDebugResources
Removed unused resources: Resource data reduced from 2570KB to 1711KB: Removed 33%
:android:validateDebugSigning
בנוסף, Gradle יוצר קובץ אבחון בשם resources.txt בתיקייה <module-name>/build/outputs/mapping/release/ (אותה תיקייה שבה נמצאים קובצי הפלט של ProGuard). הקובץ כולל פרטים כמו משאבים שמפנים למשאבים אחרים ומשאבים שנמצאים בשימוש או שהוסרו.
לדוגמה, כדי לגלות למה @drawable/ic_plus_anim_016 עדיין נמצא באפליקציה, פותחים את הקובץ resources.txt ומחפשים את שם הקובץ הזה. יכול להיות שהמשאב מוזכר במשאב אחר:
16:25:48.005 [QUIET] [system.out] @drawable/add_schedule_fab_icon_anim : reachable=true
16:25:48.009 [QUIET] [system.out] @drawable/ic_plus_anim_016
עכשיו צריך לדעת למה אפשר להגיע אל @drawable/add_schedule_fab_icon_anim. אם מחפשים למעלה, אפשר לראות שהמשאב מופיע בכותרת The root reachable resources are: ב-resources.txt.
המשמעות היא שיש הפניה לקוד add_schedule_fab_icon_anim, כלומר, המזהה R.drawable שלו נמצא בקוד שאפשר להגיע אליו.
אלא אם אתם משתמשים בבדיקה מחמירה, מזהי משאבים יכולים להיות מסומנים כמשאבים שאפשר להגיע אליהם אם יש קבועי מחרוזת שנראים כאילו הם יכולים לשמש לבניית שמות משאבים למשאבים שנטענים באופן דינמי. במקרה כזה, אם תחפשו בפלט של הבנייה את שם המשאב, יכול להיות שתמצאו הודעה כזו:
10:32:50.590 [QUIET] [system.out] Marking drawable:ic_plus_anim_016:2130837506
used because its format-string matches string pool constant ic_plus_anim_%1$d.
אם אתם רואים אחד מהמחרוזות האלה ואתם בטוחים שהמחרוזת לא משמשת לטעינה דינמית של המשאב הנתון, השתמשו במאפיין tools:discard בקובץ השמירה כדי להודיע למערכת build להסיר את המשאב.