Ketika aplikasi Anda beserta library yang direferensikannya melebihi 65.536 metode, akan muncul error build yang menunjukkan bahwa aplikasi 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, K, memiliki jumlah 1.024 (atau 2^10). Karena 65.536 sama dengan 64 X 1024, 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
level modul:
dependencies { def multidex_version = "2.0.1" implementation "androidx.multidex:multidex:$multidex_version" }
Untuk melihat versi sekarang library ini, lihat informasi tentang Multidex pada halaman versi.
Jika tidak menggunakan AndroidX, tambahkan dependensi support library berikut yang tidak digunakan lagi sebagai gantinya:
dependencies { implementation 'com.android.support:multidex:1.0.3' }
Library ini menjadi bagian dari file DEX utama aplikasi Anda, lalu mengelola akses ke file DEX tambahan dan kode yang dimuatnya. Detail selengkapnya ada di bawah ini, di bagian cara mengonfigurasi aplikasi Anda 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 pra-kompilasi pada waktu penginstalan aplikasi yang memindai file
classesN.dex
dan mengompilasinya ke satu
file .oat
untuk
dieksekusi oleh perangkat Android. Oleh karena itu, jika versi minSdkVersion
Anda
adalah 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 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 versi Android 5.0 dan yang lebih baru. 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, Anda harus melakukan langkah-langkah untuk mengurangi jumlah referensi yang dipanggil oleh kode aplikasi, termasuk metode yang didefinisikan oleh kode aplikasi atau library yang disertakan. Strategi berikut ini dapat membantu Anda agar tidak mencapai batas referensi DEX:
- Tinjau dependensi langsung dan transitif aplikasi - Pastikan setiap dependensi library berukuran besar yang disertakan dalam aplikasi Anda digunakan sedemikian rupa sehingga nilai gunanya melebihi jumlah kode yang ditambahkan ke aplikasi. Antipola umum adalah menyertakan library yang sangat besar karena beberapa metode utilitas sebelumnya berguna. Mengurangi dependensi kode aplikasi sering kali dapat membantu Anda menghindari batas referensi DEX.
- Hapus kode yang tidak digunakan dengan R8 - Aktifkan penyingkatan kode untuk menjalankan R8 bagi build rilis Anda. Mengaktifkan penyingkatan akan memastikan Anda tidak mengirimkan kode yang tidak digunakan dengan APK Anda.
Penggunaan teknik-teknik ini dapat membantu Anda menghindari keharusan mengaktifkan multidex dalam aplikasi sekaligus mengurangi ukuran keseluruhan APK.
Mengonfigurasi aplikasi untuk multidex
Jika minSdkVersion
ditetapkan ke versi 21 atau lebih tinggi, multidex akan diaktifkan secara default
dan Anda tidak memerlukan library multidex.
Namun, jika minSdkVersion
ditetapkan ke versi 20 atau lebih rendah, maka Anda
harus menggunakan
library multidex dan melakukan
modifikasi berikut pada project aplikasi:
-
Ubah file
build.gradle
level modul untuk mengaktifkan multidex dan tambahkan library multidex sebagai dependensi seperti berikut:android { defaultConfig { ... minSdkVersion 15 targetSdkVersion 28 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 Anda untuk menetapkanandroid:name
dalam 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 tersebut untuk memperluasMultiDexApplication
(jika memungkinkan) seperti berikut:Kotlin
class MyApplication : MultiDexApplication() {...}
Java
public class MyApplication extends MultiDexApplication { ... }
Jika mengganti class
Application
tetapi tidak memungkinkan untuk mengubah class dasarnya, Anda dapat mengganti metodeattachBaseContext()
dan memanggilMultiDex.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 eksekusi
MultiDex.install()
atau kode lain apa pun 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.
Pada runtime, API multidex menggunakan loader class khusus untuk menelusuri semua
file DEX yang tersedia bagi metode Anda (tidak hanya menelusuri dalam file
classes.dex
utama).
Batasan library multidex
Library multidex memiliki beberapa batasan umum yang harus Anda ketahui dan uji saat Anda memasukkannya ke konfigurasi build aplikasi:
- 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 78035). Batas ini dinaikkan di Android 4.0 (API level 14), tetapi masalah tidak teratasi sepenuhnya. Dan 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
.
Hal ini tidak akan terjadi untuk kode yang diakses secara langsung dari kode aplikasi karena alat build mengenali lokasi kode tersebut, tetapi ini dapat terjadi jika jalur kode kurang jelas, misalnya saat library yang digunakan 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.
Jadi, jika Anda menerima java.lang.NoClassDefFoundError
, Anda harus menentukan class tambahan berikut ini secara manual seperti yang diperlukan dalam file DEX utama dengan mendeklarasikannya menggunakan properti multiDexKeepFile
atau multiDexKeepProguard
dalam jenis build Anda. Jika suatu class dicocokkan dalam file multiDexKeepFile
atau multiDexKeepProguard
, class tersebut akan ditambahkan ke file DEX utama.
Properti multiDexKeepFile
File yang ditentukan dalam multiDexKeepFile
harus berisi satu class per baris, dalam format com/example/MyClass.class
. Misalnya, Anda dapat membuat file bernama multidex-config.txt
yang terlihat seperti ini:
com/example/MyClass.class com/example/MyOtherClass.class
Kemudian, Anda dapat mendeklarasikan file tersebut untuk jenis build seperti berikut:
android { buildTypes { release { multiDexKeepFile file('multidex-config.txt') ... } } }
Perlu diingat bahwa Gradle akan membaca jalur secara relatif terhadap file build.gradle
, sehingga contoh di atas akan berfungsi jika multidex-config.txt
berada dalam direktori yang sama dengan file build.gradle
.
Properti multiDexKeepProguard
File multiDexKeepProguard
akan menggunakan format yang sama dengan Proguard dan mendukung seluruh gramatika Proguard. Untuk mengetahui informasi selengkapnya tentang format dan tata bahasa Proguard, lihat bagian Keep Options pada panduan Proguard.
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 bisa mendeklarasikan file tersebut untuk jenis build seperti berikut:
android { buildTypes { 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 kembali menggunakan 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 2.3 dan yang lebih tinggi, IDE akan otomatis menggunakan fitur ini saat men-deploy aplikasi Anda ke perangkat yang menjalankan Android 5.0 (API level 21) atau yang lebih baru.
Tips: plugin Android untuk Gradle 3.0.0 dan yang lebih baru menyertakan peningkatan lebih lanjut untuk mengoptimalkan kecepatan build, seperti dexing per class (sehingga hanya class yang diubah yang di-dex ulang). Secara umum, untuk mendapatkan pengalaman pengembangan terbaik, sebaiknya Anda selalu mengupgrade ke versi terbaru Android Studio dan plugin Android.
Namun, jika menjalankan build Gradle dari command line, Anda perlu menetapkan minSdkVersion
ke 21 atau yang lebih baru untuk mengaktifkan pre-dexing. Strategi yang dapat membantu mempertahankan setelan untuk build produksi adalah dengan membuat dua versi aplikasi menggunakan ragam produk: ragam pengembangan dan ragam rilis dengan nilai yang berbeda untuk minSdkVersion
, seperti yang ditunjukkan di bawah ini.
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 what you set for // 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" }
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: Setelah memiliki beragam varian build untuk berbagai
kebutuhan multidex, Anda juga dapat menyediakan file manifes yang berbeda untuk setiap
varian (jadi hanya varian untuk API level 20 dan yang lebih rendah yang mengubah
nama tag <application>
),
atau membuat subclass Application
yang berbeda untuk setiap varian (jadi
hanya varian 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); ... }