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ı gösterir. 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, 64x1024'e eşit olduğundan bu sınıra _64K referans sınırı_ denir.

Android 5.0'den önceki sürümlerde çoklu paket 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 bytecode 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 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ümler, APK dosyalarından birden fazla DEX dosyasının yüklenmesini doğal 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ü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 Ç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 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.

64 KB sınırını aşmayı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 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şmanızı önlemeye yardımcı olabilir:

Uygulamanızın doğrudan ve geçişli bağımlılıklarını inceleme
Uygulamanıza dahil ettiğiniz büyük kitaplık bağımlılıklarının değerinin, uygulamaya eklenen kod miktarından daha fazla olup olmadığını düşünün. Birkaç yardımcı program yöntemi yararlı olduğu için çok büyük bir kitaplık eklemek yaygın ancak sorunlu bir uygulamadır. Uygulama kodunuzdaki bağımlılıkları azaltmak genellikle DEX referans sınırını aşmanızı önleyebilir.
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. Çoklu Dex izleme bu çağrıları takip etmez. Bu da DEX dosyaları arasındaki sınıf bölümünün bozuk olması nedeniyle ClassNotFoundException veya doğrulama hatalarına neden olur.

Artık uygulamanızı oluşturduğunuzda Android derleme araçları, birincil bir DEX dosyası (classes.dex) ve gerektiğinde 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ığı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:

  • DEX dosyalarının cihazın veri bölümüne başlatılma sırasında 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 kodun kullanılmayan 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'dan önceki sürümlerde, DEX dizini sınırına ulaşmadan önce linearalloc sınırına ulaşabilirsiniz. Bu nedenle, 14'ten düşük API seviyelerini hedefliyorsanız uygulamanızın başlangıçta veya belirli sınıf grupları yüklenirken sorun yaşayabileceğinden platformun bu sürümlerinde kapsamlı bir test yapın.

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

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

Derleme araçları, çok DEX'li bir uygulamanın her DEX dosyasını oluştururken birincil DEX dosyasında hangi sınıflara ihtiyaç duyulduğunu belirlemek için karmaşık kararlar alır. Bu sayede uygulamanız başarıyla başlatılabilir. Başlatma sırasında gerekli olan sınıflar 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 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 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 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 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 ön dexing özelliğini kullanarak derlemeler arasında çoklu dex çıktısını yeniden kullanın. Ön dex oluşturma 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 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 için ürün aromalarını kullanarak uygulamanızın iki sürümünü oluşturabilirsiniz. Bu sürümlerden biri geliştirme aromalı, diğeri ise sürüm aromalı olur. Her iki sürümde de 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'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 daha düşük olan dosyada <application> etiket adı değişir. 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

Çok dex'li 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);
  ...
}