64K'dan fazla yöntemler içeren uygulamalar için multidex'i etkinleştirin

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:

  1. Modül düzeyindeki build.gradle dosyası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")
    }
  2. 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ı düzenleyerek <application> etiketinde 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 bunu MultiDexApplication sınıfını genişletecek şekilde aşağıdaki gibi değiştirin:

      Kotlin

      class MyApplication : MultiDexApplication() {...}

      Java

      public class MyApplication extends MultiDexApplication { ... }
    • Application sınıfını geçersiz kılıyor ancak temel sınıfı değiştiremiyorsanız attachBaseContext() yöntemini geçersiz kılın ve multidex'i etkinleştirmek için MultiDex.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ığıyla MultiDex.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ü nedeniyle ClassNotFoundException veya 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.

Üretim derlemenizin ayarlarını korumak için ürün türlerini kullanarak uygulamanızın iki sürümünü oluşturabilirsiniz. Bu sürümlerden biri geliştirme türünde, diğeri ise yayınlama türünde olur ve 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);
  ...
}