تفعيل ميزة "الاتصال المتعدد" للتطبيقات التي تتضمّن أكثر من 64 ألف طريقة

إذا كان تطبيقك يحتوي على 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) على ملفات رموز بايت قابلة للتنفيذ في النموذج من دالفيك الملفات القابلة للتنفيذ (DEX) التي تحتوي على الرمز البرمجي المجمَّع المستخدَم لتشغيل تطبيقك. تحد مواصفات Dalvik التنفيذية من إجمالي عدد الطرق التي ضمن ملف DEX واحد إلى 65536، بما في ذلك Android وأساليب إطار العمل وطرق المكتبة والطرق في التعليمات البرمجية الخاصة بك.

في جلسة المعمل، لعلوم الكمبيوتر، فإن المصطلح kilo أو K الذي يشير إلى 1024 (أو 2^10). ولأن 65,536 تساوي 64×1024، يُشار إلى هذا الحد _64 ألف حد أقصى لعدد الملفات المرجعية_.

دعم Multidex قبل الإصدار Android 5.0

تستخدم إصدارات النظام الأساسي التي تسبق Android 5.0 (مستوى واجهة برمجة التطبيقات 21) ملف Dalvik وقت التشغيل لتنفيذ رمز التطبيق. بشكل تلقائي، تقصر Dalvik التطبيقات على إصدار واحد ملف رمز بايت واحد (classes.dex) لكل حزمة APK للتحايل على هذا إضافة مكتبة الوسائط المتعددة إلى build.gradle على مستوى الوحدة أو build.gradle.kts الملف:

Groovy

dependencies {
    def multidex_version = "2.0.1"
    implementation "androidx.multidex:multidex:$multidex_version"
}

Kotlin

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 (ART)" وDalvik.

ملاحظة: عند تشغيل تطبيقك باستخدام "استوديو Android"، اتّبِع الخطوات التالية: يتم تحسين التصميم للأجهزة المستهدفة التي تنشر عليها. ويشمل ذلك تفعيل إمكانية التشغيل المتعدّد عندما تكون الأجهزة المستهدفة قيد التشغيل. الإصدار 5.0 من Android والإصدارات الأحدث. ولأن هذا التحسين لا يتم تطبيقه إلا عند نشر التطبيق باستخدام قد لا تزال بحاجة إلى ضبط إصدار الإصدار على "استوديو Android". لـ Multidex.لتجنب حد 64 كيلوبايت.

تجنَّب الوصول إلى عدد أكبر من 64 ألف

قبل إعداد تطبيقك لإتاحة استخدام فيديوهات بتنسيق 64K أو أكثر، يُرجى اتّباع الخطوات التالية: لتقليل إجمالي عدد المراجع التي يطلبها رمز التطبيق، بما في ذلك الطرق التي تحدّدها رمز تطبيقك أو المكتبات المضمنة.

يمكن أن تساعدك الاستراتيجيات التالية في تجنُّب بلوغ الحدّ الأقصى لمراجع DEX:

مراجعة التبعيات المباشرة والمتعدية لتطبيقك
التفكير في ما إذا كانت قيمة أي تبعية كبيرة للمكتبة تُدرجها في تطبيقك تفوق عدد الرموز البرمجية التي تتم إضافتها إلى التطبيق. هناك نمط شائع ولكن إشكالي هو تضمين مكتبة كبيرة جدًا لأن بعض طرق المنفعة كانت مفيدة. غالبًا ما يساعد تقليل اعتماديات رمز تطبيقك تجنب الحد الأقصى لمراجع DEX.
إزالة الرمز غير المستخدَم باستخدام R8
تفعيل تقليص الرموز لتشغيل R8 لإصدارات الإصدارات. يمكنك تفعيل التقليل للمساعدة في ضمان لا تشحن رمزًا غير مستخدَم باستخدام حِزم APK إذا تمت تهيئة تقليص التعليمات البرمجية بشكل صحيح، أيضًا إزالة التعليمات البرمجية والموارد غير المستخدمة من تبعياتك.

ويمكن أن يساعدك استخدام هذه الأساليب في خفض الحجم الإجمالي لملف APK لتجنُّب الحاجة إلى تعدد الأذونات في تطبيقك

ضبط تطبيقك لاستخدام ميزة Multidex

ملاحظة: إذا تم ضبط minSdkVersion على 21 أو أعلى، سيتم تفعيل ميزة Multidex تلقائيًا. ولا تحتاج إلى مكتبة الوسائط المتعددة.

وإذا تم ضبط minSdkVersion على 20 أو أقل، يجب: استخدام مكتبة Multidex وإجراء التعديلات التالية على مشروع تطبيقك:

  1. عدِّل ملف build.gradle على مستوى الوحدة ليصبح تفعيل Multidex وإضافة مكتبة Multidex كملحق، كما هو موضَّح هنا:

    Groovy

    android {
        defaultConfig {
            ...
            minSdkVersion 15 
            targetSdkVersion 33
            multiDexEnabled true
        }
        ...
    }
    
    dependencies {
        implementation "androidx.multidex:multidex:2.0.1"
    }
    

    Kotlin

    android {
        defaultConfig {
            ...
            minSdk = 15 
            targetSdk = 33
            multiDexEnabled = true
        }
        ...
    }
    
    dependencies {
        implementation("androidx.multidex:multidex:2.0.1")
    }
    
  2. اعتمادًا على ما إذا تم إلغاء 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 كما يلي:

      Kotlin

      class MyApplication : MultiDexApplication() {...}
      

      Java

      public class MyApplication extends MultiDexApplication { ... }
      
    • في حال إلغاء Application الفئة لكن لا يمكن تغيير الفئة الأساسية، فعندئذ بدلاً من ذلك، إلغاء طريقة attachBaseContext() والاتصال بـ MultiDex.install(this) للتفعيل :multidex:

      Kotlin

      class MyApplication : SomeOtherApplication() {
      
          override fun attachBaseContext(base: Context) {
              super.attachBaseContext(base)
              MultiDex.install(this)
          }
      }
      

      Java

      public class MyApplication extends SomeOtherApplication {
        @Override
        protected void attachBaseContext(Context base) {
           super.attachBaseContext(base);
           MultiDex.install(this);
        }
      }
      

      تنبيه: يجب عدم التنفيذ MultiDex.install() أو أي رمز آخر من خلال الانعكاس أو JNI قبل اكتمال MultiDex.install(). سيساعدك تتبع الارتباطات المتعددة عدم متابعة هذه المكالمات، ما يؤدي إلى حدوث ClassNotFoundException أو التحقّق من الأخطاء بسبب تقسيم فئة غير صالح بين ملفات DEX.

والآن، عندما تنشئ تطبيقك، تُنشئ أدوات تصميم Android رمز DEX أساسيًا. (classes.dex) وملفات DEX الداعمة (classes2.dex وclasses3.dex وما إلى ذلك) حسب الحاجة. بعد ذلك، يعمل نظام الإصدار على تجميع جميع ملفات DEX في حزمة APK.

في وقت التشغيل، بدلاً من البحث فقط في الصفحة الرئيسية classes.dex، تستخدم واجهات برمجة التطبيقات المتعددة الإشارات أداة تحميل فئة خاصة للبحث في جميع ملفات DEX المتاحة لأساليبك.

حدود مكتبة الوسائط المتعددة

هناك بعض القيود المعروفة في مكتبة الوسائط المتعددة. عند دمج المكتبة في إعدادات إصدار التطبيق، يجب مراعاة ما يلي:

  • يُعد تثبيت ملفات DEX أثناء بدء التشغيل في قسم بيانات الجهاز أمرًا معقدًا إلى ظهور أخطاء "التطبيق لا يستجيب" (ANR) إذا كانت ملفات DEX الثانوية كبيرة. إلى لتجنُّب هذه المشكلة، يمكنك تفعيل تخفيض حجم الرموز لتقليل النتائج. حجم ملفات DEX وإزالة الأجزاء غير المستخدمة من التعليمات البرمجية.
  • عند تشغيل التطبيق على إصدارات أقدم من Android 5.0 (المستوى 21 من واجهة برمجة التطبيقات)، فإن استخدام لا يكفي استخدام Multidex للتوافق مع الحد الخطي (المشكلة 37008143). تمت زيادة هذا الحد في Android 4.0 (المستوى 14 من واجهة برمجة التطبيقات)، ولكن لم يحل ذلك المشكلة بالكامل.

    في الإصدارات الأقل من Android 4.0، قد تصل إلى حد السرعة الخطية قبل الوصول إلى حد مؤشر DEX. لذلك إذا كنت تستهدف مستويات واجهة برمجة تطبيقات أقل من 14، اختبر جيدًا على تلك الإصدارات من النظام الأساسي، لأن تطبيقك قد إذا واجهت بعض المشكلات عند بدء التشغيل أو عند تحميل مجموعات معينة من الفئات.

    يمكن أن يؤدي تصغير الرمز إلى تقليل والقضاء على هذه المشكلات.

يُرجى تعريف الفئات المطلوبة في ملف 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

بعد ذلك، يمكنك الإعلان عن هذا الملف لنوع إصدار كما يلي:

Groovy

android {
    buildTypes {
        release {
            multiDexKeepProguard file('multidex-config.pro')
            ...
        }
    }
}

Kotlin

android {
    buildTypes {
        getByName("release") {
            multiDexKeepProguard = file("multidex-config.pro")
            ...
        }
    }
}

تحسين أداء متعدد القنوات في إصدارات التطوير

يتطلب الإعداد المتعدّد الأذونات زيادة كبيرة في معالجة الإصدار. لأن نظام التصميم يجب أن يتخذ قرارات معقدة بشأن الفئات في ملف DEX الأساسي والفئات التي يمكن تضمينها ملفات DEX الثانوية. هذا يعني أنّ الإصدارات التدريجية التي تستخدم تحليلاً متعدّدًا عادةً يستغرق وقتًا أطول وقد يؤدي إلى إبطاء عملية التطوير.

للتخفيف من أوقات الإنشاء المتزايدة، استخدم pre-dexing لإعادة استخدام إخراج Multidex بين الإصدارات. يعتمد التحليل المسبق على تنسيق ART الذي لا يتوفّر إلا على Android 5.0 (المستوى 21 من واجهة برمجة التطبيقات) والإصدارات الأحدث إذا كنت تستخدم "استوديو Android"، سيستخدم IDE تلقائيًا ميزة الفهرسة المُسبقة. عند نشر تطبيقك على جهاز يعمل بالإصدار 5.0 من نظام التشغيل Android (المستوى 21 من واجهة برمجة التطبيقات) أو بإصدارات أحدث. ومع ذلك، إذا كنت تشغل إصدارات Gradle من سطر الأوامر، فيجب تعيين من minSdkVersion إلى 21 أو أعلى لتفعيل التحكّم المسبق.

للحفاظ على إعدادات حسابك، يمكنك إنشاء إصدارين من تطبيقك استخدام نكهات المنتج: إصدار واحد لنكهة التطوير ونسخة واحدة بنكهة الإصدار، مع القيم المختلفة لـ minSdkVersion، كما هو موضح:

Groovy

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"
}

Kotlin

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 مختلفة لكل خيار منتج الفئة الفرعية فقط للمستوى 20 من واجهة برمجة التطبيقات والأدنى هي التي تضيف الفئة MultiDexApplication أو يتصل بـ MultiDex.install(this).

اختبار تطبيقات Multidex

عند كتابة اختبارات قياس حالة تطبيقات Multidex، لا حاجة إلى ضبط أي إعدادات إضافية. إذا كنت تستخدم MonitoringInstrumentation أو AndroidJUnitRunner الأدوات. في حال استخدام عنوان URL آخر Instrumentation, فمن ثم، يجب عليك إلغاء طريقة onCreate() الخاصة بها باستخدام الرمز التالي:

Kotlin

fun onCreate(arguments: Bundle) {
  MultiDex.install(targetContext)
  super.onCreate(arguments)
  ...
}

Java

public void onCreate(Bundle arguments) {
  MultiDex.install(getTargetContext());
  super.onCreate(arguments);
  ...
}