Memilih library dengan bijak

Untuk mengaktifkan pengoptimalan aplikasi, Anda harus menggunakan library yang kompatibel dengan pengoptimalan Android. Jika library tidak dikonfigurasi untuk pengoptimalan Android—misalnya, jika menggunakan refleksi tanpa menggabungkan aturan keep terkait—library tersebut mungkin tidak cocok untuk aplikasi Android. Halaman ini menjelaskan alasan beberapa library lebih cocok untuk pengoptimalan aplikasi dan memberikan tips umum untuk membantu Anda memilih.

Tips umum saat memilih library

Gunakan tips ini untuk membantu memastikan bahwa library Anda kompatibel dengan pengoptimalan aplikasi.

Lebih memilih codegen daripada refleksi

Pilih library yang menggunakan pembuatan kode (codegen) alih-alih refleksi. Dengan codegen, pengoptimal dapat lebih mudah menentukan kode mana yang benar-benar digunakan saat runtime dan kode mana yang dapat dihapus. Mungkin sulit untuk mengetahui apakah library menggunakan codegen atau refleksi, tetapi ada beberapa tanda—lihat tips untuk mendapatkan bantuan.

Untuk mengetahui informasi selengkapnya tentang codegen versus refleksi, lihat Pengoptimalan untuk developer library.

Memeriksa penggunaan refleksi (lanjutan)

Anda dapat mengetahui apakah library menggunakan refleksi dengan memeriksa kodenya. Jika library menggunakan refleksi, periksa apakah library tersebut menyediakan aturan keep terkait. Library kemungkinan menggunakan refleksi jika melakukan hal berikut:

  • Menggunakan class atau metode dari paket kotlin.reflect atau java.lang.reflect.
  • Menggunakan fungsi Class.forName atau classLoader.getClass.
  • Membaca anotasi saat runtime, misalnya jika menyimpan nilai anotasi menggunakan val value = myClass.getAnnotation() atau val value = myMethod.getAnnotation(), lalu melakukan sesuatu dengan value.
  • Memanggil metode menggunakan nama metode sebagai string, seperti dalam contoh berikut:

    // Calls the private `processData` API with reflection
    myObject.javaClass.getMethod("processData", DataType::class.java)
    ?.invoke(myObject, data)
    

Memeriksa masalah pengoptimalan

Saat mempertimbangkan library baru, lihat pelacak masalah dan diskusi online library untuk memeriksa apakah ada masalah terkait minifikasi atau mengonfigurasi pengoptimalan aplikasi. Jika ada, Anda harus mencoba mencari alternatif untuk library tersebut. Ingat hal berikut:

  • Library AndroidX dan library seperti Hilt berfungsi dengan baik untuk pengoptimalan aplikasi karena sebagian besar menggunakan codegen, bukan refleksi. Saat menggunakan refleksi, mereka memberikan aturan penyimpanan minimal untuk menyimpan hanya kode yang diperlukan.
  • Library serialisasi sering menggunakan refleksi untuk menghindari kode boilerplate saat membuat instance atau melakukan serialisasi objek. Daripada menggunakan pendekatan berbasis refleksi (seperti Gson untuk JSON), cari library yang menggunakan codegen untuk menghindari masalah ini, misalnya dengan menggunakan Kotlin Serialization atau Moshi dengan codegen.
  • Jika memungkinkan, hindari library yang menyertakan aturan keep di seluruh paket. Aturan penyimpanan di seluruh paket dapat membantu menyelesaikan error, tetapi aturan penyimpanan yang luas pada akhirnya harus disempurnakan untuk menyimpan hanya kode yang diperlukan. Untuk mengetahui informasi selengkapnya, lihat Menerapkan pengoptimalan secara bertahap.
  • Library tidak mengharuskan Anda menyalin dan menempelkan aturan keep dari dokumentasi ke dalam file di project Anda, terutama aturan keep di seluruh paket. Aturan ini menjadi beban pemeliharaan bagi developer aplikasi dalam jangka panjang, dan sulit dioptimalkan serta diubah dari waktu ke waktu.

Mengaktifkan pengoptimalan setelah menambahkan library baru

Saat Anda menambahkan library baru, aktifkan pengoptimalan setelahnya dan periksa apakah ada error. Jika ada error, cari alternatif untuk library tersebut atau tulis aturan penyimpanan. Jika library tidak kompatibel dengan pengoptimalan, laporkan bug pada library tersebut.

Memfilter aturan penyimpanan yang buruk (lanjutan)

Aturan penyimpanan bersifat kumulatif. Artinya, aturan tertentu yang disertakan dependensi library tidak dapat dihapus dan dapat memengaruhi kompilasi bagian lain dari aplikasi Anda. Misalnya, jika library menyertakan aturan untuk menonaktifkan pengoptimalan kode, aturan tersebut akan menonaktifkan pengoptimalan untuk seluruh project Anda.

Anda harus menghindari library dengan aturan keep yang mempertahankan kode yang seharusnya dihapus. Namun, jika Anda harus menggunakannya, Anda dapat memfilter aturan seperti yang ditunjukkan dalam kode berikut:

// If you're using AGP 8.4 and higher
buildTypes {
    release {
        optimization.keepRules {
          it.ignoreFrom("com.somelibrary:somelibrary")
        }
    }
}

// If you're using AGP 7.3-8.3
buildTypes {
    release {
        optimization.keepRules {
          it.ignoreExternalDependencies("com.somelibrary:somelibrary")
        }
    }
}

Studi kasus: Mengapa Gson tidak berfungsi dengan pengoptimalan

Gson adalah library serialisasi yang sering menyebabkan masalah pada pengoptimalan aplikasi karena sangat banyak menggunakan refleksi. Cuplikan kode berikut menunjukkan cara penggunaan Gson biasanya, yang dapat dengan mudah menyebabkan error saat runtime. Perhatikan bahwa saat Anda menggunakan Gson untuk mendapatkan daftar objek Pengguna, Anda tidak memanggil konstruktor atau meneruskan pabrik ke fungsi fromJson(). Membuat atau menggunakan class yang ditentukan aplikasi tanpa salah satu dari berikut ini adalah tanda bahwa library mungkin menggunakan refleksi terbuka:

  • Class aplikasi yang menerapkan library, atau antarmuka atau class standar
  • Plugin pembuatan kode seperti KSP
class User(val name: String)
class UserList(val users: List<User>)

// This code runs in debug mode, but crashes when optimizations are enabled
Gson().fromJson("""[{"name":"myname"}]""", User::class.java).toString()

Untuk memahami cara kerja R8 di Gson, lihat aturan konsumen Gson. Saat R8 menganalisis kode ini dan tidak melihat UserList atau User diinstansiasi di mana pun, R8 dapat mengganti nama kolom, atau menghapus konstruktor yang tampaknya tidak digunakan, sehingga menyebabkan aplikasi Anda error. Jika Anda menggunakan library lain dengan cara yang serupa, Anda harus memeriksa apakah library tersebut tidak akan mengganggu pengoptimalan aplikasi, dan jika mengganggu, hindari penggunaannya.

Untuk menentukan class dengan cara yang kompatibel dengan aturan konsumen Gson, gunakan cuplikan berikut sebagai referensi:

class User(@com.google.gson.annotations.SerializedName("name") val name: String)
class UserList(@com.google.gson.annotations.SerializedName("users") val users: List<User>)

Perhatikan bahwa Room, Hilt, dan Moshi dengan codegen membuat jenis yang ditentukan aplikasi, tetapi menggunakan codegen untuk menghindari kebutuhan akan refleksi.