64K'dan fazla yöntemler içeren uygulamalar için multidex'i etkinleştirin

Uygulamanızın minSdk API düzeyi 20 veya daha düşükse ve uygulamanız ile referans verdiği kitaplıklar 65.536 yöntemi aşıyorsa uygulamanızın Android derleme mimarisinin sınırına ulaştığını belirten aşağıdaki derleme hatasıyla karşılaşırsınız:

trouble writing output:
Too many field references: 131000; max is 65536.
You may try using --multi-dex option.

Derleme sisteminin eski sürümleri, aynı sorunun göstergesi olan farklı bir hata bildirir:

Conversion to Dalvik format failed:
Unable to execute dex: method ID not in [0, 0xffff]: 65536

Bu hata koşullarında ortak bir sayı gösterilir: 65536. Bu sayı, tek bir Dalvik yürütülebilir (DEX) bayt kodu dosyasındaki kod tarafından çağrılabilecek toplam referans sayısını ifade eder. Bu sayfada, uygulamanızın birden fazla DEX dosyası oluşturmasına ve okumasına olanak tanıyan multidex olarak bilinen bir uygulama yapılandırmasını etkinleştirerek bu sınırlamayı nasıl aşacağınız açıklanmaktadır.

64 KB referans sınırı hakkında

Android uygulama (APK) dosyaları, uygulamanızı çalıştırmak için kullanılan derlenmiş kodu içeren Dalvik Yürütülebilir (DEX) dosyası biçiminde yürütülebilir bayt kodu dosyaları içerir. Dalvik Yürütülebilir spesifikasyonu, Android çerçeve yöntemleri, kitaplık yöntemleri ve kendi kodunuzdaki yöntemler dahil olmak üzere tek bir DEX dosyasında referans verilebilen toplam yöntem sayısını 65.536 ile sınırlar.

Bilgisayar bilimi bağlamında kilo veya K terimi 1024'ü (veya 2^10) ifade eder. 65.536, 64x1.024'e eşit olduğundan bu sınıra _64K referans sınırı_ denir.

Android 5.0'dan önceki Multidex desteği

Platformun Android 5.0 (API düzeyi 21) öncesi sürümleri, uygulama kodunu yürütmek için Dalvik çalışma zamanını kullanır. Dalvik, uygulamaları varsayılan olarak APK başına tek bir classes.dex bayt kod dosyasıyla sınırlandırır. Bu sınırlamayı aşmak için multidex kitaplığını modül düzeyindeki build.gradle veya build.gradle.kts dosyasına ekleyin:

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

Bu kitaplık, uygulamanızın birincil DEX dosyasının bir parçası olur ve ardından ek DEX dosyalarına ve bu dosyaların içerdiği koda erişimi yönetir. Bu kitaplığın mevcut sürümlerini görüntülemek için multidex sürümlerini inceleyin.

Daha fazla bilgi için uygulamanızı multidex için yapılandırma ile ilgili bölüme bakın.

Android 5.0 ve sonraki sürümler için çoklu paket desteği

Android 5.0 (API düzeyi 21) ve sonraki sürümlerde, APK dosyalarından birden fazla DEX dosyasının yüklenmesini yerel olarak destekleyen ART adlı bir çalışma zamanı kullanılır. ART, uygulama yükleme sırasında ön derleme gerçekleştirir, classesN.dex dosyalarını tarar ve Android cihaz tarafından yürütülmesi için tek bir OAT dosyasında derler. Bu nedenle, minSdkVersion 21 veya daha yeni bir sürümse multidex varsayılan olarak etkindir ve multidex kitaplığına ihtiyacınız yoktur.

Android 5.0 çalışma zamanı hakkında daha fazla bilgi edinmek için Android Runtime (ART) ve Dalvik sayfalarını okuyun.

Not: Uygulamanızı Android Studio'yu kullanarak çalıştırdığınızda derleme, dağıttığınız hedef cihazlar için optimize edilir. Hedef cihazlarda Android 5.0 ve sonraki sürümler çalıştırıldığında çoklu dizin etkinleştirme de buna dahildir. Bu optimizasyon yalnızca uygulamanızı Android Studio kullanılarak dağıtırken uygulandığından, 64 KB sınırını aşmamak için sürüm derlemenizi multidex olarak yapılandırmanız gerekebilir.

64K sınırından kaçının.

Uygulamanızı 64.000 veya daha fazla yöntem referansının kullanılmasını sağlayacak şekilde yapılandırmadan önce, uygulama kodunuz tarafından tanımlanan yöntemler veya dahil edilen kitaplıklar dahil olmak üzere uygulama kodunuz tarafından çağrılan toplam referans sayısını azaltmak için adımlar atın.

Aşağıdaki stratejiler, DEX referans sınırına ulaşmaktan kaçınmanıza yardımcı olabilir:

Uygulamanızın doğrudan ve geçişli bağımlılıklarını inceleme
Uygulamanıza eklediğiniz büyük bir kitaplık bağımlılığının değerinin, uygulamaya eklenen kod miktarından ağır bastığını düşünün. Yaygın ancak sorunlu bir model, birkaç yardımcı yöntemi faydalı olduğu için çok büyük bir kitaplık eklemektir. Uygulama kodunuzdaki bağımlılıkları azaltmak, DEX referans sınırını aşmanızı önlemeye yardımcı olabilir.
R8 ile kullanılmayan kodları kaldırma
Sürüm derlemelerinizde R8'i çalıştırmak için kod küçültmeyi etkinleştirin. APK'larınızla kullanılmayan kod göndermediğinizden emin olmak için küçültmeyi etkinleştirin. Kod küçültme doğru şekilde yapılandırılmışsa bağımlılıklarınızdan kullanılmayan kodları ve kaynakları da kaldırabilir.

Bu teknikleri kullanmak, APK'nızın genel boyutunu küçültmenize ve uygulamanızda multidex kullanma ihtiyacını önlemenize yardımcı olabilir.

Uygulamanızı multidex için yapılandırma

Not: minSdkVersion değeriniz 21 veya daha yüksek bir değere ayarlanmışsa çoklu dex varsayılan olarak etkindir ve çoklu dex kitaplığına ihtiyacınız yoktur.

minSdkVersion değeriniz 20 veya daha düşükse multidex kitaplığını kullanmanız ve uygulama projenizde aşağıdaki değişiklikleri yapmanız gerekir:

  1. Multidex'i etkinleştirmek için modül düzeyindeki build.gradle dosyasını değiştirin ve multidex kitaplığını bağımlı bir kaynak olarak ekleyin.

    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 sınıfını geçersiz kılmanıza bağlı olarak aşağıdakilerden birini yapın:
    • Application sınıfını geçersiz kılmıyorsanız manifest dosyanızı düzenleyerek <application> etiketindeki android:name değerini aşağıdaki gibi ayarlayın:

      <?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 sınıfını geçersiz kılarsanız aşağıdaki gibi MultiDexApplication'u genişletecek şekilde değiştirin:

      Kotlin

      class MyApplication : MultiDexApplication() {...}

      Java

      public class MyApplication extends MultiDexApplication { ... }
    • Application sınıfını geçersiz kılarsanız ancak temel sınıfı değiştirmek mümkün değilse bunun yerine attachBaseContext() yöntemini geçersiz kılın ve çoklu dizeyi etkinleştirmek için MultiDex.install(this)'i çağırın:

      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);
        }
      }

      Dikkat: MultiDex.install() tamamlanmadan önce MultiDex.install()'yi veya başka bir kodu yansıma veya JNI aracılığıyla yürütmeyin. Multidex izleme, bu çağrıları takip etmez. Bu nedenle, ClassNotFoundException veya DEX dosyaları arasındaki hatalı sınıf bölümü nedeniyle hataları doğrular.

Artık uygulamanızı derlerken, Android derleme araçları bir birincil DEX dosyası (classes.dex) ve destekleyici DEX dosyaları (classes2.dex, classes3.dex vb.) oluşturur. Derleme sistemi daha sonra tüm DEX dosyalarını APK'nıza paketler.

Çoklu DEX API'leri, çalışma zamanında yalnızca ana classes.dex dosyasında arama yapmak yerine, yöntemleriniz için mevcut tüm DEX dosyalarında arama yapmak üzere özel bir sınıf yükleyici kullanır.

Multidex kitaplığıyla ilgili sınırlamalar

Multidex kitaplığının bilinen bazı sınırlamaları vardır. Kitaplığı uygulama derleme yapılandırmanıza dahil ederken aşağıdakileri göz önünde bulundurun:

  • Başlatma sırasında DEX dosyalarının bir cihazın veri bölümüne yüklenmesi karmaşık bir işlemdir ve ikincil DEX dosyaları büyükse uygulama yanıt vermiyor (ANR) hatalarına neden olabilir. Bu sorunu önlemek için DEX dosyalarının boyutunu en aza indirmek ve kullanılmayan kod bölümlerini kaldırmak amacıyla kod küçültmeyi etkinleştirin.
  • Android 5.0'den (API düzeyi 21) önceki sürümlerde çalıştırırken, linearalloc sınırını aşmak için multidex kullanmak yeterli değildir (37008143 numaralı sorun). Bu sınır Android 4.0'da (API düzeyi 14) artırıldı ancak sorun tamamen çözülmedi.

    Android 4.0'tan eski sürümlerde, DEX dizini sınırına ulaşmadan önce linearalloc sınırına ulaşabilirsiniz. Bu nedenle, 14'ün altındaki API düzeylerini hedefliyorsanız uygulamanızın başlangıçta veya belirli sınıf grupları yüklenirken sorunlar yaşayabileceğinden platformun bu sürümlerinde kapsamlı bir şekilde test yapın.

    Kod küçültme, bu sorunları azaltabilir veya muhtemelen ortadan kaldırabilir.

Birincil DEX dosyasında gerekli sınıfları tanımlama

Derleme araçları, çok DEX'li bir uygulama için her DEX dosyasını oluştururken birincil DEX dosyasında hangi sınıflara ihtiyaç duyulduğunu belirlemek üzere karmaşık kararlar alır. Bu sayede uygulamanız başarıyla başlatılabilir. Başlatma sırasında gereken herhangi bir sınıf birincil DEX dosyasında sağlanmamışsa uygulamanız java.lang.NoClassDefFoundError hatasıyla kilitlenir.

Derleme araçları, doğrudan uygulama kodunuzdan erişilen kodun kod yollarını tanır. Ancak bu sorun, kod yolları daha az görünür olduğunda (ör. kullandığınız kitaplığın karmaşık bağımlılıkları olduğunda) ortaya çıkabilir. Örneğin, kodda yerel koddan Java yöntemlerinin iç gözlemi veya çağrılması kullanılıyorsa bu sınıflar birincil DEX dosyasında gerekli olarak tanınmayabilir.

java.lang.NoClassDefFoundError alırsanız birincil DEX dosyasında gerekli olan ek sınıfları, derleme türünüzde multiDexKeepProguard mülküyle açıklayarak manuel olarak belirtmeniz gerekir. multiDexKeepProguard dosyasında eşleşen bir sınıf varsa bu sınıf birincil DEX dosyasına eklenir.

multiDexKeepProguard mülkü

multiDexKeepProguard dosyası, ProGuard ile aynı biçimi kullanır ve ProGuard dil bilgisinin tamamını destekler. Uygulamanızda nelerin depolanacağını özelleştirme hakkında daha fazla bilgi için Hangi kodun saklanacağını özelleştirme bölümüne bakın.

multiDexKeepProguard içinde belirttiğiniz dosya, geçerli bir ProGuard söz diziminde -keep seçenekleri içermelidir. Örneğin, -keep com.example.MyClass.class. multidex-config.pro adlı şu dosyayı oluşturabilirsiniz:

-keep class com.example.MyClass
-keep class com.example.MyClassToo

Bir paketteki tüm sınıfları belirtmek istiyorsanız dosya şu şekilde görünür:

-keep class com.example.** { *; } // All classes in the com.example package

Ardından, bu dosyayı bir derleme türü için aşağıdaki gibi tanımlayabilirsiniz:

Groovy

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

Kotlin

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

Geliştirme derlemelerinde multidex'i optimize etme

Derleme sistemi, birincil DEX dosyasına hangi sınıfların dahil edilmesi gerektiği ve ikincil DEX dosyalarına hangi sınıfların dahil edilebileceği konusunda karmaşık kararlar vermesi gerektiğinden, çoklu DEX yapılandırması önemli ölçüde daha uzun derleme işleme süresi gerektirir. Bu, multidex kullanan artımlı derlemelerin genellikle daha uzun sürdüğü ve geliştirme sürecinizi yavaşlatabileceği anlamına gelir.

Artımlı derleme sürelerini kısaltmak için derlemeler arasında çoklu dex çıktısını yeniden kullanmak üzere ön dex oluşturma özelliğini kullanın. Önceden ekleme işlemi, yalnızca Android 5.0 (API düzeyi 21) ve sonraki sürümlerde kullanılabilen bir ART biçimini kullanır. Android Studio kullanıyorsanız IDE, uygulamanızı Android 5.0 (API düzeyi 21) veya sonraki bir sürümü çalıştıran bir cihaza dağıtırken otomatik olarak ön dexing kullanır. Ancak Gradle derlemelerini komut satırından çalıştırıyorsanız ön derlemeyi etkinleştirmek için minSdkVersion değerini 21 veya daha yüksek bir değere ayarlamanız gerekir.

Üretim derlemenizin ayarlarını korumak amacıyla ürün aromalarını kullanarak uygulamanızın iki sürümünü (biri geliştirme aromasına, diğeri sürüm aromasına sahip) aşağıda gösterildiği gibi minSdkVersion için farklı değerlerle oluşturabilirsiniz:

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 Studio'da veya komut satırında derleme hızlarını artırmaya yardımcı olacak daha fazla strateji öğrenmek için Derleme hızınızı optimize etme başlıklı makaleyi okuyun. Derleme varyantlarını kullanma hakkında daha fazla bilgi için Derleme varyantlarını yapılandırma başlıklı makaleyi inceleyin.

İpucu: Farklı multidex ihtiyaçları için farklı derleme varyantlarınız varsa her varyant için farklı bir manifest dosyası sağlayabilirsiniz. Böylece, yalnızca API düzeyi 20 ve önceki sürümlerdeki dosya, <application> etiket adını değiştirir. Ayrıca, her varyant için farklı bir Application alt sınıfı oluşturabilirsiniz. Böylece, yalnızca API düzeyi 20 ve daha düşük olan alt sınıf MultiDexApplication sınıfını genişletir veya MultiDex.install(this)'yi çağırır.

Multidex uygulamalarını test etme

Multidex uygulamaları için araç testleri yazdığınızda, MonitoringInstrumentation veya AndroidJUnitRunner enstrümantasyonu kullanıyorsanız ek yapılandırma gerekmez. Başka bir Instrumentation kullanıyorsanız onCreate() yöntemini aşağıdaki kodla geçersiz kılmanız gerekir:

Kotlin

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

Java

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