Uygulamanızda API 20 veya daha düşük bir minSdk
sürümü varsa ve uygulamanızda referans verilen kitaplıklar 65.536 yöntemi aşıyorsa uygulamanızın Android derleme mimarisi 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ı temsil eder. Bu sayfada, uygulamanızın birden fazla DEX dosyası oluşturup okumasına olanak tanıyan multidex adlı bir uygulama yapılandırmasını etkinleştirerek bu sınırlamayı nasıl aşabileceğiniz açıklanmaktadır.
64K referans sınırı hakkında
Android uygulama (APK) dosyaları, Dalvik Yürütülebilir (DEX) dosyaları biçiminde yürütülebilir bayt kodu dosyaları içerir. Bu dosyalar,uygulamanızı çalıştırmak için kullanılan derlenmiş kodu içerir. Dalvik Yürütülebilir teknik spesifikasyonu, tek bir DEX dosyasında referans verilebilecek toplam yöntem sayısını 65.536 ile (Android çerçeve yöntemleri, kitaplık yöntemleri ve yöntemler dahil) sınırlandırır.
Bilgisayar bilimi bağlamında kilo veya K terimi 1024 (veya 2^10) anlamına gelir. 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'dan (API düzeyi 21) önceki sürümleri, uygulama kodunu çalıştırmak 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 çokludex kitaplığını modül düzeyindeki build.gradle
veya build.gradle.kts
dosyasına ekleyin:
Eski
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 bunları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 ayrıntı 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ü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 anında önceden derleme gerçekleştirir, classesN.dex
dosyasını tarar ve Android cihaz tarafından yürütülmesi için tek bir OAT dosyasında derler. Bu nedenle, minSdkVersion
değeriniz 21 veya daha yüksekse multidex varsayılan olarak etkinleştirilir 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 kullanarak çalıştırırken derleme, dağıtım yaptığınız hedef cihazlara göre optimize edilir. Buna, hedef cihazlarda Android 5.0 ve sonraki sürümler çalışırken multidex'in etkinleştirilmesi de dahildir. Bu optimizasyon yalnızca Android Studio kullanarak uygulamanızı dağıtırken uygulandığından, 64K sınırından kaçınmak için yine de multidex için sürüm derlemenizi yapılandırmanız gerekebilir.
64K sınırından kaçının.
Uygulamanızı 64K veya daha fazla yöntem referansının kullanılmasını sağlayacak şekilde yapılandırmadan önce, uygulama kodunuz tarafından çağrılan toplam referans sayısını azaltmak için gerekli adımları atın (uygulama kodunuz veya dahil ettiğiniz kitaplıklar tarafından tanımlanan yöntemler dahil).
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 kodu bağımlılıklarını azaltmak genellikle DEX referans sınırından kaçınmanıza yardımcı olabilir.
- Kullanılmayan kodları R8 ile kaldırın
- Sürüm derlemelerinizde R8'i çalıştırmak için kod küçültmeyi etkinleştirin. Kullanılmayan kodları APK'larınızla birlikte göndermediğinizden emin olmak için küçültmeyi etkinleştirin. Kod daraltma doğru şekilde yapılandırılırsa kullanılmayan kod ve kaynakları da bağımlılıklarınızdan kaldırabilir.
Bu teknikleri kullanarak APK'nızın genel boyutunu küçültebilir ve uygulamanızda multimedya kullanımı ihtiyacını ortadan kaldırabilirsiniz.
Uygulamanızı multidex için yapılandırma
Not:minSdkVersion
değeriniz 21 veya daha yüksek bir değere ayarlanırsa multidex varsayılan olarak etkinleştirilir ve multidex kitaplığına ihtiyacınız olmaz.
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:
-
Multidex'i etkinleştirmek için modül düzeyindeki
build.gradle
dosyasını değiştirin ve çokludex kitaplığını aşağıda gösterildiği gibi bağımlılık olarak ekleyin:Eski
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ılıp kılmadığınıza bağlı olarak aşağıdakilerden birini yapın:Application
sınıfını geçersiz kılmazsanız manifest dosyanızı,<application>
etiketindeandroid:name
değerini ayarlayacak şekilde aşağıdaki gibi düzenleyin:<?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 şekildeMultiDexApplication
öğesini genişletmek için 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 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ıtma veya JNI aracılığıylaMultiDex.install()
veya başka bir kodu 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.
Şimdi uygulamanızı oluştururken Android derleme araçları, birincil DEX dosyası (classes.dex
) ve destekleyici DEX dosyaları (classes2.dex
, classes3.dex
vb.) oluşturur.
Ardından, derleme sistemi tüm DEX dosyalarını APK'nıza paketler.
Çalışma zamanında, multidex API'ler yalnızca ana classes.dex
dosyasında arama yapmak yerine, kullanılabilir tüm DEX dosyalarında yöntemleriniz için 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 eklerken 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 için kod küçültmeyi etkinleştirin.
- Android 5.0'dan (API düzeyi 21) önceki sürümlerde çalışırken multidex kullanmak, doğrusal sınırı aşmak için yeterli değildir (sorun 37008143). Bu sınır, Android 4.0'da (API düzeyi 14) artırılsa da sorunu tamamen çözmedi.
Android 4.0'dan düşük sürümlerde, DEX dizin sınırına ulaşmadan önce doğrusal sınırlama sınırına ulaşabilirsiniz. Bu nedenle, 14'ün altındaki API düzeylerini hedefliyorsanız uygulamanızın başlatma sırasında veya belirli sınıf grupları yüklenirken sorun 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ı bildirme
Derleme araçları, bir multidex uygulaması için her DEX dosyasını oluştururken, uygulamanızın başarılı bir şekilde başlatılabilmesi amacıyla birincil DEX dosyasında hangi sınıfların gerekli olduğunu belirlemek için karmaşık karar verme süreçleri yürütür. 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, kullandığınız bir kitaplıkta karmaşık bağımlılıklar bulunması gibi kod yollarının daha az görünür olduğu durumlarda ortaya çıkabilir. Örneğin, kod yerel koddan Java yöntemlerinin iç gözlemini veya çağrılmasını kullanı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 tanımlayarak manuel olarak belirtmeniz gerekir. multiDexKeepProguard
dosyasında eşleşen sınıflar 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
öğesinde belirttiğiniz dosya, geçerli herhangi bir ProGuard söz diziminde -keep
seçenekleri içermelidir. Örneğin, -keep com.example.MyClass.class
. multidex-config.pro
adında, şu şekilde görünen 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 aşağıdaki gibi görünür:
-keep class com.example.** { *; } // All classes in the com.example package
Ardından bu dosyayı aşağıdaki şekilde bir derleme türü için tanımlayabilirsiniz:
Eski
android { buildTypes { release { multiDexKeepProguard file('multidex-config.pro') ... } } }
Kotlin
android { buildTypes { getByName("release") { multiDexKeepProguard = file("multidex-config.pro") ... } } }
Geliştirme derlemelerinde multidex'i optimize edin
Derleme sisteminin 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 alması gerektiğinden, multidex yapılandırmasında derleme işleme süresi önemli ölçüde artar. Yani, multidex kullanan artımlı derlemeler genelde daha uzun sürer ve geliştirme sürecinizi yavaşlatabilir.
Artımlı derleme sürelerini azaltmak için önceden ekleme özelliğini kullanarak derlemeler arasında multidex çıktılarını yeniden 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çimine dayanır. Android Studio kullanıyorsanız IDE, uygulamanızı Android 5.0 (API düzeyi 21) veya sonraki sürümleri çalıştıran bir cihaza dağıtırken otomatik olarak önceden ekleme özelliğini kullanır.
Ancak Gradle derlemelerini komut satırından çalıştırıyorsanız önceden sıralamayı 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:
Eski
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") }
Derleme hızlarını Android Studio'dan veya komut satırından iyileştirmeye yardımcı olacak daha fazla strateji öğrenmek için Derleme hızınızı optimize etme bölümünü okuyun. Derleme varyantlarını kullanma hakkında daha fazla bilgi için Derleme varyantlarını yapılandırma bölümüne bakın.
İ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 altındaki alt sınıf, MultiDexApplication
sınıfını veya MultiDex.install(this)
çağrılarını genişletir.
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 bu seçeneğin 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); ... }