Sebagai penulis library, Anda harus memastikan bahwa developer aplikasi dapat dengan mudah menggabungkan 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 penggunaan di Android.
Dokumentasi ini ditujukan bagi developer library yang dipublikasikan, tetapi mungkin juga berguna bagi developer modul library internal dalam aplikasi modular yang besar.
Jika Anda adalah developer aplikasi dan ingin mempelajari cara mengoptimalkan aplikasi Android Anda, lihat Mengaktifkan pengoptimalan aplikasi. Untuk mempelajari library mana yang tepat 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 dimodifikasi 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 diselesaikan hingga dieksekusi, pengoptimal tidak tahu kode mana yang dapat dihapus dengan aman. Hal ini kemungkinan akan menghapus kode yang digunakan secara dinamis melalui refleksi selama runtime, yang menyebabkan aplikasi error bagi pengguna.
Banyak library modern menggunakan codegen, bukan refleksi. Lihat KSP untuk titik entri umum, yang digunakan oleh Room, Dagger2, dan banyak lagi.
Jika refleksi tidak masalah
Jika Anda harus menggunakan refleksi, Anda hanya boleh merefleksikan salah satu dari berikut:
- Jenis yang ditargetkan tertentu (subkelas atau penerap antarmuka tertentu)
- Kode menggunakan anotasi runtime tertentu
Penggunaan refleksi dengan cara ini membatasi biaya runtime, dan memungkinkan penulisan aturan penyimpanan konsumen yang ditargetkan.
Bentuk refleksi yang spesifik dan bertarget ini adalah pola yang dapat Anda lihat di seluruh
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.
Jenis aturan penyimpanan di perpustakaan
Ada dua jenis aturan penyimpanan berbeda yang dapat Anda miliki di pustaka:
- Aturan penyimpanan konsumen harus menentukan aturan yang menyimpan apa pun yang tercermin di library. Jika library menggunakan refleksi atau JNI untuk memanggil kodenya, atau
kode yang ditentukan oleh aplikasi klien, aturan ini harus menjelaskan kode apa yang perlu
dipertahankan. Library harus mengemas aturan keep konsumen, yang menggunakan format yang sama dengan aturan keep aplikasi. Aturan ini dibundel ke dalam artefak library
(AAR atau JAR) dan digunakan secara otomatis selama pengoptimalan aplikasi Android saat library digunakan. Aturan ini dikelola dalam
file yang ditentukan dengan properti
consumerProguardFiles
di filebuild.gradle.kts
(ataubuild.gradle
). Untuk mempelajari lebih lanjut, lihat Menulis aturan penyimpanan konsumen. - Aturan penyimpanan build library diterapkan saat library Anda dibangun. File ini hanya diperlukan jika Anda memutuskan untuk mengoptimalkan library sebagian pada waktu build.
Mereka harus mencegah penghapusan API publik library, jika tidak, API publik tidak akan ada dalam distribusi library, yang berarti developer aplikasi tidak dapat menggunakan library. Aturan ini dikelola dalam file yang ditentukan dengan properti
proguardFiles
di filebuild.gradle.kts
(ataubuild.gradle
) Anda. Untuk mempelajari lebih lanjut, lihat Mengoptimalkan build library AAR.
Menulis aturan penyimpanan konsumen
Selain panduan aturan penyimpanan umum, berikut adalah rekomendasi khusus untuk penulis library.
- Jangan gunakan aturan global yang tidak tepat—hindari menempatkan setelan global seperti
-dontobfuscate
atau-allowaccessmodification
dalam file aturan penyimpanan konsumen library Anda, karena setelan tersebut memengaruhi semua aplikasi yang menggunakan library Anda. - Jangan gunakan
-repackageclasses
dalam file aturan penyimpanan konsumen library Anda. Namun, untuk mengoptimalkan build library, Anda dapat menggunakan-repackageclasses
dengan nama paket internal, seperti<your.library.package>.internal
, di file aturan penyimpanan build library Anda. Hal ini dapat membuat library Anda lebih efisien meskipun aplikasi yang menggunakannya tidak dioptimalkan, tetapi umumnya tidak diperlukan karena aplikasi juga harus dioptimalkan. Untuk mengetahui detail selengkapnya tentang pengoptimalan library, lihat Pengoptimalan untuk penulis library. - Deklarasikan atribut apa pun yang Anda butuhkan agar library Anda berfungsi dalam file aturan keep library Anda, meskipun mungkin ada tumpang-tindih dengan atribut yang ditentukan dalam
proguard-android-optimize.txt
. - Jika Anda memerlukan atribut berikut dalam distribusi library, pertahankan atribut tersebut dalam file aturan penyimpanan build library Anda, dan bukan dalam file aturan penyimpanan konsumen library Anda:
AnnotationDefault
EnclosingMethod
Exceptions
InnerClasses
RuntimeInvisibleAnnotations
RuntimeInvisibleParameterAnnotations
RuntimeInvisibleTypeAnnotations
RuntimeVisibleAnnotations
RuntimeVisibleParameterAnnotations
RuntimeVisibleTypeAnnotations
Signature
- Penulis library harus menyimpan atribut
RuntimeVisibleAnnotations
dalam aturan penyimpanan konsumen jika anotasi digunakan saat runtime. - Penulis library tidak boleh menggunakan opsi global berikut dalam aturan penyimpanan konsumen:
-include
-basedirectory
-injars
-outjars
-libraryjars
-repackageclasses
-flattenpackagehierarchy
-allowaccessmodification
-overloadaggressively
-renamesourcefileattribute
-ignorewarnings
-addconfigurationdebugging
-printconfiguration
-printmapping
-printusage
-printseeds
-applymapping
-obfuscationdictionary
-classobfuscationdictionary
-packageobfuscationdictionary
Library AAR
Untuk menambahkan aturan konsumen bagi library AAR, gunakan opsi consumerProguardFiles
dalam skrip build modul library Android. Untuk mengetahui informasi selengkapnya, lihat
panduan kami tentang cara 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, letakkan file aturan Anda di direktori META-INF/proguard/
JAR akhir, dengan nama file apa pun.
Misalnya, jika kode Anda ada di <libraryroot>/src/main/kotlin
, letakkan file aturan konsumen di
<libraryroot>/src/main/resources/META-INF/proguard/consumer-proguard-rules.pro
dan aturan akan dibundel di lokasi yang benar dalam JAR output Anda.
Verifikasi bahwa JAR akhir mengelompokkan aturan dengan benar dengan memeriksa bahwa aturan tersebut ada di direktori META-INF/proguard
.
Mengoptimalkan build library AAR (lanjutan)
Umumnya, Anda tidak perlu 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 semua metode library digunakan, dan parameter mana yang diteruskan. Sebagai developer library, Anda perlu mempertimbangkan beberapa tahap pengoptimalan dan mempertahankan perilaku, baik pada waktu build library maupun aplikasi, sebelum Anda mengoptimalkan library tersebut.
Jika Anda masih ingin mengoptimalkan library pada waktu build, hal ini didukung oleh Android Gradle Plugin.
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 mana dari library Anda yang harus dipertahankan selama build library. Setidaknya, ini adalah API publik Anda.consumerProguardFiles
sebaliknya dikemas ke dalam library untuk memengaruhi pengoptimalan yang terjadi kemudian, 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, kemas 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 terus digunakan dalam project dengan versi R8 yang lebih lama.
Untuk menentukan aturan R8 yang ditargetkan, Anda harus menyertakannya di direktori
META-INF/com.android.tools
dalam classes.jar
AAR atau di 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
, 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>
bersifat
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 merepresentasikan sekumpulan aturan R8 yang ditargetkan. Aturan di direktori r8
dapat digunakan oleh semua versi R8. Aturan dalam direktori r8-from-8.0.0-upto-8.2.0
dapat digunakan oleh R8 dari versi 8.0.0 hingga 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).