ملاحظة: منذ آب (أغسطس) 2 2011، يجب نشر جميع التطبيقات الجديدة بتنسيق "مجموعة حزمات تطبيق". إذا كنت تنشر تطبيقك على Google Play، أنشئ مجموعة حزمات تطبيق Android وحمِّلها. عند إجراء ذلك، ينشئ Google Play تلقائيًا حِزم APK محسّنة ويعرضها لإعدادات جهاز كل مستخدم، حتى لا يتم تنزيل سوى الرمز البرمجي والموارد التي يحتاجها لتشغيل تطبيقك. يكون نشر حِزم APK متعددة مفيدًا إذا كنت تريد نشر تطبيقك على متجر لا يتيح استخدام تنسيق AAB. في هذه الحالة، عليك إنشاء كل حزمة APK وتوقيعها وإدارتها بنفسك.
على الرغم من أنّه من الأفضل إنشاء حزمة APK واحدة متوافقة مع جميع أجهزتك المستهدَفة كلما أمكن ذلك، قد يؤدي ذلك إلى إنشاء حزمة APK كبيرة جدًا بسبب الملفات المتوافقة مع قيم كثافة شاشة أو واجهات برمجة التطبيقات (ABI) متعددة. من الطرق التي يمكنك من خلالها تقليل حجم حزمة APK هي إنشاء حِزم APK متعددة تحتوي على ملفات لكثافة شاشة أو واجهات برمجة تطبيقات معيّنة.
يمكن أن تنشئ Gradle حِزم APK منفصلة تحتوي فقط على الرموز البرمجية والموارد الخاصة بكل كثافة أو معرّف بنية التطبيق (ABI). توضّح هذه الصفحة كيفية ضبط عملية الإنشاء لأجل إنشاء حِزم APK متعددة. إذا كنت بحاجة إلى إنشاء إصدارات مختلفة من تطبيقك لا تستند إلى كثافة الشاشة أو ABI، استخدِم صيغ الإصدار بدلاً من ذلك.
ضبط الإصدار لإنشاء حِزم APK متعددة
لضبط عملية الإنشاء لإنشاء حِزم APK متعددة، أضِف كتلة
splits
إلى ملف
build.gradle
على مستوى الوحدة. ضمن العنصر
splits
، قدِّم عنصرًا
density
يحدِّد الطريقة التي تريد من Gradle بها إنشاء
حِزم APK لكل كثافة أو عنصرًا abi
يحدِّد الطريقة التي تريد من Gradle بها إنشاء
حِزم APK لكل ABI. يمكنك تقديم كل من كتل كثافة الشاشة وABI، وينشئ نظام الإنشاء حزمة APK لكل مجموعة من كثافة الشاشة وABI.
ضبط حِزم APK متعددة لكثافة الشاشة
لإنشاء حِزم APK منفصلة لكثافات شاشة مختلفة، أضِف كتلة
density
داخل كتلة
splits
. في العنصر density
، قدِّم
قائمة بكثافات الشاشة المطلوبة وأحجام الشاشة المتوافقة. لا تستخدِم قائمة
أحجام الشاشات المتوافقة إلا إذا كنت بحاجة إلى عناصر
<compatible-screens>
معيّنة في بيان كل ملف APK.
تُستخدَم خيارات Gradle DSL التالية لضبط حِزم APK متعددة لكثافات الشاشة التالية:
-
enable
لملف Groovy، وisEnable
لملف Kotlin script -
في حال ضبط هذا العنصر على
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 المخصّصة لكل كثافة لتقديم بديل لأجهزة
التي لا تتطابق مع حِزم APK التي تتضمّن علامة
<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") } } }
لمزيد من التفاصيل حول تخصيص إصدارات مختلفة من تطبيقك لأنواع شاشات وأجهزة معيّنة، يُرجى الاطّلاع على الإفصاح عن توافق الشاشة المحدود.
ضبط حِزم 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 على
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 لكل واجهة برمجة تطبيقات ثنائية. تحتوي حزمة APK العامة على رمز وموارد لجميع واجهات برمجة التطبيقات (ABI) في حزمة APK واحدة. تكون القيمة التلقائيةfalse
.يُرجى العلم أنّ هذا الخيار لا يتوفّر إلا في مجموعة
splits.abi
. عند إنشاء حِزم APK متعددة بناءً على كثافة الشاشة، ينشئ Gradle دائمًا حزمة APK عامة تحتوي على الرموز البرمجية والموارد لجميع كثافات الشاشة.
ينشئ المثال التالي حزمة APK منفصلة لكل بنية أساسية للتطبيق: 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++، تحتوي لوحة صيغة الإصدار على عمودَين: الوحدة وصيغة الإصدار النشطة، كما هو موضّح في الشكل 1.
الشكل 1. تحتوي لوحة نُسخ الإصدار على عمودَين للمشاريع التي لا تحتوي على رمز برمجي برمجي/C++.
تحدِّد قيمة صيغة الإصدار النشطة لملف الوحدة نوع الإصدار الذي يتم نشره وظهوره في المحرِّر. للتبديل بين الصيغ، انقر على خلية صيغة الإصدار النشطة لأحد الوحدات واختَر الصيغة المطلوبة من حقل القائمة.
المشاريع التي تحتوي على رمز برمجي أصلي/C++
بالنسبة إلى المشاريع التي تحتوي على رمز برمجي أصلي/C++، تحتوي لوحة صيغة الإصدار على ثلاثة عمودين: الوحدة وصيغة الإصدار النشطة وActive ABI، كما هو موضّح في الشكل 2.
الشكل 2: تضيف لوحة نُسخ الإصدار عمود Active ABI لمشاريع التي تحتوي على رمز برمجي أصلي/C++.
تحدِّد قيمة صيغة الإصدار النشطة للوحدة صيغة الإصدار التي يتم نشرها وتكون مرئية في المحرِّر. بالنسبة إلى الوحدات الأصلية، تحدِّد قيمة Active ABI معرّف ABI الذي يستخدمه المحرِّر، ولكنّها لا تؤثّر في ما يتم نشره.
لتغيير نوع الإصدار أو ABI:
- انقر على خلية عمود Active Build Variant (صيغة الإصدار النشطة) أو 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 لملف تعريف ABIx86
على versionCode
2004 ويحصل ملف تعريف ABIx86_64
على versionCode
3004.
يتيح لك منح رموز الإصدارات بزيادة كبيرة، مثل 1000، منح رموز إصدار فريدة في وقت لاحق إذا كنت بحاجة إلى تحديث تطبيقك. على سبيل المثال، إذا تكررت عملية defaultConfig.versionCode
إلى 5 في تحديث لاحق، يمنح Gradle versionCode
بقيمة 2005 لملف APKx86
و3005 لملف APKx86_64
.
ملاحظة: إذا كان الإصدار يتضمّن حزمة APK عامة، يجب تحديد قيمة
versionCode
لها تكون أقل من قيمة أي من حِزم APK الأخرى.
بما أنّ "متجر Google Play" يُثبِّت إصدار تطبيقك الذي
يكون متوافقًا مع الجهاز المستهدَف ويحتوي على
versionCode
الأعلى، فإنّ منح قيمة versionCode
أقل لملف APK
العام يضمن أن يحاول "متجر Google Play" تثبيت أحد
حِزم APK قبل الرجوع إلى حزمة APK العامة. يعالج نموذج التعليمات البرمجية التالي
هذه المشكلة من خلال عدم إلغاء القيمة التلقائيةversionCode
لملف APK الموحّد.
رائع
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 متعددة، انقر على
إنشاء > إنشاء حِزم APK لإنشاء جميع حِزم APK للوحدة التي تم اختيارها حاليًا في لوحة المشروع. ينشئ Gradle حِزم APK
لكل كثافة أو معرّف بنية التطبيق الأساسية في دليل 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") } }
تتضمّن النتيجة من مثال الضبط ملفات APK الأربعة التالية:
-
app-hdpiX86-release.apk
: يحتوي على رمز وموارد لكثافةhdpi
وx86
ABI. -
app-hdpiX86_64-release.apk
: يحتوي على رمز وموارد لكثافةhdpi
وx86_64
ABI. -
app-mdpiX86-release.apk
: يحتوي على رمز وموارد لكثافةmdpi
وx86
ABI. -
app-mdpiX86_64-release.apk
: يحتوي على رمز وموارد لكثافةmdpi
وx86_64
ABI.
عند إنشاء حِزم APK متعددة استنادًا إلى كثافة الشاشة، ينشئ Gradle دائمًا حزمة APK عامة تتضمّن الرموز البرمجية والموارد لجميع كثافات الشاشة، بالإضافة إلى حِزم APK لكل كثافة شاشة.
عند إنشاء حِزم APK متعددة استنادًا إلى IDE، لا ينشئ Gradle حزمة APK تتضمّن الرمز البرمجي والموارد لجميع IDE إلا إذا حدّدت universalApk true
في مجموعة splits.abi
في ملف build.gradle
(للغة Groovy) أو isUniversalApk = true
في مجموعة splits.abi
في ملف build.gradle.kts
(لنص Kotlin).
تنسيق اسم ملف APK
عند إنشاء حِزم APK متعددة، ينشئ Gradle أسماء حِزم APK باستخدام الطريِق التالية:
modulename-screendensityABI-buildvariant.apk
مكونات المخطّط هي:
-
modulename
- لتحديد اسم الوحدة التي يتم إنشاؤها.
-
screendensity
-
في حال تفعيل حِزم APK متعددة لكثافة الشاشة، يُستخدَم هذا المَعلمة لتحديد كثافة الشاشة لملف APK، مثل
mdpi
. -
ABI
-
في حال تفعيل حِزم APK متعددة لواجهة ABI، حدِّد واجهة ABI لحزمة APK، مثل
x86
.في حال تفعيل حِزم APK متعددة لكل من كثافة الشاشة وABI، تُجمِّع Gradle اسم الكثافة مع اسم ABI، على سبيل المثال
mdpiX86
. في حال تفعيلuniversalApk
لحِزم APK الخاصة بكل واجهة برمجة تطبيقات (ABI)، يستخدم Gradleuniversal
كجزء من واجهة ABI في اسم حِزمة APK العامة. -
buildvariant
-
يحدِّد هذا العنصر نوع الإصدار الذي يتم إنشاؤه، مثل
debug
.
على سبيل المثال، عند إنشاء حزمة APK لكثافة شاشة mdpi
لإصدار debugging من myApp، يكون اسم ملف APK هو
myApp-mdpi-debug.apk
. إصدار
تطبيق myApp الذي تم إعداده لإنشاء حِزم APK متعددة لكل من
كثافة الشاشة mdpi
وملف ABI x86
يحتوي على اسم ملف APK هو
myApp-mdpiX86-release.apk
.