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:
-
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") }
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>
etiketindekiandroid: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 gibiMultiDexApplication
'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 yerineattachBaseContext()
yöntemini geçersiz kılın ve çoklu dizeyi etkinleştirmek içinMultiDex.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 önceMultiDex.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.
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); ... }