Jika aplikasi Anda memiliki minSdk
API 20 atau yang lebih rendah dan aplikasi Anda serta
library yang direferensikannya melebihi 65.536 metode, Anda akan mengalami error build berikut yang
menunjukkan bahwa aplikasi Anda telah mencapai batas arsitektur build Android:
trouble writing output: Too many field references: 131000; max is 65536. You may try using --multi-dex option.
Versi sistem build yang lebih lama melaporkan error yang berbeda, yang merupakan indikasi dari masalah yang sama:
Conversion to Dalvik format failed: Unable to execute dex: method ID not in [0, 0xffff]: 65536
Kedua kondisi error ini menampilkan angka yang sama: 65536. Angka ini menunjukkan jumlah total referensi yang dapat dipanggil oleh kode dalam satu file bytecode Dalvik Executable (DEX). Halaman ini menjelaskan cara melewati batasan ini dengan mengaktifkan konfigurasi aplikasi yang disebut multidex, yang memungkinkan aplikasi Anda membuat dan membaca beberapa file DEX.
Tentang batas referensi 64K
File aplikasi Android (APK) berisi file bytecode yang dapat dieksekusi dalam bentuk file Dalvik Executable (DEX), berisi kode kompilasi yang digunakan untuk menjalankan aplikasi Anda. Spesifikasi Dalvik Executable akan membatasi jumlah total metode yang dapat direferensikan dalam satu file DEX sebesar 65.536, termasuk metode framework Android, metode library, dan metode dalam kode Anda sendiri.
Dalam konteks ilmu komputer, istilah kilo, atau K, memiliki jumlah 1.024 (atau 2^10). Karena 65.536 sama dengan 64x1024, batas ini disebut sebagai 'batas referensi 64K'.Dukungan multidex sebelum Android 5.0
Versi platform sebelum Android 5.0 (API level 21) menggunakan runtime Dalvik untuk mengeksekusi kode aplikasi. Secara default, Dalvik membatasi aplikasi ke satu file
bytecode classes.dex
per APK. Untuk mengatasi batasan
ini, tambahkan library multidex ke file build.gradle
atau
build.gradle.kts
level modul:
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") }
Library ini menjadi bagian dari file DEX utama aplikasi Anda, lalu mengelola akses ke file DEX tambahan dan kode yang dimuatnya. Untuk melihat versi terbaru library ini, lihat versi multidex.
Untuk detail selengkapnya, lihat bagian tentang cara mengonfigurasi aplikasi untuk multidex.Dukungan multidex untuk Android 5.0 dan versi lebih tinggi
Android 5.0 (API level 21) dan yang lebih tinggi menggunakan runtime yang disebut ART, yang
secara bawaan mendukung pemuatan beberapa file DEX dari file APK. ART
melakukan prakompilasi pada waktu penginstalan aplikasi, memindai file
classesN.dex
dan mengompilasinya ke dalam satu
file OAT untuk
dieksekusi oleh perangkat Android. Oleh karena itu, jika minSdkVersion
Anda
adalah versi 21 atau lebih tinggi, multidex akan diaktifkan secara default dan Anda tidak memerlukan library multidex.
Untuk mengetahui informasi selengkapnya tentang runtime Android 5.0, baca Android Runtime (ART) dan Dalvik.
Catatan: Saat menjalankan aplikasi menggunakan Android Studio, build akan dioptimalkan untuk perangkat target yang digunakan untuk deploy. Ini termasuk mengaktifkan multidex saat perangkat target menjalankan Android versi 5.0 dan yang lebih tinggi. Karena pengoptimalan ini hanya diterapkan saat men-deploy aplikasi menggunakan Android Studio, Anda mungkin masih perlu mengonfigurasi build rilis Anda untuk multidex guna menghindari batas 64K.
Menghindari batas 64K
Sebelum mengonfigurasi aplikasi untuk mengaktifkan penggunaan referensi metode 64K atau lebih, lakukan langkah-langkah untuk mengurangi jumlah referensi yang dipanggil oleh kode aplikasi, termasuk metode yang didefinisikan oleh kode aplikasi atau library yang disertakan.
Strategi berikut bisa membantu Anda agar terhindar dari mencapai batas referensi DEX:
- Meninjau dependensi langsung dan transitif aplikasi
- Pertimbangkan apakah nilai dependensi library besar yang Anda sertakan dalam aplikasi Anda melebihi jumlah kode yang ditambahkan ke aplikasi. Pola yang umum tetapi bermasalah adalah menyertakan library yang sangat besar karena beberapa metode utilitas berguna. Mengurangi dependensi kode aplikasi sering kali dapat membantu Anda menghindari batas referensi DEX.
- Menghapus kode yang tidak digunakan dengan R8
- Aktifkan penyingkatan kode untuk menjalankan R8 bagi build rilis Anda. Aktifkan penyingkatan untuk membantu memastikan Anda tidak mengirimkan kode yang tidak digunakan dengan APK Anda. Jika penyingkatan kode dikonfigurasi dengan benar, penyingkatan kode juga dapat menghapus kode dan resource yang tidak digunakan dari dependensi Anda.
Penggunaan teknik ini dapat membantu Anda mengurangi ukuran APK secara keseluruhan dan menghindari penggunaan multidex dalam aplikasi.
Mengonfigurasi aplikasi untuk multidex
Catatan: JikaminSdkVersion
disetel ke 21 atau yang lebih tinggi, multidex akan diaktifkan secara default
dan Anda tidak memerlukan library multidex.
Jika minSdkVersion
Anda disetel ke 20 atau lebih rendah, Anda
harus menggunakan
library multidex dan melakukan
modifikasi berikut untuk project aplikasi Anda:
-
Ubah file
build.gradle
level modul untuk mengaktifkan multidex dan tambahkan library multidex sebagai dependensi seperti berikut: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") }
- Bergantung pada apakah Anda mengganti class
Application
atau tidak, lakukan salah satu hal berikut ini:Jika Anda tidak mengganti class
Application
, edit file manifes untuk menetapkanandroid:name
di tag<application>
seperti berikut:<?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>
Jika Anda mengganti class
Application
, ubah class untuk memperluasMultiDexApplication
, seperti berikut:Kotlin
class MyApplication : MultiDexApplication() {...}
Java
public class MyApplication extends MultiDexApplication { ... }
Jika Anda mengganti class
Application
tetapi tidak memungkinkan untuk mengubah class dasarnya, gantilah metodeattachBaseContext()
dan panggilMultiDex.install(this)
untuk mengaktifkan multidex: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); } }
Perhatian: Jangan jalankan
MultiDex.install()
atau kode lainnya melalui refleksi atau JNI sebelumMultiDex.install()
selesai. Pelacakan multidex tidak akan mengikuti panggilan tersebut, sehingga mengakibatkanClassNotFoundException
atau error verifikasi karena partisi class yang buruk antar-file DEX.
Sekarang, saat Anda membuat aplikasi, alat build Android akan membuat file DEX utama (classes.dex
) dan file DEX pendukung (classes2.dex
, classes3.dex
, dan seterusnya) sesuai kebutuhan.
Sistem build kemudian akan memaketkan semua file DEX ke APK Anda.
Saat runtime, alih-alih hanya menelusuri di
file classes.dex
utama, API multidex menggunakan loader class khusus untuk menelusuri semua
file DEX yang tersedia untuk metode Anda.
Batasan library multidex
Library multidex memiliki beberapa batasan umum. Saat Anda menyertakan library ke dalam konfigurasi build aplikasi, pertimbangkan hal berikut:
- Penginstalan file DEX selama startup ke partisi data perangkat adalah proses yang kompleks dan dapat mengakibatkan error Aplikasi Tidak Merespons (ANR) jika file DEX sekunder berukuran besar. Untuk menghindari masalah ini, aktifkan penyingkatan kode guna meminimalkan ukuran file DEX dan menghapus bagian kode yang tidak terpakai.
- Jika menjalankan pada versi sebelum Android 5.0 (API level 21), penggunaan
multidex tidaklah cukup untuk mengatasi batasan linearalloc (masalah 37008143). Batas ini ditingkatkan di
Android 4.0 (API level 14), tetapi masalah tidak teratasi sepenuhnya.
Pada versi yang lebih rendah dari Android 4.0, Anda mungkin mencapai batas linearalloc sebelum mencapai batas indeks DEX. Jadi, jika Anda menargetkan API level di bawah 14, lakukan pengujian menyeluruh pada versi platform tersebut karena aplikasi Anda mungkin memiliki masalah saat startup atau ketika grup class tertentu dimuat.
Penyingkatan kode dapat mengurangi atau mungkin menghilangkan masalah-masalah ini.
Mendeklarasikan class yang diperlukan dalam file DEX utama
Saat membuat setiap file DEX untuk aplikasi multidex, alat build akan melakukan pengambilan keputusan yang kompleks guna menentukan class mana yang diperlukan dalam file DEX utama agar aplikasi Anda berhasil dimulai. Jika class yang diperlukan selama startup tidak disediakan dalam file DEX utama, aplikasi akan berhenti bekerja dan menampilkan error java.lang.NoClassDefFoundError
.
Alat build mengenali jalur kode untuk kode yang diakses langsung dari kode aplikasi Anda. Namun, masalah ini dapat terjadi saat jalur kode kurang terlihat, misalnya saat library yang Anda gunakan memiliki dependensi yang kompleks. Contohnya, jika kode tersebut menggunakan introspeksi atau pemanggilan metode Java dari kode native, class tersebut mungkin tidak akan dikenali sebagaimana diperlukan dalam file DEX utama.
Jika menerima java.lang.NoClassDefFoundError
, Anda
harus menentukan secara manual class tambahan yang diperlukan dalam file DEX utama
dengan mendeklarasikannya menggunakan properti multiDexKeepProguard
dalam jenis build Anda. Jika class cocok dengan
file multiDexKeepProguard
, class tersebut
akan ditambahkan ke file DEX utama.
Properti multiDexKeepProguard
File multiDexKeepProguard
menggunakan format yang sama dengan ProGuard dan mendukung
seluruh tata bahasa ProGuard. Untuk informasi selengkapnya tentang cara menyesuaikan apa yang dipertahankan di aplikasi Anda, lihat
Menyesuaikan kode yang perlu dipertahankan.
File yang ditentukan dalam multiDexKeepProguard
harus berisi opsi -keep
dalam setiap sintaksis ProGuard yang valid. Misalnya, -keep com.example.MyClass.class
. Anda dapat membuat file bernama multidex-config.pro
yang terlihat seperti ini:
-keep class com.example.MyClass -keep class com.example.MyClassToo
Jika ingin menetapkan semua class dalam satu paket, filenya akan terlihat seperti ini:
-keep class com.example.** { *; } // All classes in the com.example package
Kemudian, Anda dapat mendeklarasikan file tersebut untuk jenis build seperti berikut:
Groovy
android { buildTypes { release { multiDexKeepProguard file('multidex-config.pro') ... } } }
Kotlin
android { buildTypes { getByName("release") { multiDexKeepProguard = file("multidex-config.pro") ... } } }
Mengoptimalkan multidex dalam build pengembangan
Konfigurasi multidex memerlukan lebih banyak waktu proses build yang signifikan karena sistem build harus membuat keputusan kompleks tentang class yang harus disertakan dalam file DEX utama dan class yang dapat disertakan dalam file DEX sekunder. Ini berarti bahwa build inkremental yang menggunakan multidex biasanya memerlukan waktu lebih lama dan berpotensi memperlambat proses pengembangan Anda.
Untuk mengurangi waktu build tambahan yang lebih lama, gunakan
pre-dexing untuk menggunakan kembali output multidex antar-build.
Pre-dexing mengandalkan format ART yang hanya tersedia di Android 5.0 (API level 21) dan yang lebih baru. Jika Anda menggunakan Android Studio, IDE akan otomatis menggunakan pre-dexing
saat men-deploy aplikasi ke perangkat yang menjalankan Android 5.0 (API level 21) atau yang lebih tinggi.
Namun, jika menjalankan build Gradle dari command line, Anda perlu menetapkan
minSdkVersion
ke 21 atau yang lebih tinggi untuk mengaktifkan pre-dexing.
minSdkVersion
,
seperti yang ditunjukkan:
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") }
Untuk mempelajari lebih lanjut strategi guna membantu meningkatkan kecepatan build dari Android Studio atau command line, baca Mengoptimalkan kecepatan build Anda. Untuk mengetahui informasi selengkapnya tentang penggunaan varian build, baca Mengonfigurasi varian build.
Tips: Jika memiliki varian build yang berbeda untuk kebutuhan
multidex yang berbeda, Anda dapat menyediakan file manifes yang berbeda untuk setiap
varian sehingga hanya file untuk API level 20 dan yang lebih rendah yang mengubah
nama tag <application>
. Anda juga dapat
membuat subclass Application
yang berbeda untuk setiap varian sehingga
hanya subclass untuk API level 20 dan yang lebih rendah yang memperluas class MultiDexApplication
atau
memanggil MultiDex.install(this)
.
Menguji aplikasi multidex
Saat menulis uji instrumentasi untuk aplikasi multidex, tidak ada konfigurasi tambahan yang diperlukan
jika Anda menggunakan instrumentasi
MonitoringInstrumentation
atau
AndroidJUnitRunner
. Jika menggunakan Instrumentation
lain, Anda harus mengganti metode onCreate()
-nya dengan kode berikut ini:
Kotlin
fun onCreate(arguments: Bundle) { MultiDex.install(targetContext) super.onCreate(arguments) ... }
Java
public void onCreate(Bundle arguments) { MultiDex.install(getTargetContext()); super.onCreate(arguments); ... }