Uygulamanızın minSdk değeri API 20 veya daha düşükse ve uygulamanız ile referans verdiği kitaplıklar 65.536 yöntemi aşarsa 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ı ortak bir sayı gösterir: 65536. Bu sayı, tek bir Dalvik Executable (DEX) bayt kodu dosyasındaki kod tarafından çağrılabilecek toplam referans sayısını temsil eder. Bu sayfada, uygulamanızın birden fazla DEX dosyası oluşturmasına ve okumasına olanak tanıyan multidex adlı bir uygulama yapılandırmasını etkinleştirerek bu sınırlamayı nasıl aşacağınız açıklanmaktadır.
64K referans sınırı hakkında
Android uygulama (APK) dosyaları, uygulamanızı çalıştırmak için kullanılan derlenmiş kodu içeren Dalvik Executable (DEX) dosyaları biçiminde yürütülebilir bayt kodu dosyaları içerir. Dalvik Executable spesifikasyonu, tek bir DEX dosyasında referans verilebilecek toplam yöntem sayısını (Android çerçeve yöntemleri, kitaplık yöntemleri ve kendi kodunuzdaki yöntemler dahil) 65.536 ile sınırlandırır.
Bilgisayar bilimi bağlamında kilo veya K terimi 1024'ü (veya 2^10) ifade eder. 65.536,64x1024'e eşit olduğundan bu sınır, _64K referans sınırı_ olarak adlandırılır.Android 5.0'dan önceki sürümlerde multidex desteği
Platformun Android 5.0'dan (API düzeyi 21) önceki sürümleri, uygulama kodunu yürütmek için Dalvik çalışma zamanını kullanır. Dalvik, varsayılan olarak uygulamaları APK başına tek bir classes.dex bayt kodu 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:
Modern
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ı haline gelir ve ardından ek DEX dosyalarına ve içerdikleri koda erişimi yönetir. Bu kitaplığın mevcut sürümlerini görüntülemek için multidex sürümleri bölümüne bakın.
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 multidex desteği
Android 5.0 (API düzeyi 21) ve sonraki sürümler, APK dosyalarından birden fazla DEX dosyası yüklemeyi yerel olarak destekleyen ART adlı bir çalışma zamanı kullanı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ülmek üzere tek bir OAT dosyasında derler. Bu nedenle, minSdkVersion
değeriniz 21 veya daha yüksekse multidex varsayılan olarak etkindir ve multidex kitaplığına ihtiyacınız yoktur.
Android 5.0 çalışma zamanı hakkında daha fazla bilgi için Android Çalışma Zamanı (ART) ve Dalvik başlıklı makaleyi 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 cihazlar Android 5.0 ve sonraki sürümleri çalıştırıyorsa multidex'i etkinleştirme de buna dahildir. Bu optimizasyon yalnızca uygulamanızı Android Studio kullanarak dağıtırken uygulandığından, 64K sınırını aşmamak için yayınlanan derlemenizi multidex için yapılandırmanız gerekebilir.
64K sınırından kaçınma
Uygulamanızı 64K veya daha fazla yöntem referansının kullanımını etkinleştirecek şekilde yapılandırmadan önce, uygulama kodunuz tarafından tanımlanan veya dahil edilen kitaplıklar tarafından tanımlanan yöntemler de dahil olmak üzere uygulama kodunuz tarafından çağrılan toplam referans sayısını azaltmak için gerekli adımları uygulayın.
Aşağıdaki stratejiler, DEX referans sınırına ulaşmanızı önlemeye 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 kitaplık bağımlılıklarının değerinin, uygulamaya eklenen kod miktarından daha fazla olup olmadığını değerlendirin. Yaygın ancak sorunlu bir yaklaşım, birkaç yardımcı yöntem faydalı olduğu için çok büyük bir kitaplığı dahil etmektir. Uygulama kodu bağımlılıklarınızı azaltmak genellikle DEX referans sınırını aşmanızı önlemeye yardımcı olabilir.
- R8 ile kullanılmayan kodları kaldırma
- Yayınlanan derlemeleriniz için R8'i çalıştırmak üzere kod daraltmayı etkinleştirin. APK'larınızla birlikte kullanılmayan kod göndermediğinizden emin olmak için küçültmeyi etkinleştirin. Kod daraltma doğru şekilde yapılandırılırsa bağımlılıklarınızdaki kullanılmayan kodları ve kaynakları da kaldırabilir.
Bu teknikleri kullanmak, APK'nızın genel boyutunu küçültmenize ve uygulamanızda multidex ihtiyacını ortadan kaldırmanıza 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 multidex varsayılan olarak etkindir ve multidex kitaplığına ihtiyacınız yoktur.
minSdkVersion değeriniz 20 veya daha düşük bir değere ayarlanmışsa multidex kitaplığını kullanmanız ve uygulama projenizde aşağıdaki değişiklikleri yapmanız gerekir:
-
Modül düzeyindeki
build.gradledosyasını değiştirerek multidex'i etkinleştirin ve multidex kitaplığını bağımlılık olarak ekleyin.Modern
android { defaultConfig { ... minSdkVersion 15 targetSdkVersion 36 multiDexEnabled true } ... } dependencies { implementation "androidx.multidex:multidex:2.0.1" }
Kotlin
android { defaultConfig { ... minSdk = 15 targetSdk = 36 multiDexEnabled = true } ... } dependencies { implementation("androidx.multidex:multidex:2.0.1") }
Applicationsınıfını geçersiz kılıp kılmadığınıza bağlı olarak aşağıdakilerden birini yapın:Applicationsınıfını geçersiz kılmazsanız manifest dosyanızı düzenleyerek<application>etiketindeandroid:namedeğ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>
Applicationsınıfını geçersiz kılarsanız bunuMultiDexApplicationsınıfını genişletecek şekilde aşağıdaki gibi değiştirin:Kotlin
class MyApplication : MultiDexApplication() {...}
Java
public class MyApplication extends MultiDexApplication { ... }
Applicationsınıfını geçersiz kılıyor ancak temel sınıfı değiştiremiyorsanızattachBaseContext()yöntemini geçersiz kılın ve multidex'i etkinleştirmek içinMultiDex.install(this)yöntemini ç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 yansıma veya JNI aracılığıylaMultiDex.install()ya da başka bir kod yürütmeyin. Multidex izleme bu çağrıları takip etmez. Bu durum, DEX dosyaları arasındaki hatalı sınıf bölümü nedeniyleClassNotFoundExceptionveya doğrulama hatalarına neden olur.
Artık uygulamanızı derlediğinizde Android derleme araçları, gerektiğinde birincil bir 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ızda paketler.
Çalışma zamanında, multidex API'leri yalnızca ana classes.dex dosyasında arama yapmak yerine, yöntemleriniz için mevcut tüm DEX dosyalarını aramak üzere özel bir sınıf yükleyici kullanır.
Multidex kitaplığının 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şıktır ve ikincil DEX dosyaları büyükse Uygulama Yanıt Vermiyor (ANR) hatalarına neden olabilir. Bu sorunu önlemek için kod daraltmayı etkinleştirerek DEX dosyalarının boyutunu küçültün ve kodun kullanılmayan kısımlarını kaldırın.
- Android 5.0'dan (API düzeyi 21) önceki sürümlerde çalışırken multidex kullanmak, linearalloc sınırını (sorun 37008143) aşmak için yeterli değildir. Bu sınır Android 4.0'da (API düzeyi 14) artırıldı ancak bu, sorunu tamamen çözmedi.
Android 4.0'dan önceki sürümlerde, DEX dizin sınırına ulaşmadan önce linearalloc sınırına ulaşabilirsiniz. Bu nedenle, 14'ten düşük hedef API düzeylerini hedefliyorsanız platformun bu sürümlerinde kapsamlı testler yapın. Uygulamanız başlatılırken veya belirli sınıf grupları yüklenirken sorunlar yaşayabilir.
Kod daraltma bu sorunları azaltabilir veya tamamen ortadan kaldırabilir.
Birincil DEX dosyasında gerekli sınıfları bildirme
Multidex uygulaması için her DEX dosyasını oluştururken derleme araçları, uygulamanızın başarıyla başlatılabilmesi için birincil DEX dosyasında hangi sınıfların gerekli olduğunu belirlemek üzere karmaşık kararlar alır. Başlatma sırasında gerekli olan herhangi bir sınıf birincil DEX dosyasında sağlanmazsa 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ının daha az görünür olduğu durumlarda (ör. kullandığınız bir kitaplığın karmaşık bağımlılıkları olduğunda) ortaya çıkabilir. Örneğin, kod yerel koddan Java yöntemlerinin iç gözlemini veya çağrısını kullanıyorsa bu sınıflar, birincil DEX dosyasında gerekli olarak tanınmayabilir.
java.lang.NoClassDefFoundError hatası alırsanız birincil DEX dosyasında gereken ek sınıfları, derleme türünüzde multiDexKeepProguard özelliğiyle bildirerek 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 özelliği
multiDexKeepProguard dosyası, ProGuard ile aynı biçimi kullanır ve tüm ProGuard dil bilgisini destekler. Uygulamanızda nelerin tutulacağını özelleştirme hakkında daha fazla bilgi için Hangi kodun tutulacağını özelleştirme bölümüne bakın.
multiDexKeepProguard içinde belirttiğiniz dosya, geçerli herhangi bir ProGuard söz diziminde -keep seçeneklerini içermelidir. Örneğin,
-keep com.example.MyClass.class. Şuna benzer şekilde multidex-config.pro adlı bir dosya 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:
Modern
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
Multidex yapılandırması, derleme sisteminin hangi sınıfların birincil DEX dosyasına dahil edilmesi ve hangi sınıfların ikincil DEX dosyalarına dahil edilebileceği konusunda karmaşık kararlar vermesi gerektiğinden derleme işleme süresini önemli ölçüde artırır. Bu nedenle, multidex kullanan artımlı derlemeler genellikle daha uzun sürer ve geliştirme sürecinizi yavaşlatabilir.
Artımlı derleme sürelerinin uzamasını önlemek için derlemeler arasında multidex çıkışını yeniden kullanmak üzere dex'e dönüştürme özelliğini kullanın.
Dex'e dönüştürme, 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ün yüklü olduğu bir cihaza dağıtırken otomatik olarak dex'e dönüştürme işlemini kullanır.
Ancak Gradle derlemelerini komut satırından çalıştırıyorsanız dex'e dönüştürmeyi etkinleştirmek için minSdkVersion değerini 21 veya daha yüksek bir değere ayarlamanız gerekir.
minSdkVersion için farklı değerler içerir:
Modern
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'dan veya komut satırından derleme hızlarını artırmaya yardımcı olacak diğer stratejiler hakkında bilgi edinmek için Derleme hızınızı optimize etme başlıklı makaleyi inceleyin. Derleme değişkenlerini kullanma hakkında daha fazla bilgi için Derleme değişkenlerini 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 daha düşük olan 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 sürümler için olan alt sınıf, MultiDexApplication sınıfını genişletir veya MultiDex.install(this) yöntemini çağırır.
Multidex uygulamalarını test etme
Multidex uygulamaları için enstrümantasyon testleri yazarken
MonitoringInstrumentation veya
AndroidJUnitRunner
enstrümantasyonu kullanırsanı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); ... }