כשמפעילים אופטימיזציה של האפליקציה, ההגדרה isShrinkResources = true
מורה למנגנון האופטימיזציה להסיר משאבים שלא בשימוש, וכך לצמצם את גודל האפליקציה. כיווץ משאבים פועל רק בשילוב עם כיווץ קוד, לכן אם מבצעים אופטימיזציה של משאבים, צריך להגדיר גם את isMinifyEnabled = true
. לדוגמה:
buildTypes {
release {
isMinifyEnabled = true
isShrinkResources = true
...
}
}
אם רוצים לשמור או להשליך משאבים ספציפיים, יוצרים קובץ XML מסוג keep במשאבי הפרויקט, למשל res/raw/my.package.keep.xml
. קובץ השמירה כולל את הרכיבים הבאים:
- תג
<resources>
– מכיל את כל רכיבי המשאבים הצאצאים ואת המאפיינים של שמירה או ביטול. - מאפיין
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, צריך להעביר את כל המשאבים לספריית הפרויקט המשותפת, ואז ליצור קובץ my.package.build.variant.keep.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 flavor, Gradle בוחר את המשאב ב-build flavor.
אם משאבים זהים מופיעים באותו קבוצת מקורות, Gradle לא יכול למזג אותם וייוצרת שגיאה במיזוג המשאבים. מצב כזה יכול לקרות אם מגדירים כמה קבוצות מקורות במאפיין sourceSet
בקובץ המודול build.gradle
. לדוגמה, אם גם src/main/res/
וגם src/main/res2/
מכילים משאבים זהים.
פתרון בעיות שקשורות לכיווץ מקורות המידע
כשמקטינים את המשאבים, בחלון Build מוצג סיכום של המשאבים שהוסרו מהאפליקציה. (לוחצים על Toggle view בצד ימין של החלון כדי להציג פלט טקסט מפורט מ-Gradle). לדוגמה:
: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
שלו נמצא בקוד שאפשר לגשת אליו.
אלא אם משתמשים בבדיקות מחמירות, מזהי משאבים יכולים להיות מסומנים כניתנים להגיע אליהם אם יש משתני מחרוזת קבועים שנראה שאפשר להשתמש בהם כדי ליצור שמות של משאבים שנטענים באופן דינמי. במקרה כזה, אם מחפשים את שם המשאב בפלט ה-build, עשויה להופיע הודעה כמו זו:
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
בקובץ keep כדי להודיע למערכת ה-build להסיר את המשאב.