Sebagai penulis library, Anda harus memastikan bahwa developer aplikasi dapat dengan mudah memasukkan library Anda ke dalam aplikasi mereka sekaligus mempertahankan pengalaman pengguna akhir yang berkualitas tinggi. Anda harus memastikan bahwa library Anda kompatibel dengan pengoptimalan Android tanpa penyiapan tambahan—atau mendokumentasikan bahwa library mungkin tidak sesuai untuk digunakan di Android.
Dokumentasi ini ditujukan untuk developer library yang dipublikasikan, tetapi mungkin juga berguna bagi developer modul library internal dalam aplikasi besar yang dimodularisasi.
Jika Anda adalah developer aplikasi dan ingin mempelajari cara mengoptimalkan aplikasi Android, lihat Mengaktifkan pengoptimalan aplikasi. Untuk mempelajari library yang sesuai untuk digunakan, lihat Memilih library dengan bijak.
Menggunakan codegen daripada refleksi
Jika memungkinkan, gunakan pembuatan kode (codegen) daripada refleksi. Codegen dan refleksi adalah pendekatan umum untuk menghindari kode boilerplate saat memprogram, tetapi codegen lebih kompatibel dengan pengoptimal aplikasi seperti R8:
- Dengan codegen, kode dianalisis dan diubah selama proses build. Karena tidak ada modifikasi besar setelah waktu kompilasi, pengoptimal mengetahui kode yang pada akhirnya diperlukan dan kode yang dapat dihapus dengan aman.
- Dengan refleksi, kode dianalisis dan dimanipulasi saat runtime. Karena kode tidak benar-benar selesai hingga dieksekusi, pengoptimal tidak tahu kode apa yang dapat dihapus dengan aman. Tindakan ini kemungkinan akan menghapus kode yang digunakan secara dinamis melalui refleksi selama runtime, yang menyebabkan error aplikasi bagi pengguna.
Banyak library modern menggunakan codegen, bukan refleksi. Lihat KSP untuk titik entri umum, yang digunakan oleh Room, Dagger2, dan banyak lagi.
Saat refleksi diizinkan
Jika harus menggunakan refleksi, Anda hanya boleh memantulkan ke salah satu hal berikut:
- Jenis yang ditargetkan secara spesifik (penerapkan antarmuka atau subclass tertentu)
- Kode yang menggunakan anotasi runtime tertentu
Menggunakan refleksi dengan cara ini akan membatasi biaya runtime, dan memungkinkan penulisan aturan penyimpanan konsumen yang ditargetkan.
Bentuk refleksi spesifik dan tertarget ini adalah pola yang dapat Anda lihat di framework Android (misalnya saat meng-inflate aktivitas, tampilan, dan drawable) dan library AndroidX (misalnya saat membuat WorkManager ListenableWorkers, atau RoomDatabases). Sebaliknya, refleksi terbuka Gson tidak sesuai untuk digunakan di aplikasi Android.
Menulis aturan simpan konsumen
Library harus memaketkan aturan keep "konsumen", yang menggunakan format yang sama dengan aturan keep aplikasi. Aturan ini dipaketkan ke dalam artefak library (AAR atau JAR) dan digunakan secara otomatis selama pengoptimalan aplikasi Android saat library digunakan.
Library AAR
Untuk menambahkan aturan konsumen untuk library AAR, gunakan opsi consumerProguardFiles
dalam skrip build modul library Android. Untuk informasi selengkapnya, lihat
panduan kami tentang membuat modul library.
Kotlin
android { defaultConfig { consumerProguardFiles("consumer-proguard-rules.pro") } ... }
Groovy
android { defaultConfig { consumerProguardFiles 'consumer-proguard-rules.pro' } ... }
Library JAR
Untuk memaketkan aturan dengan library Kotlin/Java yang dikirim sebagai JAR, tempatkan
file aturan Anda di direktori META-INF/proguard/
JAR akhir, dengan nama file apa pun.
Misalnya, jika kode Anda berada di <libraryroot>/src/main/kotlin
, tempatkan file aturan konsumen
di
<libraryroot>/src/main/resources/META-INF/proguard/consumer-proguard-rules.pro
dan aturan akan dipaketkan di lokasi yang benar dalam JAR output Anda.
Pastikan JAR final memaketkan aturan dengan benar dengan memeriksa apakah aturan tersebut
ada di direktori META-INF/proguard
.
Mengoptimalkan build library AAR (lanjutan)
Secara umum, Anda tidak boleh mengoptimalkan build library secara langsung karena kemungkinan pengoptimalan pada waktu build library sangat terbatas. Hanya selama build aplikasi, saat library disertakan sebagai bagian dari aplikasi, R8 dapat mengetahui cara penggunaan semua metode library, dan parameter mana yang diteruskan. Sebagai developer library, Anda perlu memahami beberapa tahap pengoptimalan dan mempertahankan perilaku, baik pada waktu build library maupun aplikasi, sebelum mengoptimalkan library tersebut.
Jika Anda masih ingin mengoptimalkan library pada waktu build, hal ini didukung oleh Plugin Android Gradle.
Kotlin
android { buildTypes { release { isMinifyEnabled = true proguardFiles( getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" ) } configureEach { consumerProguardFiles("consumer-rules.pro") } } }
Groovy
android { buildTypes { release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } configureEach { consumerProguardFiles "consumer-rules.pro" } } }
Perhatikan bahwa perilaku proguardFiles
sangat berbeda dengan
consumerProguardFiles
:
proguardFiles
digunakan pada waktu build, sering kali bersama dengangetDefaultProguardFile("proguard-android-optimize.txt")
, untuk menentukan bagian library yang harus disimpan selama build library. Setidaknya, ini adalah API publik Anda.- Sebaliknya,
consumerProguardFiles
dikemas ke dalam library untuk memengaruhi pengoptimalan yang terjadi nanti, selama build aplikasi yang menggunakan library Anda.
Misalnya, jika library Anda menggunakan refleksi untuk membuat class internal, Anda
mungkin perlu menentukan aturan keep di proguardFiles
dan
consumerProguardFiles
.
Jika Anda menggunakan -repackageclasses
dalam build library, paketkan ulang
class ke sub-paket di dalam paket library Anda. Misalnya, gunakan
-repackageclasses 'com.example.mylibrary.internal'
, bukan
-repackageclasses 'internal'
.
Mendukung berbagai versi R8 (lanjutan)
Anda dapat menyesuaikan aturan untuk menargetkan versi R8 tertentu. Hal ini memungkinkan library Anda berfungsi secara optimal dalam project yang menggunakan versi R8 yang lebih baru, sekaligus memungkinkan aturan yang ada untuk terus digunakan dalam project dengan versi R8 yang lebih lama.
Untuk menentukan aturan R8 yang ditargetkan, Anda harus menyertakannya dalam
direktori META-INF/com.android.tools
di dalam classes.jar
AAR atau dalam
direktori META-INF/com.android.tools
JAR.
In an AAR library:
proguard.txt (legacy location, the file name must be "proguard.txt")
classes.jar
└── META-INF
└── com.android.tools (location of targeted R8 rules)
├── r8-from-<X>-upto-<Y>/<R8-rule-files>
└── ... (more directories with the same name format)
In a JAR library:
META-INF
├── proguard/<ProGuard-rule-files> (legacy location)
└── com.android.tools (location of targeted R8 rules)
├── r8-from-<X>-upto-<Y>/<R8-rule-files>
└── ... (more directories with the same name format)
Di direktori META-INF/com.android.tools
, dapat ada beberapa
subdirektori dengan nama dalam bentuk r8-from-<X>-upto-<Y>
untuk menunjukkan
versi R8 yang digunakan untuk menulis aturan. Setiap subdirektori dapat memiliki satu atau
beberapa file yang berisi aturan R8, dengan nama dan ekstensi file apa pun.
Perhatikan bahwa bagian -from-<X>
dan -upto-<Y>
bersifat opsional, versi <Y>
eksklusif, dan rentang versi biasanya berkelanjutan, tetapi juga dapat
tumpang-tindih.
Misalnya, r8
, r8-upto-8.0.0
, r8-from-8.0.0-upto-8.2.0
, dan
r8-from-8.2.0
adalah nama direktori yang mewakili kumpulan aturan R8 yang ditargetkan.
Aturan di direktori r8
dapat digunakan oleh versi R8 apa pun. Aturan
di direktori r8-from-8.0.0-upto-8.2.0
dapat digunakan oleh R8 dari versi
8.0.0 hingga, tetapi tidak termasuk versi 8.2.0.
Plugin Android Gradle menggunakan informasi tersebut untuk memilih semua aturan yang dapat
digunakan oleh versi R8 saat ini. Jika library tidak menentukan aturan R8
yang ditargetkan, plugin Android Gradle akan memilih aturan dari lokasi lama
(proguard.txt
untuk AAR atau META-INF/proguard/<ProGuard-rule-files>
untuk
JAR).