إذا كان تطبيقك يحتوي على minSdk
من المستوى 20 لواجهة برمجة التطبيقات أو مستوى أقل وكان تطبيقك والملفان
البرمجيان المُشار إليهما يتضمّنان أكثر من 65,536 طريقة، سيظهر لك خطأ الإنشاء التالي الذي
يشير إلى أنّ تطبيقك وصل إلى الحد الأقصى لبنية إنشاء Android:
trouble writing output: Too many field references: 131000; max is 65536. You may try using --multi-dex option.
تُبلغ الإصدارات القديمة من نظام الإنشاء عن خطأ مختلف، ما يشير إلى المشكلة نفسها:
Conversion to Dalvik format failed: Unable to execute dex: method ID not in [0, 0xffff]: 65536
تعرض حالات الخطأ هذه رقمًا شائعًا: 65536. هذا الرقم العدد الإجمالي للمراجع التي يمكن تم استدعاءها بواسطة الرمز البرمجي داخل ملف بايت واحد بتنسيق Dalvik قابل للتنفيذ (DEX). توضِّح هذه الصفحة كيفية تجاوز هذا القيد من خلال تفعيل إعدادات التطبيق المعروفة باسم multidex، والتي تسمح لتطبيقك بإنشاء ملفات DEX متعددة وقراءتها.
لمحة عن الحد الأقصى المسموح به للمراجع الذي يبلغ 64 كيلوبايت
تحتوي ملفات تطبيق Android (APK) على ملفات رمز برمجي قابل للتنفيذ في شكل ملفات Dalvik القابلة للتنفيذ (DEX)، والتي تحتوي على الرمز المجمّع المستخدَم لتشغيل تطبيقك. تحدّ مواصفات Dalvik القابلة للتنفيذ من إجمالي عدد الطرق التي يمكن الإشارة إليها في ملف DEX واحد إلى 65,536، بما في ذلك طرق إطار عمل Android وطرق المكتبة والطرق الواردة في الرمز البرمجي الخاص بك.
في جلسة المعمل، لعلوم الكمبيوتر، فإن المصطلح kilo أو K الذي يشير إلى 1024 (أو 2^10). ولأن 65,536 تساوي 64×1024، يشار إلى هذا الحد _64 ألف حد أقصى لعدد الملفات المرجعية_.دعم Multidex قبل الإصدار Android 5.0
تستخدم إصدارات النظام الأساسي الأقدم من Android 5.0 (المستوى 21 لواجهة برمجة التطبيقات) وقت تشغيل Dalvik
لتنفيذ رمز التطبيق. يحصر Dalvik التطبيقات تلقائيًا في استخدام ملف bytecode واحد فقط
classes.dex
لكل حزمة APK. للتغلب على هذا
القيد، أضِف مكتبة multidex إلى ملف build.gradle
أو
build.gradle.kts
على مستوى الوحدة:
dependencies { def multidex_version = "2.0.1" implementation "androidx.multidex:multidex:$multidex_version" }
dependencies { val multidex_version = "2.0.1" implementation("androidx.multidex:multidex:$multidex_version") }
تصبح هذه المكتبة جزءًا من ملف DEX الأساسي لتطبيقك، ثم يدير الوصول إلى ملفات DEX الإضافية والتعليمات البرمجية التي تحتوي عليها. لعرض النُسخ الحالية لهذه المكتبة، يُرجى مراجعة إصدارات Multidex.
لمزيد من التفاصيل، راجع القسم الخاص بكيفية ضبط تطبيقك لـ Multidexإتاحة حِزم Multidex لنظام التشغيل Android 5.0 والإصدارات الأحدث
يستخدم Android 5.0 (المستوى 21 من واجهة برمجة التطبيقات) والإصدارات الأحدث بيئة تشغيل تُسمى ART
تتيح في الأصل تحميل ملفات DEX متعددة من ملفات APK. الفن
التجميع المسبق للبيانات في وقت تثبيت التطبيق، ويبحث عن
classesN.dex
ملف وتجميعها في ملف واحد
ملف OAT لـ
الجهاز الذي يعمل بنظام التشغيل Android. لذلك، إذا كانت minSdkVersion
إذا كان عمر 21 عامًا أو أكثر، يتم تفعيل ميزة Multidex تلقائيًا ولا تحتاج إلى مكتبة Multidex.
لمزيد من المعلومات عن وقت تشغيل Android 5.0 ، يُرجى الاطّلاع على مقالة Android Runtime (ART) وDalvik.
ملاحظة: عند تشغيل تطبيقك باستخدام "استوديو Android"، اتّبِع الخطوات التالية: يتم تحسين التصميم للأجهزة المستهدفة التي تنشر عليها. ويشمل ذلك تفعيل إمكانية التشغيل المتعدّد عندما تكون الأجهزة المستهدفة قيد التشغيل. الإصدار 5.0 من Android والإصدارات الأحدث. ولأن هذا التحسين لا يتم تطبيقه إلا عند نشر التطبيق باستخدام قد لا تزال بحاجة إلى ضبط إصدار الإصدار على "استوديو Android". لـ Multidex.لتجنب حد 64 كيلوبايت.
تجنُّب الحدّ الأقصى البالغ 64 كيلوبايت
قبل إعداد تطبيقك لإتاحة استخدام فيديوهات بتنسيق 64K أو أكثر، يُرجى اتّباع الخطوات التالية: لتقليل إجمالي عدد المراجع التي يطلبها رمز التطبيق، بما في ذلك الطرق التي تحدّدها رمز تطبيقك أو المكتبات المضمنة.
يمكن أن تساعدك الاستراتيجيات التالية في تجنُّب بلوغ الحدّ الأقصى لمرجع DEX:
- مراجعة التبعيات المباشرة والمتعدية لتطبيقك
- التفكير في ما إذا كانت قيمة أي تبعية كبيرة للمكتبة تُدرجها في تطبيقك تفوق عدد الرموز البرمجية التي تتم إضافتها إلى التطبيق. هناك نمط شائع ولكن إشكالي هو تضمين مكتبة كبيرة جدًا لأن بعض طرق المنفعة كانت مفيدة. غالبًا ما يساعد تقليل اعتماديات رمز تطبيقك تجنب الحد الأقصى لمراجع DEX.
- إزالة الرمز غير المستخدَم باستخدام R8
- فعِّل ميزة تقليل حجم الرموز لتشغيل R8 في عمليات إنشاء الإصدارات. يمكنك تفعيل التقليل للمساعدة في ضمان لا تشحن رمزًا غير مستخدَم باستخدام حِزم APK إذا تمت تهيئة تقليص التعليمات البرمجية بشكل صحيح، أيضًا إزالة التعليمات البرمجية والموارد غير المستخدمة من تبعياتك.
ويمكن أن يساعدك استخدام هذه الأساليب في خفض الحجم الإجمالي لملف APK لتجنُّب الحاجة إلى تعدد الأذونات في تطبيقك
ضبط تطبيقك للاستفادة من ميزة "متعدد الإصدارات"
ملاحظة: إذا تم ضبطminSdkVersion
على 21 أو إصدار أحدث، سيتم تفعيل حزمة multidex تلقائيًا
ولن تحتاج إلى مكتبة multidex.
وإذا تم ضبط minSdkVersion
على 20 أو أقل، يجب:
استخدام
مكتبة Multidex وإجراء
التعديلات التالية على مشروع تطبيقك:
-
عدِّل ملف
build.gradle
على مستوى الوحدة لأجل تفعيل حزمة multidex وإضافة مكتبة multidex كعنصر تابع، كما هو موضّح هنا:android { defaultConfig { ... minSdkVersion 15 targetSdkVersion 33 multiDexEnabled true } ... } dependencies { implementation "androidx.multidex:multidex:2.0.1" }
android { defaultConfig { ... minSdk = 15 targetSdk = 33 multiDexEnabled = true } ... } dependencies { implementation("androidx.multidex:multidex:2.0.1") }
- استنادًا إلى ما إذا كنت تريد إلغاء فئة
Application
، نفِّذ أحد الإجراءات التالية:إذا لم تلغي فئة
Application
، عدِّل ملف البيان لضبطandroid:name
في العلامة<application>
على النحو التالي:<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.myapp"> <application android:name="androidx.multidex.MultiDexApplication" > ... </application> </manifest>
في حال إلغاء
Application
الفئة، قم بتغييرها إلىMultiDexApplication
كما يلي:في حال إلغاء
Application
الفئة ولكن لا يمكن تغيير الفئة الأساسية، فعندئذ بدلاً من ذلك، إلغاء طريقةattachBaseContext()
والاتصال بـMultiDex.install(this)
للتفعيل :multidex:class MyApplication : SomeOtherApplication() { override fun attachBaseContext(base: Context) { super.attachBaseContext(base) MultiDex.install(this) } }
public class MyApplication extends SomeOtherApplication { @Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); MultiDex.install(this); } }
تحذير: لا تنفِّذ
MultiDex.install()
أو أي رمز برمجي آخر من خلال ميزة Reflection أو JNI قبل اكتمالMultiDex.install()
. سيساعدك تتبع الارتباطات المتعددة عدم متابعة هذه المكالمات، ما يؤدي إلى حدوثClassNotFoundException
أو التحقّق من الأخطاء بسبب تقسيم فئة غير صالح بين ملفات DEX.
الآن عند إنشاء تطبيقك، تُنشئ أدوات إنشاء Android ملف DEX أساسيًا (classes.dex
) وملفات DEX داعمة (classes2.dex
وclasses3.dex
وما إلى ذلك) حسب الحاجة.
بعد ذلك، يعمل نظام الإصدار على تجميع جميع ملفات DEX في حزمة APK.
أثناء التشغيل، بدلاً من البحث في ملف classes.dex
الرئيسي فقط، تستخدِم واجهات برمجة تطبيقات حِزم DEX المتعددة أداة تحميل فئة خاصة للبحث في جميع ملفّات classes.dex
المتاحة عن طريقطك.
حدود مكتبة الوسائط المتعددة
هناك بعض القيود المعروفة في مكتبة الوسائط المتعددة. عند دمج المكتبة في إعدادات إنشاء تطبيقك، يجب مراعاة ما يلي:
- إنّ تثبيت ملفات DEX أثناء بدء التشغيل على قسم بيانات الجهاز عملية معقدة، ويمكن أن تؤدي إلى أخطاء "التطبيق لا يستجيب" (ANR) إذا كانت ملفات DEX الثانوية كبيرة. إلى لتجنُّب هذه المشكلة، يمكنك تفعيل تقليص الرموز للحدّ من حجم ملفات DEX وإزالة الأجزاء غير المستخدمة من التعليمات البرمجية.
- عند تشغيل التطبيق على إصدارات أقدم من Android 5.0 (المستوى 21 من واجهة برمجة التطبيقات)، فإن استخدام
لا يكفي استخدام Multidex للتوافق مع الحد الخطي (المشكلة 37008143). تم رفع هذا الحدّ في
الإصدار 4.0 من نظام التشغيل Android (المستوى 14 من واجهة برمجة التطبيقات)، ولكنّ ذلك لم يحلّ المشكلة بالكامل.
في الإصدارات الأقدم من Android 4.0، قد تصل إلى الحد الأقصى لمساحة التخزين في ذاكرة التخزين المؤقت قبل بلوغ الحد الأقصى لفهرسة DEX. لذلك إذا كنت تستهدف مستويات واجهة برمجة تطبيقات أقل من 14، اختبر جيدًا على تلك الإصدارات من النظام الأساسي، لأن تطبيقك قد إذا واجهت بعض المشكلات عند بدء التشغيل أو عند تحميل مجموعات معينة من الفئات.
يمكن أن تقلِّل تصغير الرموز البرمجية من هذه المشاكل أو تقضي عليها.
تحديد الفئات المطلوبة في ملف DEX الأساسي
عند إنشاء كل ملف DEX لتطبيق متعدّد DEX، تُجري أدوات الإنشاء عملية اتخاذ قرارات معقدة لتحديد الفئات المطلوبة في ملف DEX الأساسي كي يتمكّن تطبيقك من البدء بنجاح. إذا كانت هناك أي فئة مطلوبة
أثناء بدء التشغيل في ملف DEX الأساسي، فسيتعطّل التطبيق
مع الخطأ java.lang.NoClassDefFoundError
.
تتعرّف أدوات التصميم على مسارات الرموز البرمجية التي يمكن الوصول إليها مباشرةً من تطبيقك. الرمز. ومع ذلك، يمكن أن تحدث هذه المشكلة عندما تكون مسارات الرموز البرمجية أقل ظهورًا، مثل عندما تحتوي المكتبة التي تستخدمها على تبعيات معقّدة. على سبيل المثال، إذا كان الرمز يستخدم التأمل الداخلي أو الاستدعاء من طرق Java من خلال التعليمات البرمجية الأصلية، فقد لا يتم التعرف على هذه الفئات المطلوبة في ملف DEX الأساسي.
إذا تلقّيت الخطأ java.lang.NoClassDefFoundError
،
عليك تحديد الفئات الإضافية المطلوبة يدويًا في ملف DEX
الأساسي من خلال الإفصاح عنها باستخدام السمة multiDexKeepProguard
في نوع الإنشاء. إذا تم مطابقة فئة فيملفmultiDexKeepProguard
، تتم إضافة هذه الفئة إلى ملف DEX الأساسي.
سمة multiDexKeepProguard
يستخدم ملف multiDexKeepProguard
التنسيق نفسه المستخدَم في ProGuard ويتوافق مع نحو ProGuard بالكامل. لمزيد من المعلومات عن كيفية تخصيص المحتوى الذي يتم الاحتفاظ به في تطبيقك، اطّلِع على مقالة
تخصيص الرموز البرمجية التي يتم الاحتفاظ بها.
يجب أن يحتوي الملف الذي تحدّده في multiDexKeepProguard
على خيارات -keep
في أيّ صيغة صالحة من ProGuard. على سبيل المثال:
-keep com.example.MyClass.class
يمكنك إنشاء ملف يسمى
multidex-config.pro
الذي يبدو كما يلي:
-keep class com.example.MyClass -keep class com.example.MyClassToo
إذا كنت تريد تحديد جميع الفئات في حزمة، سيبدو الملف كما يلي:
-keep class com.example.** { *; } // All classes in the com.example package
يمكنك بعد ذلك الإفصاح عن هذا الملف لنوع الإصدار على النحو التالي:
android { buildTypes { release { multiDexKeepProguard file('multidex-config.pro') ... } } }
android { buildTypes { getByName("release") { multiDexKeepProguard = file("multidex-config.pro") ... } } }
تحسين حِزم multidex في إصدارات التطوير
تتطلّب عملية إعداد حِزم متعددة بتنسيق DEX وقتًا متزايدًا بشكل كبير لمعالجة عملية الإنشاء، لأنّ نظام الإنشاء يجب أن يتّخذ قرارات معقّدة بشأن الفئات التي يجب تضمينها في ملف DEX الأساسي والفئات التي يمكن تضمينها في ملفات DEX الثانوية. وهذا يعني أنّ عمليات الإنشاء المتزايدة باستخدام multidex تستغرق عادةً وقتًا أطول وقد تبطئ عملية التطوير.
للتخفيف من أوقات الإنشاء المتزايدة، استخدم
pre-dexing لإعادة استخدام إخراج Multidex بين الإصدارات.
تعتمد ميزة "الترميز المُسبَق" على تنسيق ART غير المتوفّر إلا على الإصدار 5.0 من Android
(المستوى 21 من واجهة برمجة التطبيقات) والإصدارات الأحدث. إذا كنت تستخدم "استوديو Android"، سيستخدم IDE تلقائيًا ميزة الفهرسة المُسبقة.
عند نشر تطبيقك على جهاز يعمل بالإصدار 5.0 من نظام التشغيل Android (المستوى 21 من واجهة برمجة التطبيقات) أو بإصدارات أحدث.
ومع ذلك، إذا كنت تُشغّل عمليات إنشاء Gradle من سطر الأوامر، عليك ضبط
minSdkVersion
على 21 أو إصدار أحدث لتفعيل ميزة "المعالجة المسبقة للغة Java".
minSdkVersion
،
كما هو موضح:
android { defaultConfig { ... multiDexEnabled true // The default minimum API level you want to support. minSdkVersion 15 } productFlavors { // Includes settings you want to keep only while developing your app. dev { // Enables pre-dexing for command-line builds. When using // Android Studio 2.3 or higher, the IDE enables pre-dexing // when deploying your app to a device running Android 5.0 // (API level 21) or higher, regardless of minSdkVersion. minSdkVersion 21 } prod { // If you've configured the defaultConfig block for the production version of // your app, you can leave this block empty and Gradle uses configurations in // the defaultConfig block instead. You still need to include this flavor. // Otherwise, all variants use the "dev" flavor configurations. } } buildTypes { release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { implementation "androidx.multidex:multidex:2.0.1" }
android { defaultConfig { ... multiDexEnabled = true // The default minimum API level you want to support. minSdk = 15 } productFlavors { // Includes settings you want to keep only while developing your app. create("dev") { // Enables pre-dexing for command-line builds. When using // Android Studio 2.3 or higher, the IDE enables pre-dexing // when deploying your app to a device running Android 5.0 // (API level 21) or higher, regardless of minSdkVersion. minSdk = 21 } create("prod") { // If you've configured the defaultConfig block for the production version of // your app, you can leave this block empty and Gradle uses configurations in // the defaultConfig block instead. You still need to include this flavor. // Otherwise, all variants use the "dev" flavor configurations. } } buildTypes { getByName("release") { isMinifyEnabled = true proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro") } } } dependencies { implementation("androidx.multidex:multidex:2.0.1") }
للتعرّف على المزيد من الاستراتيجيات للمساعدة في تحسين سرعات الإنشاء من "استوديو Android" أو سطر الأوامر، يمكنك الاطّلاع على مقالة تحسين سرعة الإنشاء. لمزيد من المعلومات عن استخدام صيغ الإصدار، يُرجى الاطّلاع على ضبط صيغ الإصدار
ملاحظة: إذا كانت لديك صيغ مختلفة لإصدارات مختلفة
متعددة، يمكنك تقديم ملف بيان مختلف لكل منها
لذلك، لا يتم تغيير سوى ملف المستوى 20 لواجهة برمجة التطبيقات الأقل
اسم العلامة <application>
يمكنك أيضًا
إنشاء فئة فرعية مختلفة من Application
لكل صيغة لكي
لا تُوسِّع فئة MultiDexApplication
أو
تطلب MultiDex.install(this)
إلا الفئة الفرعية للمستوى 20 من واجهة برمجة التطبيقات والإصدارات الأقدم.
اختبار التطبيقات التي تستخدم ملفات DEX متعددة
عند كتابة اختبارات أداة القياس لتطبيقات حِزم متعددة، لن تكون هناك حاجة إلى ضبط أي إعدادات إضافية
إذا كنت تستخدم أداة قياس
MonitoringInstrumentation
أو
AndroidJUnitRunner
. إذا كنت تستخدم
Instrumentation
آخر،
عليك إلغاء طريقة onCreate()
باستخدام الرمز التالي:
fun onCreate(arguments: Bundle) { MultiDex.install(targetContext) super.onCreate(arguments) ... }
public void onCreate(Bundle arguments) { MultiDex.install(getTargetContext()); super.onCreate(arguments); ... }