משתמשים נמנעים לעיתים קרובות מהורדת אפליקציות שנראות גדולות מדי, במיוחד בשווקים מתפתחים שבהם המכשירים מתחברים לרשתות 2G ו-3G לא יציבות או פועלים בתוכניות עם מגבלות נתונים. בדף הזה מוסבר איך לצמצם את גודל ההורדה של האפליקציה, כדי לאפשר ליותר משתמשים להוריד אותה.
העלאת האפליקציה באמצעות קובצי Android App Bundle
כדי לחסוך באופן מיידי בגודל האפליקציה כשמפרסמים אותה ב-Google Play, כדאי להעלות אותה כחבילת אפליקציות של Android. Android App Bundle הוא פורמט להעלאה שכולל את כל המשאבים והקוד המהדר של האפליקציה, אבל העברת היצירה והחתימה של ה-APK מתבצעת ב-Google Play.
לאחר מכן, מודל הצגת האפליקציות של Google Play משתמש בחבילת האפליקציות כדי ליצור ולהציג חבילות APK שעברו אופטימיזציה לכל הגדרת מכשיר של משתמש, כך שהם מורידים רק את הקוד והמשאבים הנחוצים להפעלת האפליקציה. כך לא תצטרכו ליצור, לחתום ולנהל כמה חבילות APK כדי לתמוך במכשירים שונים, והמשתמשים יקבלו הורדות קטנות יותר שעברו אופטימיזציה.
ב-Google Play נאכפת הגבלה על גודל ההורדה הדחוס של 200MB לאפליקציות שפורסמו עם חבילות אפליקציות. אפשר להשתמש ב-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. בקובץ הזה מפורטים השם, הגרסה, זכויות הגישה וקבצי הספרייה של האפליקציה. הקובץ בפורמט ה-XML הבינארי של Android.
צמצום מספר המשאבים והגודל שלהם
גודל קובץ ה-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") } } }
Groovy
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 זמין במאמר כיווץ, ערפול ואופטימיזציה של האפליקציה.
ב-Android Gradle Plugin 7.0 ואילך, אפשר להצהיר על ההגדרות שהאפליקציה תומכת בהן. Gradle מעביר את המידע הזה למערכת ה-build באמצעות הטעם resourceConfigurations
והאפשרות defaultConfig
. לאחר מכן, מערכת ה-build מונעת ממשאבים של תצורות אחרות שלא נתמכות להופיע ב-APK, וכך מקטינה את גודל ה-APK. למידע נוסף על התכונה הזו, ראו הסרה של משאבים חלופיים שלא בשימוש.
צמצום השימוש במשאבים מספריות
כשמפתחים אפליקציה ל-Android, בדרך כלל משתמשים בספריות חיצוניות כדי לשפר את נוחות השימוש והגמישות של האפליקציה. לדוגמה, אפשר להפנות ל-AndroidX כדי לשפר את חוויית המשתמש במכשירים ישנים יותר, או להשתמש ב-Google Play Services כדי לאחזר תרגומים אוטומטיים של טקסט באפליקציה.
אם ספרייה מיועדת לשרת או למחשב, היא עשויה לכלול אובייקטים ושיטות רבים שאפליקצייתכם לא צריכה. כדי לכלול רק את החלקים של הספרייה שנחוצים לאפליקציה, אפשר לערוך את הקבצים של הספרייה אם הרישיון מאפשר לשנות אותה. אפשר גם להשתמש בספרייה חלופית שמתאימה לנייד כדי להוסיף פונקציונליות ספציפית לאפליקציה.
פענוח של תמונות מונפשות מותאמות
ב-Android 12 (רמת API 31), ה-API של NDK ImageDecoder
הורחב כדי לפענח את כל הפריימים ונתוני התזמון של תמונות שמשתמשות בפורמטים של קובצי GIF מונפשים ו-WebP מונפשים.
כדאי להשתמש ב-ImageDecoder
במקום בספריות של צד שלישי כדי להקטין עוד יותר את גודל קובץ ה-APK וליהנות מעדכונים עתידיים שקשורים לאבטחה ולביצועים.
למידע נוסף על ה-API של ImageDecoder
, אפשר לעיין במסמכי העזרה של API reference
ובדוגמה ב-GitHub.
תמיכה רק בצפיפויות ספציפיות
Android תומך בדחיסות מסך שונות, כמו:
ldpi
mdpi
tvdpi
hdpi
xhdpi
xxhdpi
xxxhdpi
מערכת Android תומכת בדחיסות שצוינו למעלה, אבל אין צורך לייצא את הנכסים הרסטריים לכל דחיסות.
אם אתם יודעים שלרק אחוז קטן מהמשתמשים יש מכשירים עם צפיפות ספציפית, כדאי לשקול אם אתם צריכים לצרף את הצפיפויות האלה לאפליקציה. אם לא תכללו משאבים לצפיפות מסך ספציפית, Android תתאים באופן אוטומטי את המשאבים הקיימים שתוכננו במקור לצפיפויות מסך אחרות.
אם באפליקציה שלכם נדרשות רק תמונות מותאמות, תוכלו לחסוך עוד יותר מקום על ידי שמירת גרסה אחת של התמונה ב-drawable-nodpi/
. מומלץ לכלול באפליקציה לפחות xxhdpi
וריאנטים של תמונות.
למידע נוסף על ערכי דחיסות המסך, ראו גדלים ודחיסות של מסכים.
שימוש באובייקטים שניתנים לציור
לחלק מהתמונות לא נדרש משאב של תמונה סטטית. במקום זאת, המסגרת יכולה לצייר את התמונה באופן דינמי במהלך זמן הריצה. אובייקטים מסוג Drawable
– או <shape>
ב-XML – יכולים לתפוס כמות קטנה מאוד של מקום ב-APK. בנוסף, אובייקטים מסוג Drawable
ב-XML יוצרים תמונות מונוכרום שתואמות להנחיות של 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
הכלי aapt
יכול לבצע אופטימיזציה של משאבי התמונות שממוקמים ב-res/drawable/
באמצעות דחיסה ללא אובדן נתונים במהלך תהליך ה-build. לדוגמה, הכלי aapt
יכול להמיר קובץ PNG בצבעים אמיתיים שלא דורשים יותר מ-256 צבעים לקובץ PNG של 8 ביט עם לוח צבעים. כך מתקבלת תמונה באיכות זהה, אבל עם פחות נפח אחסון.
ל-aapt
יש את המגבלות הבאות:
- הכלי
aapt
לא מצמצם קובצי PNG שנמצאים בתיקייהasset/
. - קובצי תמונות צריכים לכלול 256 צבעים או פחות כדי שכלי
aapt
יוכל לבצע אופטימיזציה שלהם. - ייתכן שהכלי
aapt
יביא להגדלת נפח של קובצי PNG שכבר דחוסים. כדי למנוע זאת, אפשר להשתמש בדגלisCrunchPngs
כדי להשבית את התהליך הזה בקובצי PNG:
Kotlin
buildTypes.all { isCrunchPngs = false }
Groovy
buildTypes.all { isCrunchPngs = false }
דחיסת קבצי PNG ו-JPEG
אפשר להקטין את הגודל של קובצי PNG בלי לפגוע באיכות התמונה באמצעות כלים כמו pngcrush, pngquant או zopflipng. כל הכלים האלה יכולים להקטין את גודל קובץ ה-PNG תוך שמירה על איכות התמונה.
הכלי pngcrush
יעיל במיוחד. הכלי הזה מבצע איטרציה על מסנני PNG ועל פרמטרים של zlib (Deflate), ומשתמש בכל שילוב של מסננים ופרמטרים כדי לדחוס את התמונה.
לאחר מכן, המערכת בוחרת את ההגדרה שמניבה את הפלט המצונן הקטן ביותר.
כדי לדחוס קבצי JPEG, אפשר להשתמש בכלים כמו packJPG ו-guetzli.
שימוש בפורמט קובץ WebP
במקום להשתמש בקובצי PNG או JPEG, אפשר להשתמש גם בפורמט הקובץ WebP לתמונות. פורמט WebP מספק שקיפות ודחיסת נתונים מסוג lossy, כמו JPG ו-PNG, והוא יכול לספק דחיסת נתונים טובה יותר מאשר JPEG או PNG.
אפשר להמיר תמונות קיימות בפורמט BMP, JPG, PNG או GIF סטטי לפורמט WebP באמצעות Android Studio. מידע נוסף זמין במאמר יצירת תמונות WebP.
שימוש בגרפיקה וקטורית
אפשר להשתמש בגרפיקה וקטורית כדי ליצור סמלים שאינם תלויים ברזולוציה וסוגי מדיה אחרים שניתן לשנות את הגודל שלהם.
אפשר להשתמש בקבצים הגרפיים האלה כדי לצמצם באופן משמעותי את נפח הקבצים של קובץ ה-APK. תמונות וקטוריות מיוצגות ב-Android כאובייקטים מסוג VectorDrawable
. באמצעות אובייקט VectorDrawable
, קובץ של 100 בייטים יכול ליצור תמונה חדה בגודל המסך.
עם זאת, המערכת דורשת זמן רב יותר כדי ליצור עיבוד (רנדור) של כל אובייקט VectorDrawable
, ותמונות גדולות יותר מופיעות במסך זמן רב יותר.
לכן, מומלץ להשתמש בגרפיקת הווקטורים הזו רק כשמציגים תמונות קטנות.
למידע נוסף על עבודה עם אובייקטים מסוג VectorDrawable
, ראו Drawables.
שימוש בגרפיקה וקטורית לתמונות מונפשות
לא מומלץ להשתמש ב-AnimationDrawable
כדי ליצור אנימציות פריים אחר פריים, כי כדי לעשות זאת צריך לכלול קובץ בייטמאפ נפרד לכל פריים של האנימציה, וכך גדל באופן משמעותי הגודל של קובץ ה-APK.
במקום זאת, צריך להשתמש ב-
AnimatedVectorDrawableCompat
כדי ליצור רכיבי drawable של וקטורים מונפשים.
צמצום הקוד המקורי והקוד ב-Java
אתם יכולים להשתמש בשיטות הבאות כדי לצמצם את הגודל של קוד הבסיס של Java ושל הקוד המקורי באפליקציה.
הסרת קוד שנוצר שלא נדרש
חשוב להבין את טביעת הרגל של כל קוד שנוצר באופן אוטומטי. לדוגמה, הרבה כלים של מאגרי נתונים זמניים לפרוטוקולים יוצרים מספר גדול מדי של שיטות וכיתות, שיכולים להגדיל את גודל האפליקציה פי שניים או פי שלושה.
הימנעות מרשימות
enum יחיד יכול להוסיף כ-1.0 עד 1.4 KB לקובץ classes.dex
של האפליקציה. הוספות כאלה יכולות לצבור במהירות במערכות מורכבות או בספריות משותפות. אם אפשר, כדאי להשתמש בהערה @IntDef
ובצמצום קוד כדי להסיר את המניינים ולהמיר אותם למספרים שלמים. המרה מהסוג הזה שומרת על כל היתרונות של בטיחות הסוגים של enums.
צמצום הגודל של קובצי הבינארי הנתמכים
אם האפליקציה שלכם משתמשת בקוד מקומי וב-Android NDK, תוכלו גם לצמצם את הגודל של גרסת המהדורה של האפליקציה על ידי אופטימיזציה של הקוד. שתי שיטות שימושיות הן הסרת סמלי ניפוי באגים ולא חילוץ ספריות מקוריות.
הסרת סמלי ניפוי באגים
כדאי להשתמש בסמלי ניפוי באגים אם האפליקציה נמצאת בפיתוח ועדיין צריך לנפות בה באגים. משתמשים בכלי arm-eabi-strip
שסופק ב-Android NDK כדי להסיר סמלי ניפוי באגים מיותרים מספריות מקוריות. לאחר מכן תוכלו לקמפל את גרסה ה-build של המוצר.
הימנעות מחילוץ של ספריות מקוריות
כשמפתחים את גרסת המהדורה של האפליקציה, צריך לארוז קבצים לא דחוסים מסוג .so
בקובץ ה-APK. לשם כך, מגדירים את הערך useLegacyPackaging
לערך false
בקובץ build.gradle.kts
של האפליקציה. השבתת הדגל הזה מונעת מ-PackageManager
להעתיק קבצים של .so
מקובץ ה-APK למערכת הקבצים במהלך ההתקנה. השיטה הזו מאפשרת ליצור עדכונים קטנים יותר לאפליקציה.
שמירה על כמה חבילות APK פשוטות
יכול להיות ש-APK שלכם מכיל תוכן שהמשתמשים מורידים אבל אף פעם לא משתמשים בו, כמו שפות נוספות או משאבים לכל צפיפות מסך. כדי להבטיח שהמשתמשים יורידו מינימום נתונים, כדאי להעלות את האפליקציה ל-Google Play באמצעות Android App Bundles. העלאת חבילות אפליקציות מאפשרת ל-Google Play ליצור ולהציג חבילות APK שעברו אופטימיזציה לכל הגדרת מכשיר של משתמש, כך שהם מורידים רק את הקוד והמשאבים הנדרשים להפעלת האפליקציה. כך לא תצטרכו ליצור, לחתום ולנהל כמה חבילות APK כדי לתמוך במכשירים שונים, והמשתמשים יקבלו הורדות קטנות יותר שעברו אופטימיזציה.
אם אתם לא מפרסמים את האפליקציה ב-Google Play, אתם יכולים לפלח את האפליקציה לכמה קובצי APK, ולהבדיל ביניהם לפי גורמים כמו גודל המסך או תמיכה בטקסטורות של GPU.
כשמשתמש מוריד את האפליקציה, המכשיר שלו מקבל את קובץ ה-APK הנכון על סמך המאפיינים וההגדרות של המכשיר. כך, מכשירים לא מקבלים נכסים של תכונות שהמכשירים לא כוללים. לדוגמה, אם למשתמש יש מכשיר hdpi
, הוא לא צריך משאבי xxxhdpi
שיכול להיות שתכללו במכשירים עם צפיפות גבוהה יותר של המסך.
מידע נוסף זמין במאמרים יצירת מספר קובצי APK ותמיכה בכמה קובצי APK.