זהירות: מאז אוגוסט 2021, כל השינויים צריך לפרסם אפליקציות כקובצי App Bundle. אם אתם מפרסמים את האפליקציה ב-Google Play, ליצור קובץ Android App Bundle ולהעלות אותו. מתי במקרה כזה, Google Play יוצרת ומציגה באופן אוטומטי חבילות APK שעברו אופטימיזציה את תצורת המכשיר של כל משתמש, כך שהוא יוריד רק את הקוד והמשאבים שהם צריכים להפעיל את האפליקציה. פרסום של חבילות APK מרובות שימושי אם לפרסם בחנות שאינה תומכת בפורמט AAB. במקרה כזה, ליצור, לחתום ולנהל כל APK בעצמכם.
למרות שעדיף לפתח APK יחיד שיתמוך בכל מכשירי היעד שלך כשהדבר אפשרי, ה-APK גדול מאוד עקב הקבצים תומכים במספר דחיסות המסך או Application Binary ממשקים (ABI). אחת הדרכים להקטין את גודל ה-APK היא ליצור מספר חבילות APK מכילים קבצים לדחיסות מסך או לממשקי ABI ספציפיים.
Gradle יכולה ליצור חבילות APK נפרדות שמכילות רק קוד ומשאבים ספציפיים לכל צפיפות או ABI. בדף הזה נסביר איך להגדיר את ה-build כדי יוצרים כמה חבילות APK. אם אתם צריכים ליצור גרסאות שונות של האפליקציה שלא מבוססים על דחיסות המסך או על ממשק ABI, צריך להשתמש במקום זאת ביצירת וריאנטים.
הגדרת ה-build לכמה חבילות APK
כדי להגדיר את ה-build לכמה חבילות APK, צריך להוסיף
splits
חסום ברמת המודול
קובץ build.gradle
. בתוך
חסימת splits
, יש לציין
בלוק density
שמציין איך רוצים ש-Gradle ייצור
חבילות APK לכל צפיפות או בלוק abi
שמציין איך רוצים להשתמש ב-Gradle
כדי ליצור חבילות APK לכל ABI. אפשר לספק גם בלוקים דחיסות וגם בלוקים ABI,
מערכת ה-build יוצרת APK לכל שילוב של צפיפות ו-ABI.
הגדרת חבילות APK מרובות לדחיסות מסך
כדי ליצור חבילות APK נפרדות לדחיסות מסך שונות, צריך להוסיף
חסימה אחת (density
) בתוך
חסימת splits
. בבלוק density
שלך, יש לציין
רשימה של דחיסות המסך הרצויה וגודלי מסך תואמים. השתמשו רק ברשימה של
בגדלים תואמים, אם צריך
<compatible-screens>
רכיבים במניפסט של כל APK.
האפשרויות הבאות של Gradle DSL משמשות להגדרת חבילות APK מרובות עבור דחיסות המסך:
-
enable
ל-Groovy,isEnable
לסקריפט של Kotlin -
אם מגדירים את הרכיב הזה ל-
true
, Gradle יוצרת כמה חבילות APK בהתאם לדחיסות המסך שהגדרתם. ערך ברירת המחדל הואfalse
-
exclude
-
מציין רשימה מופרדת בפסיקים של ערכי צפיפות שבהם לא רוצים להשתמש ב-Gradle
כדי ליצור חבילות APK נפרדות. כדאי להשתמש ב-
exclude
אם רוצה ליצור חבילות APK לרוב הדחיסות, אבל צריך להחריג כמה מהן צפיפות הצפיפות שהאפליקציה לא תומכת בהן. -
reset()
-
ניקוי רשימת ברירת המחדל של צפיפות המסך. יש להשתמש בו רק בשילוב עם רכיב
include
כדי לציין את הדחיסות הרצויה הוספהקטע הקוד הבא מגדיר את רשימת הדחיסות כ-
ldpi
וגםxxhdpi
באמצעות חיוג אלreset()
כדי לנקות את הרשימה, ולאחר מכן להשתמש ב-include
:reset() // Clears the default list from all densities // to no densities. include "ldpi", "xxhdpi" // Specifies the two densities to generate APKs // for.
-
include
-
מציינת רשימה מופרדת בפסיקים של צפיפות שרוצים ש-Gradle ייצור
חבילות APK ל-. יש להשתמש רק בשילוב עם
reset()
כדי לציין רשימה מדויקת של צפיפות. -
compatibleScreens
-
מציינת רשימה של גדלים תואמים של מסכים שמופרדים בפסיקים. המכשיר הזה מבצע החדרה תואם צומת
<compatible-screens>
במניפסט של כל APK.ההגדרה הזו מספקת דרך נוחה לנהל את שני המסכים הדחיסות וגודל המסך באותו קטע
build.gradle
. אבל, באמצעות יש ל-<compatible-screens>
אפשרות להגביל את סוגי המכשירים שהאפליקציה שלך עובדת איתה. לדרכים חלופיות לספק במסכים בגדלים שונים, סקירה כללית על תאימות המסך
מפני שכל APK שמבוסס על צפיפות המסך כולל
תג <compatible-screens>
עם הגבלות ספציפיות
על סוגי המסכים שנתמכים ב-APK — גם אם אתם מפרסמים כמה סוגי מסכים
חבילות APK - חלק מהמכשירים החדשים לא תואמים למסנני ה-APK המרובים. לכן,
Gradle תמיד יוצרת APK אוניברסלי נוסף שמכיל נכסים
לכל צפיפות המסך, ולא כולל
תג <compatible-screens>
. פרסם זאת
חבילת APK אוניברסלית וחבילות APK לפי דחיסות, כחלופה
מכשירים שלא תואמים ל-APKs עם
תג <compatible-screens>
.
הדוגמה הבאה יוצרת APK נפרד לכל אחד מהם.
מסך
צפיפות מלבד ldpi
, xxhdpi
ו-
xxxhdpi
הפעולה הזו מתבצעת באמצעות exclude
כדי להסיר
שלוש הדחיסות האלה מרשימת ברירת המחדל של כל הדחיסות.
מגניב
android { ... splits { // Configures multiple APKs based on screen density. density { // Configures multiple APKs based on screen density. enable true // Specifies a list of screen densities you don't want Gradle to create multiple APKs for. exclude "ldpi", "xxhdpi", "xxxhdpi" // Specifies a list of compatible screen size settings for the manifest. compatibleScreens 'small', 'normal', 'large', 'xlarge' } } }
Kotlin
android { ... splits { // Configures multiple APKs based on screen density. density { // Configures multiple APKs based on screen density. isEnable = true // Specifies a list of screen densities you don't want Gradle to create multiple APKs for. exclude("ldpi", "xxhdpi", "xxxhdpi") // Specifies a list of compatible screen size settings for the manifest. compatibleScreens("small", "normal", "large", "xlarge") } } }
לפרטים נוספים על התאמה אישית של גרסאות build שונות של האפליקציה לסוגים שונים של מסכים ומכשירים, לראות הצהרה על הגבלה תמיכה במסך.
הגדרה של כמה חבילות APK לממשקי ABI
כדי ליצור חבילות APK נפרדות לממשקי ABI שונים, צריך להוסיף בלוק abi
בתוך
חסימת splits
. בבלוק של abi
, עליך לספק רשימה של
בממשקי ה-ABI הרצויים.
האפשרויות הבאות של Gradle DSL משמשות להגדרת חבילות APK מרובות לכל ממשק ABI:
-
enable
ל-Groovy אוisEnable
לסקריפט של Kotlin - אם מגדירים את הרכיב הזה לערך
true
, Gradle יוצרת מספר מודעות חבילות APK שמבוססות על ממשקי ה-ABI שהגדרתם. ערך ברירת המחדל הואfalse
. -
exclude
-
מציינת רשימה של ממשקי ABI מופרדים בפסיקים שאתם לא רוצים ש-Gradle ישתמש בהם
ליצור חבילות APK נפרדות. אם רוצים ליצור, צריך להשתמש ב-
exclude
חבילות APK לרוב ממשקי ה-ABI, אבל צריך להחריג כמה ממשקי ABI שלא כוללים את האפליקציה תמיכה. -
reset()
-
ניקוי של רשימת ממשקי ברירת המחדל של ABI. יש להשתמש בו רק בשילוב עם
include
כדי לציין את ממשקי ה-ABI שרוצים להוסיף.קטע הקוד הבא מגדיר את רשימת ממשקי ה-ABI כ-
x86
בלבדx86_64
נשלחת אלreset()
כדי לנקות את הרשימה. ואז באמצעותinclude
:reset() // Clears the default list from all ABIs to no ABIs. include "x86", "x86_64" // Specifies the two ABIs we want to generate APKs for.
-
include
-
מציינת רשימה מופרדת בפסיקים של ממשקי ABI שרוצים ש-Gradle ייצור חבילות APK.
עבור. יש להשתמש רק בשילוב עם
reset()
כדי לציין ערך מדויק של ה-ABI. -
universalApk
בשביל גרוב, אוisUniversalApk
בשביל סקריפט Kotlin -
אם הערך שלו הוא
true
, Gradle יוצרת APK אוניברסלי בנוסף חבילות APK לכל ממשק ABI. APK אוניברסלי מכיל קוד ומשאבים לכל ממשקי ה-ABI APK יחיד. ערך ברירת המחדל הואfalse
.הערה: האפשרות הזו זמינה רק זמינות בבלוק של
splits.abi
. כשיוצרים כמה חבילות APK לפי דחיסות המסך, Gradle תמיד יוצרת APK אוניברסלי מכיל קוד ומשאבים לכל צפיפות המסך.
הדוגמה הבאה יוצרת APK נפרד לכל ממשק ABI: x86
ו-x86_64
. הפעולה מתבצעת באמצעות reset()
להתחיל עם רשימה ריקה של ממשקי ABI, ואחריה include
עם
רשימה של ממשקי ABI שכל אחד מהם מקבל APK.
מגניב
android { ... splits { // Configures multiple APKs based on ABI. abi { // Enables building multiple APKs per ABI. enable true // By default all ABIs are included, so use reset() and include to specify that you only // want APKs for x86 and x86_64. // Resets the list of ABIs for Gradle to create APKs for to none. reset() // Specifies a list of ABIs for Gradle to create APKs for. include "x86", "x86_64" // Specifies that you don't want to also generate a universal APK that includes all ABIs. universalApk false } } }
Kotlin
android { ... splits { // Configures multiple APKs based on ABI. abi { // Enables building multiple APKs per ABI. isEnable = true // By default all ABIs are included, so use reset() and include to specify that you only // want APKs for x86 and x86_64. // Resets the list of ABIs for Gradle to create APKs for to none. reset() // Specifies a list of ABIs for Gradle to create APKs for. include("x86", "x86_64") // Specifies that you don't want to also generate a universal APK that includes all ABIs. isUniversalApk = false } } }
רשימה של ממשקי ABI נתמכים נתמך ממשקי ABI.
פרויקטים ללא קוד מקורי/C++
בפרויקטים בלי קוד מקורי/C++, בחלונית יצירת וריאנטים יש עמודות: מודול ו-Active Build וריאנט, כפי שמוצג באיור 1.
איור 1. בחלונית יצירת וריאנטים יש שתי עמודות לפרויקטים ללא
נייטיב/קוד C++.
הערך Active Build וריאנט של קובע את גרסת ה-build שנפרסת ומוצגת בכלי העריכה. כדי לעבור בין וריאציות, לוחצים על התא וריאנט של Active Build במודול. ובוחרים את הווריאציה הרצויה בשדה הרשימה.
פרויקטים עם קוד מקורי/C++
בפרויקטים עם קוד מקורי/C++, החלונית יצירת וריאנטים כוללת 3 אפשרויות עמודות: מודול, Active Build וריאנט ו-Active ABI, כפי שמתואר באיור 2.
איור 2. החלונית יצירת וריאנטים מוסיפה את העמודה Active ABI של עם קוד מקורי/C++.
הערך Active Build וריאנט של המודול קובע את גרסת ה-build שנפרסה ומוצגת בכלי העריכה. במודולים מותאמים, הערך Active ABI קובע את ה-ABI שהעורך משתמשת, אבל היא לא משפיעה על מה שנפרס.
כדי לשנות את סוג ה-build או את ה-ABI:
- לוחצים על התא ווריאנט Active Build. או Active ABI.
- בוחרים את הווריאציה או ה-ABI הרצויים מהרשימה. השדה הזה. סנכרון חדש יופעל באופן אוטומטי.
שינוי של כל אחת מהעמודות של אפליקציה או של ספרייה מחיל את השינוי על כל שורות תלויות.
הגדרת ניהול גרסאות
כברירת מחדל, כש-Gradle יוצר כמה חבילות APK, לכל חבילת APK יש אותו דבר.
פרטי הגרסה, כפי שמצוין ברמת המודול
קובץ build.gradle
או build.gradle.kts
. כי
חנות Google Play אינה מתירה שימוש בחבילות APK מרובות לאותה אפליקציה, שכולן מכילות
פרטי גרסה זהים, צריך לוודא שלכל APK יש מזהה
versionCode
לפני ההעלאה לחנות Play.
ניתן להגדיר את קובץ build.gradle
ברמת המודול כך:
לשנות את המאפיין versionCode
לכל APK. על ידי יצירת מיפוי
שמקצה ערך מספרי ייחודי לכל ABI וצפיפות שאתם מגדירים
כמה חבילות APK עבורם, ניתן לשנות את קוד גרסת הפלט בערך
משלב את קוד הגרסה המוגדר ב-defaultConfig
או
בלוק productFlavors
עם הערך המספרי שהוקצה לפונקציה
צפיפות או ממשק ABI.
בדוגמה הבאה, ה-APK של ממשק ה-ABI של x86
מקבל versionCode
של 2004 ואת ה-ABI של x86_64
מקבל versionCode
של 3004.
הקצאת קודי גרסאות במרווחים גדולים, כמו 1,000, מאפשרת
כדי להקצות קודי גרסאות ייחודיים מאוחר יותר, אם צריך לעדכן את האפליקציה. עבור
לדוגמה, אם defaultConfig.versionCode
חוזר ל-5 ב
לאחר מכן, Gradle מקצה versionCode
של 2005
ה-APK x86
וגרסת 3005 ל-APK של x86_64
.
טיפ: אם ה-build כולל APK אוניברסלי, מקצים לו
versionCode
שהוא נמוך יותר מזה של חבילות ה-APK האחרות שלך.
כי חנות Google Play מתקינה את גרסת האפליקציה שהיא
תואם למכשיר היעד ומתבסס על
versionCode
, מוקצית ערך נמוך יותר של versionCode
חבילת APK אוניברסלית מבטיחה שחנות Google Play תנסה להתקין אחד
חבילות APK לפני חזרה ל-APK האוניברסלי. הקוד לדוגמה הבא
מטפל בכך על ידי לא ביטול ה-APK האוניברסלי
ברירת המחדל היא versionCode
.
מגניב
android { ... defaultConfig { ... versionCode 4 } splits { ... } } // Map for the version code that gives each ABI a value. ext.abiCodes = ['armeabi-v7a':1, x86:2, x86_64:3] // For per-density APKs, create a similar map: // ext.densityCodes = ['mdpi': 1, 'hdpi': 2, 'xhdpi': 3] import com.android.build.OutputFile // For each APK output variant, override versionCode with a combination of // ext.abiCodes * 1000 + variant.versionCode. In this example, variant.versionCode // is equal to defaultConfig.versionCode. If you configure product flavors that // define their own versionCode, variant.versionCode uses that value instead. android.applicationVariants.all { variant -> // Assigns a different version code for each output APK // other than the universal APK. variant.outputs.each { output -> // Stores the value of ext.abiCodes that is associated with the ABI for this variant. def baseAbiVersionCode = // Determines the ABI for this variant and returns the mapped value. project.ext.abiCodes.get(output.getFilter(OutputFile.ABI)) // Because abiCodes.get() returns null for ABIs that are not mapped by ext.abiCodes, // the following code doesn't override the version code for universal APKs. // However, because you want universal APKs to have the lowest version code, // this outcome is desirable. if (baseAbiVersionCode != null) { // Assigns the new version code to versionCodeOverride, which changes the // version code for only the output APK, not for the variant itself. Skipping // this step causes Gradle to use the value of variant.versionCode for the APK. output.versionCodeOverride = baseAbiVersionCode * 1000 + variant.versionCode } } }
Kotlin
android { ... defaultConfig { ... versionCode = 4 } splits { ... } } // Map for the version code that gives each ABI a value. val abiCodes = mapOf("armeabi-v7a" to 1, "x86" to 2, "x86_64" to 3) // For per-density APKs, create a similar map: // val densityCodes = mapOf("mdpi" to 1, "hdpi" to 2, "xhdpi" to 3) import com.android.build.api.variant.FilterConfiguration.FilterType.* // For each APK output variant, override versionCode with a combination of // abiCodes * 1000 + variant.versionCode. In this example, variant.versionCode // is equal to defaultConfig.versionCode. If you configure product flavors that // define their own versionCode, variant.versionCode uses that value instead. androidComponents { onVariants { variant -> // Assigns a different version code for each output APK // other than the universal APK. variant.outputs.forEach { output -> val name = output.filters.find { it.filterType == ABI }?.identifier // Stores the value of abiCodes that is associated with the ABI for this variant. val baseAbiCode = abiCodes[name] // Because abiCodes.get() returns null for ABIs that are not mapped by ext.abiCodes, // the following code doesn't override the version code for universal APKs. // However, because you want universal APKs to have the lowest version code, // this outcome is desirable. if (baseAbiCode != null) { // Assigns the new version code to output.versionCode, which changes the version code // for only the output APK, not for the variant itself. output.versionCode.set(baseAbiCode * 1000 + (output.versionCode.get() ?: 0)) } } } }
לדוגמאות נוספות של סכימות קוד של גרסה חלופית, ראו הקצאת קודי גרסאות.
בניית חבילות APK מרובות
אחרי שמגדירים את build.gradle
ברמת המודול, או
קובץ build.gradle.kts
כדי לבנות כמה חבילות APK, צריך ללחוץ
Build > (פיתוח) מפתחים את ה-APK כדי לבנות את כל חבילות ה-APK שזמינות כרגע
שנבחר בחלונית פרויקט. Gradle יוצרת את חבילות ה-APK
לכל צפיפות או ממשק ABI ב-build/outputs/apk/
של הפרויקט
Gradle יוצרת APK לכל צפיפות או ממשק ABI שמגדירים עבורם כמה חבילות APK. אם מפעילים כמה חבילות APK גם לדחיסות וגם לממשקי ABI, אז Gradle תיצור APK לכל שילוב של צפיפות ו-ABI.
לדוגמה,
קטע הקוד של build.gradle
מאפשר ליצור כמה חבילות APK בשביל mdpi
וגם
צפיפות של hdpi
, וגם ממשקי ABI של x86
ו-x86_64
:
מגניב
... splits { density { enable true reset() include "mdpi", "hdpi" } abi { enable true reset() include "x86", "x86_64" } }
Kotlin
... splits { density { isEnable = true reset() include("mdpi", "hdpi") } abi { isEnable = true reset() include("x86", "x86_64") } }
הפלט מהתצורה לדוגמה כולל את 4 חבילות ה-APK הבאות:
app-hdpiX86-release.apk
: מכיל קוד ומשאבים עבור צפיפות שלhdpi
ו-ABIx86
.app-hdpiX86_64-release.apk
: מכיל קוד ומשאבים עבור צפיפות שלhdpi
ו-ABIx86_64
.app-mdpiX86-release.apk
: מכיל קוד ומשאבים עבור צפיפות שלmdpi
ו-ABIx86
.app-mdpiX86_64-release.apk
: מכיל קוד ומשאבים עבור צפיפות שלmdpi
ו-ABIx86_64
.
כשיוצרים כמה חבילות APK על סמך דחיסות המסך, Gradle תמיד יוצרת APK אוניברסלי שכולל קוד ומשאבים לכל צפיפות הנתונים, בנוסף ל-APKs לכל צפיפות.
כשיוצרים כמה חבילות APK על סמך
ממשק ABI ו-Gradle יוצר רק חבילת APK שכוללת קוד ומשאבים לכולם
ממשקי ABI אם מציינים universalApk true
בלוק אחד (splits.abi
) בקובץ build.gradle
שלך
(בשביל גרובי) או isUniversalApk = true
ב
בלוק אחד (splits.abi
) בקובץ build.gradle.kts
שלך
(לסקריפט Kotlin).
פורמט השם של קובץ APK
כשמפתחים כמה חבילות APK, Gradle יוצרת שמות קובצי APK באמצעות הקוד הבא scheme:
modulename-screendensityABI-buildvariant.apk
רכיבי הסכימה הם:
-
modulename
- מציין את שם המודול שנוצר.
-
screendensity
-
אם מופעלות כמה חבילות APK לדחיסות מסך, מציין את מסך
צפיפות עבור ה-APK, כגון
mdpi
. -
ABI
-
אם הופעלו כמה חבילות APK ל-ABI, מציין את ה-ABI של ה-APK, כמו בתור
x86
.אם הופעלו כמה חבילות APK לדחיסות המסך ול-ABI, לדוגמה, Gradle משרשרת את שם הצפיפות לשם ה-ABI.
mdpiX86
אם המדיניותuniversalApk
מופעלת לכל ABI חבילות APK, Gradle משתמשת ב-universal
כחלק ה-ABI ב-APK האוניברסלי [שם הקובץ]. -
buildvariant
-
מציין את הווריאנט של ה-build, למשל
debug
.
לדוגמה, כשיוצרים חבילת APK לדחיסות מסך של mdpi
עבור
גרסת ניפוי באגים של myApp, שם קובץ ה-APK הוא
myApp-mdpi-debug.apk
. הגרסה
של myApp שהוגדרה לבנות מספר חבילות APK עבור שתי האפליקציות
צפיפות המסך של mdpi
וה-ABI של x86
כולל את שם הקובץ של ה-APK
myApp-mdpiX86-release.apk
.