64 हज़ार से ज़्यादा तरीकों वाले ऐप्लिकेशन के लिए, मल्टीडेक्स की सुविधा चालू करें

अगर आपके ऐप्लिकेशन में एपीआई 20 या उससे पहले के वर्शन का minSdk है और आपका ऐप्लिकेशन और जिन लाइब्रेरी का रेफ़रंस 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. यह नंबर उन रेफ़रंस की कुल संख्या दिखाता है जिन्हें जिसे किसी एक Delvik वित्तीय सेवा देने वाले (DEX) बाइट कोड फ़ाइल के कोड से शुरू किया गया हो. इस पेज पर बताया गया है कि multidex नाम की ऐप्लिकेशन कॉन्फ़िगरेशन को चालू करना, जिससे आपके ऐप्लिकेशन को का इस्तेमाल करें.

64 हज़ार पहचान सीमा के बारे में जानकारी

Android ऐप्लिकेशन (APK) की फ़ाइलों में, एक्ज़ीक्यूटेबल बाइट कोड फ़ाइलें होती हैं Dalvik का एक्ज़ीक्यूटेबल (DEX) फ़ाइलें, जिनमें आपके ऐप्लिकेशन को चलाने के लिए इस्तेमाल किया जाने वाला कंपाइल कोड होता है. डलास के हिसाब से दिए गए नियमों में, उन तरीकों की कुल संख्या को सीमित किया जाता है जो एक DEX फ़ाइल में 65,536 तक का संदर्भ दिया जा सकता है—इसमें Android भी शामिल है फ़्रेमवर्क के तरीके, लाइब्रेरी के तरीके, और तरीकों की जानकारी अपने कोड में शामिल करें.

इस कंप्यूटर साइंस के संदर्भ में, किलो या K शब्द 1024 दिखाता है (या 2^10). 65,536 का साइज़ 64x1024 के बराबर होता है. इसलिए, इस सीमा को _64K में रेफ़रंस की सीमा तय की गई_.

Android 5.0 से पहले के वर्शन के लिए मल्टीडेक्स सहायता

Android 5.0 (एपीआई लेवल 21) से पहले के प्लैटफ़ॉर्म के वर्शन में, Delvik का इस्तेमाल किया जाता है किसी ऐप्लिकेशन कोड को चलाने के लिए रनटाइम. डिफ़ॉल्ट रूप से, Delvik ऐप्लिकेशन को एक बार में एक हर APK के लिए classes.dex बाइट कोड फ़ाइल. इससे बचने के लिए सीमा है, तो मल्टीडेक्स लाइब्रेरी को मॉड्यूल-लेवल build.gradle में जोड़ें या build.gradle.kts फ़ाइल:

ग्रूवी

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 फ़ाइलों और उनमें मौजूद कोड के ऐक्सेस को मैनेज करता है. इस लाइब्रेरी का मौजूदा वर्शन देखने के लिए, यह देखें मल्टीडेक्स वर्शन में उपलब्ध है.

ज़्यादा जानकारी के लिए, मल्टीडेक्स के लिए अपने ऐप्लिकेशन को कॉन्फ़िगर करें.

Android 5.0 और इसके बाद के वर्शन के लिए Multidex की सुविधा

Android 5.0 (एपीआई लेवल 21) और उसके बाद के वर्शन, ART नाम के रनटाइम का इस्तेमाल करते हैं मूल रूप से, APK फ़ाइलों से कई DEX फ़ाइलें लोड करने की सुविधा मिलती है. एआरटी ऐप्लिकेशन इंस्टॉल के समय पूर्व-संकलन करता है, classesN.dex फ़ाइलें और उन्हें एक में कंपाइल करना इसके लिए OAT फ़ाइल Android डिवाइस पर लागू होता है. इसलिए, अगर आपका minSdkVersion 21 या उससे ज़्यादा है, मल्टीडेक्स डिफ़ॉल्ट रूप से चालू है और आपको मल्टीडेक्स लाइब्रेरी की ज़रूरत नहीं है.

Android 5.0 के बारे में ज़्यादा जानकारी पाने के लिए रनटाइम, Android रनटाइम (ART) और Delvik को पढ़ें.

ध्यान दें: Android Studio का इस्तेमाल करके अपना ऐप्लिकेशन चलाते समय, बिल्ड को उन टारगेट डिवाइसों के हिसाब से ऑप्टिमाइज़ किया गया है जिन पर आपका ऐप्लिकेशन काम करता है. इसमें, टारगेट किए गए डिवाइसों के चलने के दौरान मल्टीडेक्स को चालू करना शामिल है Android 5.0 और इसके बाद के वर्शन. चूंकि यह ऑप्टिमाइज़ेशन केवल तभी लागू होता है, जब Android Studio का इस्तेमाल करने पर, आपको अब भी रिलीज़ बिल्ड को कॉन्फ़िगर करना पड़ सकता है मल्टीडेक्स के लिए 64K सीमा से बचने के लिए भी ऐसा ही करें.

64 हज़ार की सीमा पार करने से बचें

अपने ऐप्लिकेशन को 64K या इससे ज़्यादा तरीकों के रेफ़रंस के तौर पर इस्तेमाल करने के लिए कॉन्फ़िगर करने से पहले, यह तरीका अपनाएं आपके ऐप्लिकेशन कोड से कॉल किए गए रेफ़रंस की कुल संख्या को कम करने के लिए, इसमें आपके ऐप्लिकेशन कोड या शामिल लाइब्रेरी की जानकारी शामिल होती है.

नीचे दी गई रणनीतियों की मदद से, DEX पहचान सीमा के अंदर आने से बचा जा सकता है:

अपने ऐप्लिकेशन की डायरेक्ट और ट्रांज़िटिव डिपेंडेंसी की समीक्षा करना
ध्यान रखें कि आपने अपने ऐप्लिकेशन में बड़ी लाइब्रेरी डिपेंडेंसी शामिल की है या नहीं, इसकी वैल्यू कोड की तय सीमा से ज़्यादा है को ऐप में जोड़ा जा रहा है. एक बहुत बड़ी लाइब्रेरी को शामिल करना, एक आम लेकिन समस्या वाला पैटर्न है क्योंकि कुछ उपयोगी तरीके उपयोगी थे. ऐप्लिकेशन कोड डिपेंडेंसी कम करने से, अक्सर आप DEX पहचान सीमा से बच जाते हैं.
R8 की मदद से इस्तेमाल नहीं किए गए कोड को हटाएं
R8 चलाने के लिए, कोड छोटा करने की सुविधा चालू करें का सुझाव भी देता है. श्रिंकिंग की सुविधा चालू करें, ताकि यह पक्का किया जा सके कि आपके APK के साथ इस्तेमाल न किया गया कोड नहीं भेज रहे हैं. अगर कोड का आकार छोटा करने की सुविधा को सही तरीके से कॉन्फ़िगर किया गया है, तो आपकी डिपेंडेंसी से इस्तेमाल नहीं होने वाले कोड और रिसॉर्स को भी हटा सकता है.

इन तकनीकों का इस्तेमाल करके आप अपने APK का कुल साइज़ कम कर सकते हैं और अपने ऐप्लिकेशन में मल्टीडेक्स की ज़रूरत से बचें.

मल्टीडेक्स के लिए अपने ऐप्लिकेशन को कॉन्फ़िगर करें

ध्यान दें: अगर आपका minSdkVersion 21 या उससे बाद पर सेट है, तो मल्टीडेक्स डिफ़ॉल्ट रूप से चालू रहता है और आपको मल्टीडेक्स लाइब्रेरी की ज़रूरत नहीं है.

अगर आपके minSdkVersion को 20 या इससे कम पर सेट किया गया है, तो को multidex लाइब्रेरी और आपके ऐप्लिकेशन प्रोजेक्ट में ये बदलाव किए गए हैं:

  1. मॉड्यूल-लेवल build.gradle फ़ाइल को इसमें बदलें मल्टीडेक्स को चालू करें और मल्टीडेक्स लाइब्रेरी को डिपेंडेंसी के तौर पर जोड़ें, जैसा कि यहां दिखाया गया है:

    ग्रूवी

    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) को कॉल करें मल्टीडेक्स:

      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 वगैरह) ज़रूरत के मुताबिक. इसके बाद, बिल्ड सिस्टम आपके APK में सभी DEX फ़ाइलों को पैकेज कर देता है.

रनटाइम के दौरान, सिर्फ़ मुख्य ऐप्लिकेशन में खोजने के बजाय classes.dex फ़ाइल है, तो मल्टीडेक्स एपीआई आपके तरीकों के लिए उपलब्ध DEX फ़ाइलें.

मल्टीडेक्स लाइब्रेरी की सीमाएं

मल्टीडेक्स लाइब्रेरी की कुछ सीमाएं हैं जिनके बारे में पहले से जानकारी है. अपने ऐप्लिकेशन के बिल्ड कॉन्फ़िगरेशन में लाइब्रेरी को शामिल करते समय, इन बातों का ध्यान रखें:

  • किसी डिवाइस के डेटा पार्टीशन पर स्टार्टअप के दौरान DEX फ़ाइलों को इंस्टॉल करना जटिल और सेकंडरी DEX फ़ाइलें बड़ी होने पर, ऐप्लिकेशन नॉट रिस्पॉन्डिंग (एएनआर) की गड़बड़ियां हो सकती है. यहां की यात्रा पर हूं इस समस्या से बचने के लिए, कोड को छोटा करने की सुविधा चालू करें DEX फ़ाइलों का साइज़ बदल सकते हैं और कोड के इस्तेमाल न किए गए हिस्से हटा सकते हैं.
  • Android 5.0 (एपीआई लेवल 21) से पहले के वर्शन पर चलाते समय, मल्टीडेक्स, लीनियरएलोक सीमा (समस्या 37008143) के आस-पास काम करने के लिए काफ़ी नहीं है. यह सीमा इतनी बढ़ाई गई Android 4.0 (एपीआई लेवल 14) के वर्शन के साथ काम करता है, लेकिन इससे समस्या पूरी तरह से हल नहीं हुई.

    Android 4.0 से पहले के वर्शन पर, हो सकता है कि आप लीनियर ऐलोकेशन की सीमा तक पहले पहुंच जाएं DEX इंडेक्स की सीमा तक पहुंच रहा है. इसलिए, अगर एपीआई लेवल इससे नीचे वाले लेवल को टारगेट किया जा रहा है 14, प्लैटफ़ॉर्म के उन वर्शन की अच्छी तरह से जांच कर लें, क्योंकि आपका ऐप्लिकेशन स्टार्टअप पर या क्लास के किसी ग्रुप के लोड होने पर समस्याएं हों.

    कोड छोटा करने की सुविधा का इस्तेमाल करके, इस समस्या को हल किया जा सकता है.

मुख्य DEX फ़ाइल में ज़रूरी क्लास के बारे में बताएं

किसी मल्टीडेक्स ऐप्लिकेशन के लिए हर DEX फ़ाइल बनाते समय, बिल्ड टूल अच्छी परफ़ॉर्मेंस देते हैं यह तय करने के लिए मुश्किल फ़ैसले लेना कि प्राइमरी DEX में किस क्लास की ज़रूरत है फ़ाइल में मौजूद है ताकि आपका ऐप्लिकेशन सफलतापूर्वक शुरू हो सके. अगर किसी क्लास की जानकारी देना ज़रूरी है, तो शुरू करने के दौरान प्राथमिक DEX फ़ाइल में नहीं दिया गया है, तो आपका ऐप्लिकेशन क्रैश हो जाता है java.lang.NoClassDefFoundError गड़बड़ी हुई.

बिल्ड टूल, ऐसे कोड के कोड पाथ की पहचान करता है जिसे सीधे आपके ऐप्लिकेशन से ऐक्सेस किया जाता है कोड. हालांकि, यह समस्या हो सकती है ये तब होते हैं, जब कोड पाथ कम दिखते हैं, जैसे कि जब इस्तेमाल की जाने वाली लाइब्रेरी में जटिल डिपेंडेंसी. उदाहरण के लिए, अगर कोड में आत्मनिरीक्षण या शुरू करने की कोशिश का इस्तेमाल किया गया है का इस्तेमाल किया है, तो हो सकता है कि उन क्लास की पहचान प्राथमिक 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')
            ...
        }
    }
}

Kotlin

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

डेवलपमेंट बिल्ड में मल्टीडेक्स को ऑप्टिमाइज़ करें

मल्टीडेक्स कॉन्फ़िगरेशन के लिए बिल्ड प्रोसेसिंग में काफ़ी बढ़ोतरी करने की ज़रूरत है समय पर पाबंदी लगा दी जाती है, क्योंकि बिल्ड सिस्टम को यह तय करना होता है कि कौनसे क्लास प्राथमिक DEX फ़ाइल में शामिल होना चाहिए और कौन-सी क्लास में शामिल किया जा सकता है दूसरी DEX फ़ाइलें शामिल की जाती हैं. इसका मतलब है कि आम तौर पर मल्टीडेक्स का इस्तेमाल करने वाले इंक्रीमेंटल बिल्ड इसमें ज़्यादा समय लगता है और इससे आपकी डेवलपमेंट प्रोसेस धीमी हो सकती है.

बिल्ड में लगने वाले ज़्यादा समय को कम करने के लिए, प्री-डेक्सिंग का इस्तेमाल करें, ताकि बिल्ड के बीच मल्टीडेक्स आउटपुट का फिर से इस्तेमाल किया जा सके. प्री-डेक्सिंग, सिर्फ़ Android 5.0 पर उपलब्ध एआरटी फ़ॉर्मैट के हिसाब से होती है (एपीआई लेवल 21) और उसके बाद वाले वर्शन. Android Studio का इस्तेमाल करने पर, आईडीई अपने-आप प्री-डेक्सिंग का इस्तेमाल करता है Android 5.0 (एपीआई लेवल 21) या उसके बाद के वर्शन वाले डिवाइस पर अपना ऐप्लिकेशन डिप्लॉय करते समय. हालांकि, अगर कमांड लाइन से Gradle बिल्ड चलाया जा रहा है, तो आपको प्री-डेक्सिंग चालू करने के लिए, minSdkVersion से 21 या उससे ज़्यादा.

अपनी सेटिंग को बनाए रखने के लिए प्रोडक्शन बिल्ड के साथ, अपने ऐप्लिकेशन के दो वर्शन बनाए जा सकते हैं उत्पादों के फ़्लेवर का इस्तेमाल करना—एक वर्शन जिसमें डेवलपमेंट फ़्लेवर और रिलीज़ फ़्लेवर वाला एक वर्शन शामिल है. 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"
}

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 Studio या 'निर्देश' की मदद से, बिल्ड की स्पीड बढ़ाने के लिए ज़्यादा रणनीतियां लाइन में, अपने बिल्ड की स्पीड ऑप्टिमाइज़ करें लेख पढ़ें. बिल्ड के वैरिएंट का इस्तेमाल करने के बारे में ज़्यादा जानने के लिए, यहां देखें बिल्ड वैरिएंट कॉन्फ़िगर करें.

सलाह: अगर आपके पास अलग-अलग प्रॉडक्ट के लिए अलग-अलग बिल्ड वैरिएंट हैं मल्टीडेक्स ज़रूरतों के लिए, आप हर एक फ़ाइल के लिए एक अलग मेनिफ़ेस्ट फ़ाइल दे सकते हैं वैरिएंट वाले वर्शन का इस्तेमाल करने से पहले <application> टैग का नाम. आप यह भी कर सकते हैं हर वैरिएंट के लिए एक अलग Application सब-क्लास बनाएं, ताकि सिर्फ़ एपीआई लेवल 20 और उससे पहले के लेवल के लिए सब-क्लास, MultiDexApplication क्लास को बढ़ाती है या MultiDex.install(this) को कॉल करता है.

मल्टीडेक्स ऐप्लिकेशन को टेस्ट करें

मल्टीडेक्स ऐप्लिकेशन के लिए इंस्ट्रुमेंटेशन टेस्ट लिखते समय, किसी अतिरिक्त कॉन्फ़िगरेशन की ज़रूरत नहीं होती अगर आप किसी MonitoringInstrumentation या AndroidJUnitRunner इंस्ट्रुमेंटेशन चुनें. अगर आपको किसी अन्य 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);
  ...
}