تنبيه: منذ آب (أغسطس) 2021، سيتم تفعيل جميع الإصدارات يجب نشر التطبيقات على هيئة مجموعات حزمات تطبيق. في حال نشر تطبيقك على Google Play إنشاء مجموعة حزمات تطبيق Android وتحميلها. فعندما إجراء ذلك، ينشئ Google Play حِزم APK محسَّنة ويعرضها تلقائيًا تهيئة الجهاز لكل مستخدم، حتى ينزّل الرمز والموارد فقط يحتاجون إليها لتشغيل تطبيقك. ويكون نشر حِزم APK متعددة أمرًا مفيدًا إذا كنت النشر في متجر لا يتيح تنسيق AAB. في هذه الحالة، إنشاء كل ملف APK وتوقيعه وإدارته بنفسك.
رغم أنه من الأفضل إنشاء حزمة APK واحدة لتتوافق مع جميع أجهزتك المستهدفة كلما أمكن، قد ينتج عن ذلك حجم ملف APK كبير جدًا بسبب الملفات دعم متعددة (كثافات الشاشة) أو Application Binary الواجهات (ABI) تتمثل إحدى طرق تقليل حجم APK في إنشاء ملفات APK متعددة والتي سيحتوي على ملفات لكثافات شاشة أو واجهات تطبيقات ثنائية (ABI) محددة.
يمكن لنظام 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 -
إذا ضبطت هذا العنصر على
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
لإزالة
هذه الكثافات الثلاث من القائمة الافتراضية لجميع الكثافات.
Groovy
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) التي تريد إضافتها.يضبط المقتطف التالي قائمة واجهات التطبيق الثنائية (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
.لاحظ أن هذا الخيار متاح في الجزء
splits.abi
. عند إنشاء حِزم APK متعدّدة استنادًا إلى كثافة الشاشة، تُنشئ Gradle دائمًا حِزمة APK عامة يحتوي على تعليمات برمجية وموارد لجميع كثافات الشاشة.
ينشئ المثال التالي حزمة 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) المتوافقة، يُرجى مراجعة متوافق واجهات التطبيق الثنائية (ABI).
المشاريع بدون رمز أصلي/C++
بالنسبة إلى المشاريع التي لا تحتوي على رمز أصلي/C++ ، تحتوي لوحة Build Variants على اثنتين الأعمدة: الوحدة وActive Build الصيغة، كما هو موضّح في الشكل 1.
الشكل 1. تحتوي لوحة إنشاء صيغ على عمودين للمشاريع التي ليس لها
الرمز الأصلي/C++.
قيمة صيغة الإصدار النشط صيغة الإصدار المنشورة والظاهرة في المحرِّر. للتبديل بين الصيغ، انقر على خلية صيغة الإصدار النشط لإحدى الوحدات. واختر الصيغة المطلوبة من حقل القائمة.
المشاريع التي تستخدم رموز برمجية أصلية/C++
بالنسبة إلى المشاريع التي تستخدم رمزًا برمجيًا أصليًا/C++ ، تحتوي لوحة Build Variants على ثلاث متغيرات الأعمدة: الوحدة وActive Build الصيغة وواجهة التطبيق الثنائية (ABI) النشطة، كما هو موضّح في الشكل 2.
الشكل 2. تضيف لوحة صيغ الإصدار عمود واجهة التطبيق الثنائية (ABI) النشطة من أجل باستخدام رمز أصلي/C++.
قيمة صيغة الإصدار النشط للوحدة صيغة الإصدار المنشورة والتي تظهر في المحرِّر. بالنسبة إلى الوحدات المدمجة مع المحتوى، تحدِّد قيمة واجهة التطبيق الثنائية (ABI) النشطة واجهة التطبيق الثنائية (ABI) التي ضبطها المحرِّر. المستخدم، لكنه لا يؤثر على ما يتم نشره.
لتغيير نوع الإصدار أو واجهة التطبيق الثنائية (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 الخاصة بواجهة التطبيق الثنائية (ABI) التي تعمل بنظام التشغيل x86
يحصل على versionCode
لعام 2004 وx86_64
واجهة التطبيق الثنائية (ABI)
على versionCode
من 3004.
ويتيح تعيين رموز الإصدار بزيادات كبيرة، مثل 1000،
لتعيين رموز إصدارات فريدة لاحقًا إذا احتجت إلى تحديث تطبيقك. بالنسبة
على سبيل المثال، إذا كررت 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
التلقائية.
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] // 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.
لكل كثافة أو واجهة ABI في build/outputs/apk/
الخاصة بالمشروع
الدليل.
تنشئ منصّة Gradle حِزمة APK لكل كثافة أو واجهة التطبيق الثنائية (ABI) التي تضبط لها حِزم APK متعددة. في حال تفعيل عدة حِزم APK لكل من كثافات واجهات التطبيق الثنائية (ABI)، ستُنشئ Gradle حزمة APK. لكل كثافة وواجهة ABI.
على سبيل المثال، ما يلي
يتيح مقتطف build.gradle
إنشاء حِزم APK متعددة لـ mdpi
و
كثافات hdpi
وأيضًا x86
وx86_64
واجهات التطبيق الثنائية (ABI):
Groovy
... 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 متعددة استنادًا إلى
لا تنشئ واجهة التطبيق الثنائية (ABI) سوى حزمة APK التي تتضمّن رموزًا وموارد لجميع التطبيقات.
واجهات التطبيق الثنائية (ABI) في حال تحديد 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
لكل واجهة ABI ملفات APK، يستخدم Gradleuniversal
باعتباره جزء ABI من حزمة APK العامة. . -
buildvariant
-
تُحدِّد صيغة الإصدار التي يتم إنشاؤها، مثل
debug
.
على سبيل المثال، عند إنشاء mdpi
حزمة APK لكثافة الشاشة
إصدار تصحيح الأخطاء من myApp، اسم ملف APK هو
myApp-mdpi-debug.apk
الإصدار
من myApp الذي تم إعداده لإنشاء حِزم APK متعددة لكل من
كثافة الشاشة هي mdpi
ويحتوي واجهة التطبيق الثنائية (ABI) على x86
اسم ملف APK يبلغ
myApp-mdpiX86-release.apk