צמצום גודל האפליקציה

לעיתים קרובות משתמשים נמנעים מהורדת אפליקציות שנראות גדולות מדי, במיוחד בשווקים מתעוררים שבהם מכשירים מתחברים לרשתות 2G ו-3G לא יציבות או עובדים על תוכניות עם מגבלות נתונים. בדף הזה נסביר איך להקטין את גודל ההורדה של האפליקציה, כדי לאפשר ליותר משתמשים להוריד אותה.

העלאת אפליקציה באמצעות קובצי Android App Bundle

מעלים את האפליקציה כקובץ Android App Bundle כדי שמירת גודל האפליקציה כשמפרסמים ב-Google Play. קובץ Android App Bundle הוא פורמט העלאה שכולל את כל הקוד והמשאבים המורכבים של האפליקציה, אבל מונעים יצירת APK וכניסה ל-Google Play.

לאחר מכן, מודל הצגת האפליקציות של Google Play משתמש ב-App Bundle כדי ליצור ולהציג חבילות APK שעברו אופטימיזציה. לתצורת המכשיר של כל משתמש, כדי שהוא יוריד רק את הקוד והמשאבים שדרושים לו להריץ את האפליקציה. אתם לא צריכים לפתח, לחתום ולנהל חבילות APK מרובות כדי לתמוך במכשירים שונים, והמשתמשים מקבלים הורדות קטנות ומשופרות.

Google Play אוכפת הורדה דחוסה הגבלת גודל של 200MB לאפליקציות שפורסמו באמצעות קובצי App Bundle. גדלים גדולים יותר אפשריות באמצעות Play Feature Delivery ו-Play Asset Delivery, אבל הגדלה של גודל האפליקציה תשפיע לרעה על הצלחת ההתקנה ותגדיל את מספר ההסרות, לכן אנחנו ממליצים להחיל שמתוארות בדף הזה כדי להקטין את גודל ההורדה של האפליקציה ככל האפשר.

הסבר על מבנה ה-APK

לפני שמקטינים את גודל האפליקציה, חשוב להבין את מבנה ה-APK של האפליקציה. קובץ APK מורכב מארכיון ZIP שמכיל את כל הקבצים שמהם מורכבת האפליקציה. האלה הקבצים כוללים קובצי מחלקה של Java, קובצי משאבים וקובץ שמכיל משאבים שעברו הידור.

חבילת APK מכילה את הספריות הבאות:

  • META-INF/: מכיל את החתימה CERT.SF ו-CERT.RSA קבצים שונים, וגם MANIFEST.MF בקובץ המניפסט.
  • assets/: מכיל את נכסי האפליקציה, שהאפליקציה יכולה לאחזר באמצעות AssetManager לאובייקט.
  • res/: מכיל משאבים שלא עברו הידור resources.arsc.
  • lib/: מכיל את הקוד שעבר הידור שספציפי לשכבת התוכנה של ומעבד מידע. הספרייה הזו מכילה ספריית משנה לכל סוג פלטפורמה, כמו armeabi, armeabi-v7a, arm64-v8a, x86 x86_64 ו-mips.

חבילת APK מכילה גם את הקבצים הבאים. חובה להזין רק AndroidManifest.xml:

  • resources.arsc: מכיל משאבים שעברו הידור. הקובץ הזה מכיל את התוכן בפורמט XML מכל ההגדרות של התיקייה res/values/. כלי האריזה מחלץ את זה תוכן XML, מהדר אותו לצורה בינארית ומעביר את התוכן לארכיון. התוכן הזה כולל שפה מחרוזות וסגנונות, וכן נתיבים לתוכן שלא נכלל ישירות resources.arsc, למשל קובצי פריסה ותמונות.
  • classes.dex: מכיל את הכיתות שעברו הידור בפורמט קובץ DEX שמבינים על ידי במכונה הווירטואלית Dalvik או ART.
  • AndroidManifest.xml: מכיל את קובץ המניפסט המרכזי של Android. בקובץ הזה מפורטים השם, הגרסה, הרשאות הגישה וקובצי הספרייה של האפליקציה. הקובץ משתמש ב-Android בפורמט XML בינארי.

הקטנה של מספר המשאבים והגודל שלהם

גודל ה-APK משפיע על מהירות הטעינה של האפליקציה, על נפח הזיכרון שהיא משתמשת בו ועל אופן הטעינה שהוא צורך. ניתן להקטין את ה-APK על ידי הקטנת המספר והגודל של ה-APK את המשאבים שהוא מכיל. באופן ספציפי, אפשר להסיר משאבים שהאפליקציה כבר לא משתמשת בהם, יכולים להשתמש במודל יכולת התאמה Drawable אובייקטים ב- המקום של קובצי התמונות. הקטע הזה דן בשיטות האלה ובדרכים נוספות שבהן אפשר לצמצם את משאבים באפליקציה שלך כדי להקטין את הגודל הכולל של ה-APK.

הסרת משאבים שלא נמצאים בשימוש

הכלי lint – כלי לניתוח קוד סטטי שכלולות ב-Android Studio – המערכת מזהה משאבים בתיקייה res/ שבהם הקוד לא מפנה. כשהכלי lint מאתר משאב שעשוי להיות שלא נמצא בשימוש בחשבון שלך המערכת מדפיסה הודעה כמו בדוגמה הבאה:

res/layout/preferences.xml: Warning: The resource R.layout.preferences appears
    to be unused [UnusedResources]

יכול להיות שספריות שהוספת לקוד יכללו משאבים שלא נמצאים בשימוש. Gradle יכולה אוטומטית להסיר משאבים בשמך אם מפעילים shrinkResources ב- את קובץ build.gradle.kts של האפליקציה.

Kotlin

android {
    // Other settings.

    buildTypes {
        getByName("release") {
            minifyEnabled = true
            shrinkResources = true
            proguardFiles(getDefaultProguardFile('proguard-android.txt'), "proguard-rules.pro")
        }
    }
}

מגניב

android {
    // Other settings.

    buildTypes {
        release {
            minifyEnabled true
            shrinkResources true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

כדי להשתמש ב-shrinkResources, צריך להפעיל כיווץ קוד. במהלך ה-build, מקישים קודם על R8 מסירה קוד שלא בשימוש. אחר כך, הפלאגין של Android Gradle מסיר את המשאבים שלא נמצאים בשימוש.

בקישורים הבאים תוכלו למצוא מידע נוסף על כיווץ הקוד והמשאבים ועל דרכים נוספות שבהן Android Studio גודל ה-APK זמין במאמר כיווץ, ערפול קוד (obfuscation) ואופטימיזציה של האפליקציה.

ב-Android Gradle Plugin מגרסה 7.0 ואילך, אפשר להצהיר על ההגדרות שהאפליקציה שלך נתמך. Gradle מעבירה את המידע הזה למערכת ה-build באמצעות resourceConfigurations טעם חדש והאפשרות defaultConfig. לאחר מכן מערכת ה-build מונעת משאבים תצורות אחרות שאינן נתמכות ב-APK, וכתוצאה מכך הקטנת את גודל ה-APK. לקבלת מידע נוסף על התכונה הזאת: הסרת חלופה שלא בשימוש משאבים.

צמצום השימוש במשאבים מספריות

כשמפתחים אפליקציה ל-Android, בדרך כלל משתמשים בספריות חיצוניות כדי לשפר את שימושיות וגמישות. לדוגמה, אפשר להיעזר ב-AndroidX כדי לשפר את חוויית המשתמש במכשירים קודמים, או שאפשר להשתמש Google Play Services לאחזור תרגומים אוטומטיים של טקסט בתוך האפליקציה.

אם ספרייה מיועדת לשרת או לשולחן עבודה, היא יכולה לכלול הרבה אובייקטים ושיטות שהאפליקציה לא נחוצה. כדי לכלול רק את החלקים מהספרייה שנדרשים לאפליקציה, אפשר לערוך את הקבצים של הספרייה, אם הרישיון מאפשר לכם לשנות את הספרייה. אפשר גם להשתמש בחלופה לספרייה ידידותית לנייד כדי להוסיף פונקציונליות ספציפית לאפליקציה.

פענוח תמונה מונפשת רגילה

ב-Android 12 (רמת API 31), ה-NDK ממשק ה-API של ImageDecoder מורחב לפענוח קוד כל נתוני הפריימים והתזמון מתמונות שנעשה בהן שימוש בפורמט GIF מונפש וקובץ WebP מונפש.

יש להשתמש ב-ImageDecoder במקום בספריות של צד שלישי כדי להמשיך הקטנת ה-APK והפקת תועלת מעתיד עדכונים שקשורים לאבטחה ולביצועים.

לפרטים נוספים על ImageDecoder API, אפשר לעיין במאמר בנושא API reference וגם דוגמה ב-GitHub.

תמיכה בדחיסות ספציפיות בלבד

מערכת Android תומכת בדחיסות מסך שונות, למשל:

  • ldpi
  • mdpi
  • tvdpi
  • hdpi
  • xhdpi
  • xxhdpi
  • xxxhdpi

למרות ש-Android תומך בדחיסות הקודמת, אין צורך לייצא את נכסים לכל צפיפות.

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

אם האפליקציה שלך צריכה רק תמונות מותאמות, תוכל לחסוך עוד יותר מקום אם תשתמש בווריאציה אחת של תמונה באוסף drawable-nodpi/. מומלץ לכלול לפחות xxhdpi של קבוצת התמונות באפליקציה שלך.

למידע נוסף על דחיסות המסך, גדלים ודחיסויות של מסכים.

שימוש באובייקטים שניתנים להזזה

בחלק מהתמונות אין צורך במשאב של תמונה סטטית. תוכנת ה-framework יכולה לשרטט באופן דינמי את התמונה בזמן ריצה. Drawable אובייקטים — או <shape> אינץ' XML - יכול לתפוס שטח קטן ב-APK. בנוסף, XML Drawable אובייקטים מייצרים תמונות מונוכרומטיות שתואמות להנחיות של Material Design.

שימוש חוזר במשאבים

אפשר לכלול משאב נפרד לווריאציות של תמונה, כמו שימוש בגוון, הצללה או מסובבים את אותה התמונה. עם זאת, מומלץ להשתמש שוב באותה קבוצת משאבים ולהתאים אותם אישית לפי הצורך בזמן הריצה.

ב-Android יש כמה כלים לשינוי צבע של נכס, באמצעות android:tint ו-tintMode.

אפשר גם להשמיט משאבים שהם רק מקבילים של משאב אחר ברוטציה. הבאים היא דוגמה להפיכת 'תמונה ממוזערת' למצב 'אל תוך אגודל' באמצעות שינוי באמצע התמונה, ומסובב ב-180 מעלות:

<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/ic_thumb_up"
    android:pivotX="50%"
    android:pivotY="50%"
    android:fromDegrees="180" />

עיבוד מקוד

ניתן גם להקטין את גודל ה-APK על ידי עיבוד פרוצדורלי של התמונות. רינדור פרוצדורלי מפנה מקום כי כבר לא מאחסנים קובץ תמונה ב-APK.

קובצי PNG מסוג Crunch

הכלי aapt יכול לבצע אופטימיזציה של משאבי התמונות שמוצבים בres/drawable/ עם דחיסת נתונים ללא אובדן מידע במהלך תהליך ה-build. לדוגמה, הכלי aapt יכול צריך להמיר קובץ PNG בצבע אמיתי שלא דורש יותר מ-256 צבעים לקובץ PNG עם 8 ביט עם צבע לוח צבעים. אם עושים זאת, מתקבלת תמונה באיכות זהה אבל טביעת הרגל הפחמנית קטנה יותר של הזיכרון.

המגבלות הבאות חלות על aapt:

  • הכלי aapt לא מכווץ קובצי PNG שכלולים בasset/ .
  • כדי לבצע אופטימיזציה של קובצי תמונה, צריך להשתמש ב-256 צבעים או פחות כדי שהכלי aapt יבצע אופטימיזציה אותם.
  • הכלי aapt עשוי לנפח קובצי PNG שכבר דחוסים. כדי למנוע במקרה הזה אפשר להשתמש בדגל isCrunchPngs כדי להשבית את התהליך הזה בקובצי PNG:
  • Kotlin

        buildTypes.all { isCrunchPngs = false }
        

    מגניב

        buildTypes.all { isCrunchPngs = false }
        

דחיסת קובצי PNG ו-JPEG

אפשר להקטין את הגודל של קובצי PNG בלי לגרוע מאיכות התמונה באמצעות כלים כמו pngcrush, pngquant, או zopflipng. כל הכלים האלה יכולים להקטין את קובץ ה-PNG תוך שמירה על איכות התמונה.

הכלי pngcrush יעיל במיוחד. הכלי הזה מבצע איטרציה על בסיס מסנני PNG zlib (Deflate) באמצעות כל שילוב של מסננים ופרמטרים כדי לדחוס את התמונה. לאחר מכן הוא בוחר את התצורה שיוצרת את הפלט הדחוס הקטן ביותר.

כדי לדחוס קובצי JPEG, אפשר להשתמש בכלים כמו packJPG ו-guetzli.

שימוש בפורמט הקובץ WebP

במקום להשתמש בקובצי PNG או JPEG, אפשר להשתמש גם פורמט הקובץ WebP של התמונות. ה-WebP שמספק דחיסת נתונים מסוג איבוד מידע ושקיפות, כמו JPG ו-PNG, והוא יכול לספק שקיפות דחיסת נתונים מאשר JPEG או PNG.

Android Studio מאפשר להמיר תמונות קיימות בפורמט BMP, JPG, PNG או GIF סטטי לפורמט WebP. מידע נוסף זמין במאמר יצירת תמונות WebP.

שימוש בגרפיקה וקטורית

ניתן להשתמש בגרפיקה וקטורית כדי ליצור סמלים שאינם תלויים ברזולוציה ומדיה אחרת שניתן לשנות את הגודל שלה. אפשר להשתמש בגרפיקה הזו כדי לצמצם משמעותית את טביעת הרגל הפחמנית של ה-APK. תמונות וקטוריות מיוצגות ב Android בתור VectorDrawable אובייקטים. באמצעות אובייקט VectorDrawable, קובץ בגודל 100 בייטים יכול ליצור תמונה חדה גודל המסך.

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

למידע נוסף על עבודה עם אובייקטים מסוג VectorDrawable: נכסים דיגיטליים.

שימוש בגרפיקה וקטורית לתמונות מונפשות

אני לא רוצה להשתמש AnimationDrawable כדי ליצור אנימציות של פריים אחרי פריים, כי הפעולה הזו דורשת הוספה של מפת סיביות נפרדת עבור כל פריים באנימציה, פעולה שמגדילה משמעותית את גודל ה-APK.

במקום זאת, השתמשו AnimatedVectorDrawableCompat כדי ליצור וקטור מונפש פריטים שניתנים להזזה.

הפחתת הקוד המקורי וקוד Java

אפשר להשתמש בשיטות הבאות כדי להקטין את הגודל של Java ושל Native Codebase אפליקציה.

מסירים קוד מיותר שנוצר

חשוב להבין את טביעת הרגל של כל קוד שנוצר באופן אוטומטי. לדוגמה, כלים רבים למאגר נתונים זמני של פרוטוקולים מייצרים מספר גדול של שיטות ומחלקות, מה שעלול להכפיל או פי 3 מגודל האפליקציה.

נמנעים מספירה

enum אחד יכול להוסיף בין 1.0 ל-1.4KB לקובץ classes.dex של האפליקציה. האלה ותוספות יכולות להצטבר במהירות במערכות מורכבות או בספריות משותפות. אם אפשר, כדאי באמצעות ההערה @IntDef וכיווץ הקוד כדי להסיר ספירות ולהמיר אותן למספרים שלמים. המרה מסוג זה שומרת את כל יתרונות הבטיחות של טיפוסים בני מנייה (enum).

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

אם באפליקציה נעשה שימוש בקוד נייטיב וב-Android NDK, אפשר גם להקטין את גודל הגרסה של האפליקציה על ידי אופטימיזציה של הקוד. יש שתי שיטות שימושיות להסרת סמלים של ניפוי באגים, ולא מחלצים ספריות נייטיב.

הסרת סמלים של ניפוי באגים

כדאי להשתמש בסמלים לניפוי באגים אם האפליקציה נמצאת בפיתוח ועדיין מחייבת שימוש בניפוי באגים. כדאי להשתמש הכלי arm-eabi-strip שמסופק ב-Android NDK להסרת ניפוי באגים מיותר מספריות מקוריות. לאחר מכן, תוכלו להדר את ה-build של הגרסה.

הימנעות מחילוץ ספריות נייטיב

כשיוצרים את גרסת ההפצה של האפליקציה, צריך לארוז קובצי .so לא דחוסים APK לפי הגדרה useLegacyPackaging אל false בקובץ build.gradle.kts של האפליקציה שלך. השבתת הסימון הזה מונעת PackageManager מ- העתקת .so קבצים מה-APK למערכת הקבצים במהלך ההתקנה. השיטה הזאת מאפשרת של האפליקציה.

ניהול מספר חבילות APK רזות

יכול להיות שה-APK מכיל תוכן שמשתמשים מורידים אבל אף פעם לא משתמשים בו, כמו שפה נוספת או משאבים בדחיסות מסך. כדי להבטיח הורדה מינימלית של המשתמשים, כדאי להעלות את האפליקציה אל Google Play באמצעות קובצי Android App Bundle. העלאת קובצי App Bundle מאפשרת ל-Google מערכת Play יוצרת ומציגה חבילות APK שעברו אופטימיזציה בהתאם להגדרת המכשיר של כל משתמש, כדי שהן יוכלו להוריד רק את הקוד והמשאבים הדרושים להם כדי להפעיל את האפליקציה. לא צריך ליצור, לחתום ולנהל כמה פלטפורמות חבילות APK שתומכות במכשירים שונים, והמשתמשים מקבלים הורדות קטנות ומשופרות.

אם לא מפרסמים את האפליקציה ב-Google Play, אפשר לפלח את האפליקציה לכמה חבילות APK, שונה בהתאם לגורמים כמו גודל המסך או תמיכה בטקסטורה של GPU.

כשמשתמש מוריד את האפליקציה שלך, המכשיר שלו מקבל את ה-APK הנכון, בהתאם תכונות והגדרות. כך, מכשירים לא יקבלו נכסים עבור תכונות שהמכשירים לא מקבלים שיש. לדוגמה, אם למשתמש יש מכשיר hdpi, הוא לא צריך xxxhdpi שאולי תוכלו לכלול במכשירים עם מסכים עם צפיפות גבוהה יותר.

אפשר לקרוא מידע נוסף במאמר יצירת גרסאות מרובות חבילות APK ותמיכה ב-APK מרובים.