התאמה אישית של המשאבים שיישארו

כשמפעילים אופטימיזציה של אפליקציות, התנהגות ברירת המחדל של הכלי לאופטימיזציה שונה בגרסאות שונות של 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/my.package.keep.xml. קובץ ה-Keep כולל את הרכיבים הבאים:

  • התג <resources> – מכיל את כל רכיבי משאבי הצאצאים ואת המאפיינים 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, צריך להעביר את כל המשאבים לספריית הפרויקט המשותפת, ואז ליצור קובץ my.package.build.variant.keep.xml שונה לכל וריאנט build בספריית המשאבים של הווריאנט. בקובץ keep, מציינים באופן ידני את המשאבים שרוצים להסיר כשמשאב מסוים נראה בשימוש בקוד (ולכן לא מוסר על ידי הכלי לכיווץ), אבל יודעים שהוא לא ישמש בפועל לוריאנט build הנתון.

הסרה של משאבים חלופיים שלא בשימוש

הכלי לא יסיר משאבים חלופיים לתצורות שונות של מכשירים.

כדי להסיר קבצים חלופיים של משאבים שהאפליקציה לא צריכה, משתמשים במאפיין Android Gradle‏ resConfigs בקובץ המודול build.gradle של האפליקציה.

לדוגמה, אם אתם משתמשים בספרייה שכוללת משאבי שפה (כמו Google Play Services), האפליקציה שלכם כוללת את כל מחרוזות השפה המתורגמות להודעות בספריות האלה, גם אם שאר האפליקציה מתורגמת לאותן שפות וגם אם לא. כדי להשאיר רק את השפות שהאפליקציה שלכם תומכת בהן באופן רשמי, מציינים את השפות האלה באמצעות המאפיין resConfigs. כל המשאבים של שפות שלא צוינו יוסרו.

בקטעי הקוד הבאים אפשר לראות איך מגבילים את משאבי השפה לאנגלית ולצרפתית בלבד:

android {
    defaultConfig {
        ...
        resourceConfigurations.addAll(listOf("en", "fr"))
    }
}

או

android {
    defaultConfig {
        ...
        resConfigs "en", "fr"
    }
}

כשמפרסמים אפליקציה בפורמט קובץ Android App Bundle‏ (AAB), כברירת מחדל, רק השפות שהוגדרו במכשיר של המשתמש יורדות כשהמשתמש מתקין את האפליקציה. באופן דומה, רק משאבים שתואמים לצפיפות המסך של המכשיר וספריות Native שתואמות לממשק ABI של המכשיר נכללים בהורדה. מידע נוסף זמין במאמר הפעלה מחדש או השבתה של סוגים של חבילות APK להגדרת תצורה.

באפליקציות מדור קודם שמופצות באמצעות קובצי APK (שנוצרו לפני אוגוסט 2021), אפשר ליצור כמה קובצי APK שמיועדים לתצורות שונות של מכשירים כדי להתאים אישית את משאבי צפיפות המסך או ה-ABI שייכללו בקובץ ה-APK.

מניעת התנגשויות כשממזגים משאבים

כברירת מחדל, הפלאגין של Android Gradle (AGP) ממזג משאבים עם שמות זהים, כמו משאבי drawable עם אותו שם שנמצאים בתיקיות משאבים שונות. ההתנהגות הזו לא נשלטת על ידי המאפיין shrinkResources ואי אפשר להשבית אותה כי היא נחוצה כדי למנוע שגיאות כשכמה משאבים כוללים את השם שהקוד מפנה אליו.

מיזוג של מקורות מידע מתרחש רק כששני קבצים או יותר חולקים שם, סוג ומאפיין זהים של מקור מידע. ‫AGP בוחר את הקובץ שהוא מזהה כבחירה הטובה ביותר מבין הכפילויות (על סמך סדר עדיפויות שמתואר בהמשך) ומעביר רק את המשאב הזה ל-AAPT להפצה בארטיפקט הסופי של הבנייה.

החיפוש של משאבים כפולים ב-AGP מתבצע במיקומים הבאים:

  • מקורות מידע ראשיים שמשויכים לקבוצת המקורות הראשית, בדרך כלל נמצאים בתיקייה src/main/res/
  • שכבות-על של וריאנטים, מסוג ה-build ומטעמי ה-build
  • תלויות של פרויקט הספרייה

‫AGP ממזג משאבים כפולים לפי סדר העדיפות הבא:

‫Dependencies (תלויות) ← Main (ראשי) ← Build flavor (טעם build) ← Build type (סוג build)

לדוגמה, אם משאב כפול מופיע גם במשאבים הראשיים וגם בגרסת 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 להסיר את המשאב.