שימו לב: מאז אוגוסט 2021, כל האפליקציות החדשות חייבות להתפרסם כקובצי App Bundle. אם אתם מפרסמים את האפליקציה ב-Google Play, אתם צריכים ליצור ולהעלות Android App Bundle. כשמפרסמים כמה חבילות APK, מערכת Google Play יוצרת ומציגה באופן אוטומטי חבילות APK שעברו אופטימיזציה לכל תצורת מכשיר של משתמש, כך שהמשתמשים מורידים רק את הקוד והמשאבים שדרושים להם כדי להפעיל את האפליקציה. פרסום של כמה חבילות APK שימושי אם אתם מפרסמים בחנות שלא תומכת בפורמט AAB. במקרה כזה, תצטרכו ליצור, לחתום ולנהל כל APK בעצמכם.
עדיף ליצור קובץ APK יחיד כדי לתמוך בכל מכשירי היעד, אבל לפעמים זה עלול לגרום לקובץ APK גדול מאוד בגלל קבצים שתומכים בכמה ממשקי ABI. אחת הדרכים להקטין את גודל קובץ ה-APK היא ליצור חבילות APK מרובות שמכילות קבצים עבור ממשקי ABI ספציפיים.
מערכת Gradle יכולה ליצור קובצי APK נפרדים שמכילים רק קוד ומשאבים שספציפיים לכל ABI. בדף הזה מוסבר איך להגדיר את תהליך הבנייה כדי ליצור כמה קובצי APK. אם אתם צריכים ליצור גרסאות שונות של האפליקציה שלא מבוססות על ABI, אתם יכולים להשתמש בוריאציות של build.
הגדרת גרסת ה-build לכמה חבילות APK
כדי להגדיר את ה-build למספר חבילות APK, מוסיפים בלוק
splits לקובץ build.gradle ברמת המודול. בתוך הבלוק splits, מספקים בלוק abi שמציין איך רוצים ש-Gradle ייצור קובצי APK לכל ABI.
הגדרת כמה חבילות 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ל-Groovy אוisUniversalApkלסקריפט Kotlin -
אם
true, Gradle יוצר APK אוניברסלי בנוסף לחבילות APK לכל ממשק ABI. חבילת APK אוניברסלית מכילה קוד ומשאבים לכל ממשקי ה-ABI בחבילת APK אחת. ערך ברירת המחדל הואfalse.
בדוגמה הבאה נוצר קובץ APK נפרד לכל ABI: x86
ו-x86_64. כדי לעשות את זה, משתמשים ב-reset()
כדי להתחיל עם רשימה ריקה של ממשקי ABI, ואז משתמשים ב-include עם רשימה של ממשקי ABI שכל אחד מהם מקבל APK.
Groovy
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 הנתמכים מופיעה כאן.
פרויקטים ללא קוד מקורי או קוד ++C
בפרויקטים ללא קוד מקורי או קוד C++, בחלונית Build Variants יש שתי עמודות: Module ו-Active Build Variant, כמו שמוצג באיור 1.

איור 1. בחלונית Build Variants יש שתי עמודות לפרויקטים ללא קוד native/C++.
הערך של Active Build Variant במודול קובע את גרסת ה-build שמוצגת בעורך. כדי לעבור בין וריאציות, לוחצים על התא Active Build Variant (וריאציית Build פעילה) של מודול ובוחרים את הווריאציה הרצויה מתוך רשימת השדות.
פרויקטים עם קוד מקורי או קוד C++
בפרויקטים עם קוד מקורי או קוד C++, בחלונית Build Variants יש שלוש עמודות: Module, Active Build Variant ו-Active ABI, כמו שמוצג באיור 2.
איור 2. בחלונית Build Variants (יצירת וריאציות של Build) נוספת העמודה Active ABI (ממשק ABI פעיל) לפרויקטים עם קוד מקורי או קוד C++.
הערך של Active Build Variant (גרסת build פעילה) עבור המודול קובע את גרסת ה-build שנפרסת ומוצגת בכלי העריכה. במודולים מקוריים, הערך של Active ABI קובע את ה-ABI שבו נעשה שימוש בעורך, אבל לא משפיע על מה שנפרס.
כדי לשנות את סוג ה-build או את ה-ABI:
- לוחצים על התא בעמודה Active Build Variant (גרסת Build פעילה) או Active ABI (ממשק 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 של x86 ABI
מקבל versionCode של 2004 ו-x86_64 ABI
מקבל versionCode של 3004.
הקצאת קודי גרסה במרווחים גדולים, כמו 1,000, מאפשרת לכם להקצות קודי גרסה ייחודיים מאוחר יותר אם תצטרכו לעדכן את האפליקציה. לדוגמה, אם defaultConfig.versionCode חוזר על עצמו עד 5 בעדכון הבא, Gradle מקצה את הערך versionCode של 2005 ל-APK של x86 ואת הערך 3005 ל-APK של x86_64.
טיפ: אם הגרסה שלכם כוללת APK אוניברסלי, צריך להקצות לו versionCode נמוך מזה של כל חבילות ה-APK האחרות.
מכיוון שאפליקציית חנות Google Play מתקינה את גרסת האפליקציה שתואמת למכשיר היעד ושיש לה את versionCode הכי גבוה, הקצאת versionCode נמוך יותר לחבילת ה-APK האוניברסלית מבטיחה שאפליקציית חנות Google Play תנסה להתקין אחת מחבילות ה-APK לפני שתחזור לחבילת ה-APK האוניברסלית. בדוגמת הקוד הבאה
הטיפול בבעיה מתבצע על ידי אי-שינוי ברירת המחדל versionCode של קובץ APK אוניברסלי.
Groovy
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] 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) 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 > Build APK (יצירה > יצירת קובץ APK) כדי ליצור את כל קובצי ה-APK של המודול שנבחר כרגע בחלונית Project (פרויקט). Gradle יוצר את קובצי ה-APK לכל ABI בספרייה build/outputs/apk/ של הפרויקט.
Gradle יוצר חבילת APK לכל ABI שאתם מגדירים עבורו כמה חבילות APK.
לדוגמה, קטע הקוד build.gradle הבא מאפשר ליצור כמה קובצי APK עבור ממשקי האפליקציה הבינאריים x86 ו-x86_64:
Groovy
... splits { abi { enable true reset() include "x86", "x86_64" } }
Kotlin
... splits { abi { isEnable = true reset() include("x86", "x86_64") } }
הפלט מהגדרת הדוגמה כולל את 4 קובצי ה-APK הבאים:
-
app-X86-release.apk: מכיל קוד ומשאבים עבורx86ABI. -
app-X86_64-release.apk: מכיל קוד ומשאבים עבורx86_64ABI.
כשיוצרים כמה קובצי APK על סמך ABI, Gradle יוצר רק קובץ APK שכולל קוד ומשאבים לכל ה-ABI אם מציינים universalApk true בבלוק splits.abi בקובץ build.gradle (ב-Groovy) או isUniversalApk = true בבלוק splits.abi בקובץ build.gradle.kts (בסקריפט Kotlin).
פורמט של שם קובץ APK
כשיוצרים כמה קובצי APK, Gradle יוצר שמות של קובצי APK באמצעות הסכימה הבאה:
modulename-ABI-buildvariant.apk
הרכיבים של הסכימה הם:
-
modulename - מציין את שם המודול שנבנה.
-
ABI -
אם מופעלות כמה חבילות APK ל-ABI, מציינים את ה-ABI של חבילת ה-APK, כמו
x86. -
buildvariant -
מציין את וריאציית ה-build שנוצרת, כמו
debug.