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

Uygulamanızın minSdk API 20 veya önceki sürümü varsa ve uygulamanız ve referans verdiği 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 farklı bir hata bildiriyor. Bu hata, aynı sorunun göstergesi:

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 atlatabileceğiniz açıklanmaktadır.

64K referans sınırı hakkında

Android uygulama (APK) dosyaları, Dalvik Yürütülebilir (DEX) dosyası 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 spesifikasyonu, tek bir DEX dosyasında referans verilebilecek yöntemlerin toplam sayısını 65.536 ile sınırlandırır (Android çerçeve yöntemleri, kitaplık yöntemleri ve kendi kodunuzdaki yöntemler dahil).

Bilgisayar bilimi bağlamında kilo veya K terimi 1024 (veya 2^10) anlamına gelir. 65.536, 64x1024 değerine eşit olduğundan bu sınıra _64K referans sınırı_ denir.

Android 5.0 öncesi 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. Varsayılan olarak Dalvik, uygulamaları 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:

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 bunların içerdiği koda erişimi yönetir. Bu kitaplığın güncel 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 bölümüne 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 önceden derleme gerçekleştirir, classesN.dex dosyalarını tarar ve Android cihaz tarafından yürütülmesi için bunları 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 için Android Runtime (ART) ve Dalvik'i okuyun.

Not: Uygulamanızı Android Studio ile çalıştırdığınızda derleme, dağıtım yaptığınız hedef cihazlar için optimize edilir. Buna, hedef cihazlarda Android 5.0 ve sonraki sürümleri çalıştıran multidex'in etkinleştirilmesi dahildir. Bu optimizasyon yalnızca uygulamanızı Android Studio kullanarak dağıtırken uygulandığından, 64K sınırından kaçınmak amacıyla yine de multidex için sürüm derlemenizi 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ımını etkinleştirecek şekilde yapılandırmadan önce, uygulama kodunuz veya dahil edilen kitaplıklar tarafından tanımlanan yöntemler de dahil olmak üzere uygulama kodunuzun çağırdığı 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ığının değerinin, uygulamaya eklenen kod miktarına eşit olup olmadığını düşünün. Yaygın ancak sorunlu bir kalıp, birkaç yardımcı yöntemden dolayı ç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.
R8 ile kullanılmayan kodları kaldırın
Sürüm derlemelerinizde R8'i çalıştırmak için kod daraltmayı etkinleştirin. APK'larınızla kullanılmayan kod göndermediğinizden emin olmak için daraltmayı etkinleştirin. Kod daraltma özelliği doğru şekilde yapılandırılırsa kullanılmayan kod ve kaynakları da bağımlılıklarınızdan kaldırabilir.

Bu teknikleri kullanmak, APK'nızın genel boyutunu küçültmenize ve uygulamanızda multidex ihtiyacını önlemenize yardımcı olabilir.

Uygulamanızı multidex için yapılandırma

Not: minSdkVersion 21 veya daha yüksek bir değere ayarlanırsa multidex varsayılan olarak etkinleştirilir ve multidex kitaplığına ihtiyacınız yoktur.

minSdkVersion değeriniz 20 veya daha düşük bir değere ayarlanırsa multidex kitaplığını kullanmanız ve uygulama projenizde aşağıdaki değişiklikleri yapmanız gerekir:

  1. Burada gösterildiği gibi, 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 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ılıp kılmamanıza bağlı olarak aşağıdakilerden birini gerçekleştirin:
    • Application sınıfını geçersiz kılmazsanız manifest dosyanızı, <application> etiketinde android:name içerecek ş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 adımları uygulayarak MultiDexApplication 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 değilse bunun yerine, multidex'i etkinleştirmek için attachBaseContext() yöntemini geçersiz kılın ve 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() veya başka herhangi bir kodu yürütmeyin. Çokludex izleme bu çağrıları takip etmeyeceğinden DEX dosyaları arasındaki bozuk sınıf bölümü nedeniyle ClassNotFoundException veya doğrulama hataları meydana gelir.

Artık uygulamanızı derleme sırasında Android derleme araçları, gerektiğinde birincil DEX dosyası (classes.dex) ve destekleyen DEX dosyaları (classes2.dex, classes3.dex vb.) oluşturur. Daha sonra derleme sistemi, tüm DEX dosyalarını APK'nızın içine paketler.

Multidex API'leri, çalışma zamanında yalnızca ana classes.dex dosyasında arama yapmak yerine mevcut tüm DEX dosyalarında yöntemlerinizi aramak için ö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 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 kod küçültmeyi etkinleştirerek DEX dosyalarının boyutunu en aza indirin ve kullanılmayan kod bölümlerini kaldırın.
  • Android 5.0'dan (API düzeyi 21) önceki sürümlerde çalışırken multidex kullanmak, lineeralloc sınırını aşmak için yeterli olmaz (sorun 37008143). Bu sınır, Android 4.0'da (API düzeyi 14) artırıldı ancak sorunu tamamen çözmedi.

    Android 4.0'dan önceki sürümlerde, DEX dizin sınırına ulaşmadan önce lineeralloc sınırına ulaşabilirsiniz. Bu nedenle, 14'ün altındaki API düzeylerini hedefliyorsanız platformun bu sürümleri üzerinde ayrıntılı testler yapın. Bunun nedeni, uygulamanızda başlangıçta veya belirli sınıf grupları yüklendiğinde sorun yaşanabilmesidir.

    Kod daraltma, bu sorunları azaltabilir veya muhtemelen ortadan kaldırabilir.

Birincil DEX dosyasında gerekli sınıfları belirtme

Multidex uygulamaları için her DEX dosyası derlenirken derleme araçları, uygulamanızın başarılı bir şekilde başlayabilmesi için birincil DEX dosyasında hangi sınıfların gerekli olduğunu belirlemek amacıyla karmaşık karar verme süreçleri uygular. Başlatma sırasında gereken 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 kodların kod yollarını tanır. Ancak bu sorun, kod yolları daha az görünür olduğunda (örneğin, 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özlemi 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 özelliğiyle bildirerek manuel olarak belirtmeniz gerekir. multiDexKeepProguard dosyasında eşleştirilen bir sınıf, birincil DEX dosyasına eklenir.

multiDexKeepProGuard özelliği

multiDexKeepProguard dosyası ProGuard ile aynı biçimi kullanır ve ProGuard dilbilgisinin tamamını destekler. Uygulamanızda saklanan öğeleri nasıl özelleştireceğinizle ilgili daha fazla bilgi için Saklanacak kodu özelleştirme konusuna bakın.

multiDexKeepProguard içinde 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 şuna benzer 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, bir derleme türü için bu dosyayı aşağıdaki şekilde 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 edin

Derleme sisteminin birincil DEX dosyasına hangi sınıfların eklenmesi gerektiği ve hangi sınıfların ikincil DEX dosyalarına dahil edileceği konusunda karmaşık kararlar vermesi gerektiğinden, multidex yapılandırmasında derleme işleme süresinin önemli ölçüde artırılması gerekir. Bu, multidex kullanan artımlı derlemelerin genellikle daha uzun sürdüğü ve geliştirme sürecinizi yavaşlatabileceği anlamına gelir.

Daha uzun artımlı derleme sürelerinin etkisini azaltmak için derlemeler arasında multidex çıkışını yeniden kullanmak üzere ön sıralama yöntemini kullanın. Önceden dizinleme, 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 sürümleri çalıştıran bir cihaza dağıtırken otomatik olarak önceden dizinlemeyi kullanır. Ancak, Gradle derlemelerini komut satırından çalıştırıyorsanız önceden dizine eklemeyi 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 çeşitlerini kullanarak uygulamanızın iki sürümünü oluşturabilirsiniz. Bu sürümlerden biri geliştirme çeşidine, diğeri sürüm çeşidine sahip olup minSdkVersion için farklı değerler içerir. Örneğin:

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 veya komut satırından derleme hızlarını 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ı çokludex 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ümler için olan dosyalar <application> etiketinin 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 önceki alt sınıfların alt sınıfı, MultiDexApplication sınıfını genişletir veya MultiDex.install(this) yöntemini çağırır.

Multidex uygulamalarını test edin

Multidex uygulamaları için araç testleri yazarken MonitoringInstrumentation veya AndroidJUnitRunner araçları 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);
  ...
}