Uygulamanızın 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 şu derleme hatasıyla karşılaşırsınız:minSdk
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ı soruna işaret eden 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ı içindeki kod tarafından çağrılabilen toplam referans sayısını gösterir. 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.
64.000 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) dosyaları 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 de dahil olmak üzere tek bir DEX dosyasında referans verilebilecek toplam yöntem sayısını 65.536 ile sınırlar.
Bilgisayar bilimleri bağlamında kilo veya K terimi 1024'ü (veya 2^10) ifade eder. 65.536, 64x1024'e eşit olduğundan bu sınıra _64K referans sınırı_ adı verilir.Android 5.0'dan önceki sürümlerde multidex desteği
Platformun Android 5.0 (API düzeyi 21) öncesi sürümlerinde uygulama kodunu yürütmek için Dalvik çalışma zamanı kullanılır. Varsayılan olarak Dalvik, uygulamaları APK başına tek bir classes.dex
bayt kodu dosyasıyla sınırlar. 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ümlerine bakın.
Daha fazla bilgi için Uygulamanızı multidex için yapılandırma başlıklı bölümü inceleyin.Android 5.0 ve sonraki sürümlerde 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 sırasında ön derleme gerçekleştirir, classesN.dex
dosyalarını tarar ve bunları Android cihaz tarafından yürütülmek üzere tek bir OAT dosyası olarak derler. Bu nedenle, minSdkVersion
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 inceleyin.
Not: Uygulamanızı Android Studio'yu kullanarak çalıştırdığınızda, derleme, dağıtım yaptığınız hedef cihazlar için optimize edilir. Hedef cihazlarda Android 5.0 ve sonraki sürümler çalışırken multidex'in etkinleştirilmesi 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ın derlemenizi multidex için yapılandırmanız gerekebilir.
64.000 karakter sınırını aşmaktan kaçının
Uygulamanızı 64.000 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 da 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ş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 kitaplık bağımlılıklarının değerinin, uygulamaya eklenen kod miktarından daha fazla olup olmadığını değerlendirin. Birkaç yardımcı yöntemin faydalı olması nedeniyle çok büyük bir kitaplığın eklenmesi yaygın ancak sorunlu bir durumdur. Uygulama kodu bağımlılıklarınızı azaltmak genellikle DEX referans sınırından kaçınmanıza yardımcı olabilir.
- R8 ile kullanılmayan kodu kaldırma Sürüm derlemelerinizde R8'i çalıştırmak için
- kod küçültmeyi etkinleştirin. APK'larınızla kullanılmayan kodları göndermediğinizden emin olmak için küçültmeyi etkinleştirin. Kod küçültme doğru şekilde yapılandırılırsa bağımlılıklarınızdaki kullanılmayan kodları ve kaynakları da kaldırabilir.
Bu teknikleri kullanarak APK'nızın genel boyutunu küçültebilir ve uygulamanızda multidex kullanma ihtiyacını ortadan kaldırabilirsiniz.
Uygulamanızı multidex için yapılandırma
Not:minSdkVersion
değeriniz 21 veya daha yüksekse multidex varsayılan olarak etkindir
ve multidex 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 ve multidex kitaplığını bağımlılık olarak eklemek için modül düzeyindeki
build.gradle
dosyasını aşağıdaki gibi değiştirin: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ılıp kılmadığını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>
etiketindeandroid: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
sınıfını 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 olmazsa bunun yerineattachBaseContext()
yöntemini geçersiz kılın ve çoklu dex'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()
ya da başka bir kodu yürütmeyin. Multidex izleme bu çağrıları takip etmez. Bu durum, DEX dosyaları arasında kötü bir sınıf bölümlemesi nedeniyleClassNotFoundException
veya doğrulama hatalarına neden olur.
Artık uygulamanızı oluşturduğunuzda Android derleme araçları, gerektiğinde 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, yalnızca ana classes.dex
dosyasında arama yapmak yerine, çoklu DEX API'leri, yöntemleriniz için mevcut tüm DEX dosyalarında arama yapmak üzere özel bir sınıf yükleyici kullanır.
Multidex kitaplığının sınırlamaları
Çoklu dex kitaplığının bilinen bazı sınırlamaları vardır. Kitaplığı uygulamanızın derleme yapılandırmasına dahil ederken aşağıdakileri göz önünde bulundurun:
- Başlangıç sırasında DEX dosyalarının 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 küçültmeyi etkinleştirerek DEX dosyalarının boyutunu en aza indirin ve kodun kullanılmayan kısımlarını kaldırın.
- Android 5.0'dan (API düzeyi 21) önceki sürümlerde çalıştırılırken, linearalloc sınırını (37008143 numaralı sorun) aşmak için multidex kullanmak yeterli değildir. Bu sınır, Android 4.0'da (API düzeyi 14) artırılmış olsa da sorun tamamen çözülmemiştir.
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 API seviyelerini hedefliyorsanız platformun bu sürümlerinde kapsamlı bir test yapın. Aksi takdirde, uygulamanız başlatılırken veya belirli sınıf grupları yüklenirken sorun yaşayabilir.
Kod küçültme, bu sorunları azaltabilir veya tamamen ortadan kaldırabilir.
Birincil DEX dosyasında gereken sınıfları bildirme
Çoklu DEX uygulaması için her bir DEX dosyası oluşturulurken derleme araçları, uygulamanızın başarılı bir şekilde başlatılabilmesi için birincil DEX dosyasında hangi sınıfların gerekli olduğunu belirlemek üzere karmaşık kararlar verir. Başlatma sırasında gerekli olan 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ı daha az görünür olduğunda (ör. kullandığınız bir kitaplığın karmaşık bağımlılıkları olduğunda) ortaya çıkabilir. Örneğin, kod, Java yöntemlerinin yerel koddan yansıtılmasını veya çağrılması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 ProGuard gramerinin tamamını destekler. Uygulamanızda nelerin tutulacağını özelleştirme hakkında daha fazla bilgi için Hangi kodun tutulacağını özelleştirme başlıklı makaleyi inceleyin.
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
. Şu şekilde görünen bir multidex-config.pro
dosyası 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ı aşağıdaki gibi bir derleme türü için bildirebilirsiniz:
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
Çoklu DEX yapılandırması, 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 vermek zorunda olduğundan derleme işleme süresinin önemli ölçüde artmasını gerektirir. Bu nedenle, multidex kullanan artımlı derlemeler genellikle daha uzun sürer ve geliştirme sürecinizi yavaşlatabilir.
Daha uzun artımlı derleme sürelerini azaltmak için derlemeler arasında çoklu dex çıkışını yeniden kullanmak üzere önceden dexleme özelliğini kullanın.
Önceden dex oluşturma, 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 bir sürümü çalıştıran bir cihaza dağıtırken otomatik olarak önceden dexleme kullanır.
Ancak Gradle derlemelerini komut satırından çalıştırıyorsanız önceden dexleme özelliğini etkinleştirmek için minSdkVersion
değerini 21 veya daha yüksek bir değere ayarlamanız gerekir.
minSdkVersion
için farklı değerler kullanılır.
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 veya komut satırından 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 inceleyin. Derleme varyantlarını kullanma hakkında daha fazla bilgi için Derleme varyantlarını yapılandırma başlıklı makaleyi inceleyin.
İpucu: Farklı çoklu dex 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ı da oluşturabilirsiniz. Böylece yalnızca API düzeyi 20 ve önceki sürümler için olan alt sınıf, MultiDexApplication
sınıfını genişletir veya MultiDex.install(this)
'ı çağırır.
Multidex uygulamalarını test etme
Çoklu dex uygulamaları için enstrümantasyon testleri yazarken
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); ... }