Berita Produk

Mengonfigurasi dan memecahkan masalah Aturan Keep R8

Waktu baca: 7 menit

Dalam pengembangan Android modern, mengirimkan aplikasi yang kecil, cepat, dan aman adalah ekspektasi mendasar pengguna. Alat utama sistem build Android untuk mencapai hal ini adalah pengoptimal R8 , compiler yang menangani penghapusan kode dan resource yang tidak digunakan untuk penyingkatan, penggantian nama atau minifikasi kode, dan pengoptimalan aplikasi.

Mengaktifkan R8 adalah langkah penting dalam menyiapkan aplikasi untuk rilis, tetapi developer harus memberikan panduan dalam bentuk "Aturan Penyimpanan".

Setelah membaca artikel ini, tonton video Performance Spotlight Week tentang cara mengaktifkan, men-debug, dan memecahkan masalah pengoptimal R8 di YouTube.

 

 

Alasan Aturan Penyimpanan diperlukan

Kebutuhan untuk menulis Aturan Keep berasal dari konflik inti: R8 adalah alat analisis statis, tetapi aplikasi Android sering kali mengandalkan pola eksekusi dinamis seperti refleksi atau panggilan masuk dan keluar dari kode native menggunakan JNI (Java Native Interface).

R8 membuat grafik kode yang digunakan dengan menganalisis panggilan langsung. Jika kode diakses secara dinamis, analisis statis R8 tidak dapat memprediksinya dan akan mengidentifikasi kode tersebut sebagai tidak digunakan dan menghapusnya, sehingga menyebabkan error runtime.

 Aturan keep adalah petunjuk eksplisit untuk compiler R8, yang menyatakan: "Class, metode, atau kolom tertentu ini adalah titik entri yang akan diakses secara dinamis saat runtime. Anda harus menyimpannya, meskipun Anda tidak dapat menemukan referensi langsung ke dalamnya."

Lihat panduan resmi untuk mengetahui detail selengkapnya tentang Aturan Penyimpanan.

Tempat menulis Aturan Keep

Aturan Penyimpanan Kustom untuk aplikasi ditulis dalam file teks. Menurut konvensi, file ini diberi nama proguard-rules.pro dan terletak di root aplikasi atau modul library. File ini kemudian ditentukan dalam jenis build release file build.gradle.kts modul Anda.

  release {

    isShrinkResources = true

    isMinifyEnabled = true

    proguardFiles(

        getDefaultProguardFile("proguard-android-optimize.txt"),

        "proguard-rules.pro",

    )

}

Menggunakan file default yang benar

Metode getDefaultProguardFile mengimpor kumpulan aturan default yang disediakan oleh Android SDK. Jika menggunakan file yang salah, aplikasi Anda mungkin tidak dioptimalkan. Pastikan untuk menggunakan proguard-android-optimize.txt. File ini menyediakan Aturan Keep default untuk komponen Android standar dan memungkinkan pengoptimalan kode R8. proguard-android.txt yang sudah tidak berlaku hanya menyediakan Aturan Mempertahankan, tetapi tidak mengaktifkan pengoptimalan R8.

progaurd.png

Karena ini adalah masalah performa yang serius, kami mulai memperingatkan developer tentang penggunaan file yang salah, mulai dari Update Fitur Baru Android Studio Narwhal 3. Mulai dari Plugin Android Gradle Versi 9.0, kami tidak lagi mendukung file proguard-android.txt yang sudah usang. Jadi, pastikan Anda mengupgrade ke versi yang dioptimalkan.

Cara menulis Aturan Keep

Aturan penyimpanan terdiri dari tiga bagian utama:

  1. Opsi seperti -keep atau -keepclassmembers
  2. Pengubah opsional seperti allowshrinking
  3. Spesifikasi class yang menentukan kode yang akan dicocokkan

Untuk mengetahui sintaksis dan contoh lengkapnya, lihat panduan untuk menambahkan Aturan Penyimpanan.

Anti-pola Aturan penyimpanan

Penting untuk mengetahui praktik terbaik, tetapi juga anti-pola. Anti-pola ini sering kali muncul akibat kesalahpahaman atau jalan pintas pemecahan masalah dan dapat berdampak buruk pada performa build produksi.

Opsi global

Flag ini adalah tombol global yang tidak boleh digunakan dalam build rilis. Opsi ini hanya untuk proses debug sementara guna mengisolasi masalah.

Penggunaan -dontotptimize secara efektif menonaktifkan pengoptimalan performa R8 yang menyebabkan aplikasi menjadi lebih lambat.

Saat menggunakan -dontobfuscate, Anda menonaktifkan semua penggantian nama dan penggunaan -dontshrink akan menonaktifkan penghapusan kode tidak terpakai. Kedua aturan global ini meningkatkan ukuran aplikasi.

Hindari penggunaan tanda global ini di lingkungan produksi jika memungkinkan untuk pengalaman pengguna aplikasi yang berperforma lebih baik.

Aturan penyimpanan yang terlalu luas

Cara termudah untuk membatalkan manfaat R8 adalah dengan menulis Aturan Keep yang terlalu luas. Aturan keep seperti di bawah ini menginstruksikan pengoptimal R8 untuk tidak menyusutkan, tidak meng-obfuscate, dan tidak mengoptimalkan class apa pun dalam paket ini atau sub-paket apa pun. Tindakan ini akan sepenuhnya menghilangkan manfaat R8 untuk seluruh paket tersebut. Coba tulis Aturan Penyimpanan yang sempit dan spesifik.
 

  -keep class com.example.package.** { *;} // WIDE KEEP RULES CAUSE PROBLEMS

Operator inversi (!)

Operator inversi (!) tampaknya merupakan cara yang efektif untuk mengecualikan paket dari aturan. Namun, tidak sesederhana itu. Lihat contoh berikut:

  -keep class !com.example.my_package.** { *; } // USE WITH CAUTION

Anda mungkin berpikir bahwa aturan ini berarti "jangan pertahankan class dicom.example.package". Namun, sebenarnya aturan ini berarti "pertahankan setiap class, metode, dan properti di seluruh aplikasi yang tidak ada di com.example.package". Jika hal ini mengejutkan Anda, sebaiknya periksa negasi dalam konfigurasi R8 Anda.

Aturan berlebihan untuk komponen Android

Kesalahan umum lainnya adalah menambahkan Aturan Penyimpanan secara manual untuk ActivitiesServices, atau BroadcastReceivers aplikasi Anda. Hal ini tidak perlu. File proguard-android-optimize.txt default sudah menyertakan aturan yang relevan agar komponen Android standar ini dapat berfungsi langsung.

Selain itu, banyak library yang memiliki Aturan Penyimpanannya sendiri. Jadi, Anda tidak perlu menulis aturan sendiri untuk hal ini. Jika ada masalah dengan Aturan Penyimpanan dari library yang Anda gunakan, sebaiknya hubungi penulis library untuk mengetahui masalahnya.

Praktik terbaik Aturan Keep

Setelah mengetahui apa yang tidak boleh dilakukan, mari kita bahas praktik terbaik.

Menulis Aturan Keep yang spesifik

Aturan Penyimpanan yang baik harus sesempit dan sespesifik mungkin. Mereka hanya boleh mempertahankan apa yang diperlukan, sehingga R8 dapat mengoptimalkan semuanya.
 

RuleKualitas

 

-keep class com.example.** { ; }

 

Rendah: Mempertahankan seluruh paket dan subpaketnya

 

-keep class com.example.MyClass { ; }

 

Rendah: Mempertahankan seluruh class yang kemungkinan masih terlalu lebar
-keepclassmembers class com.example.MyClass {

    private java.lang.String secretMessage;

    public void onNativeEvent(java.lang.String);

}
Tinggi: Hanya metode dan properti yang relevan dari class tertentu yang dipertahankan

Menggunakan leluhur yang sama

Daripada menulis Aturan Penyimpanan terpisah untuk beberapa model data yang berbeda, tulis satu aturan yang menargetkan class dasar atau antarmuka umum. Aturan di bawah memberi tahu R8 untuk menyimpan anggota class yang menerapkan antarmuka ini dan sangat dapat diskalakan.

  # Keep all fields of any class that implements SerializableModel

-keepclassmembers class * implements com.example.models.SerializableModel {

    <fields>;

}

Menggunakan Anotasi untuk menargetkan beberapa kelas

Buat anotasi kustom (misalnya, @Serialize) dan gunakan untuk "menandai" class yang kolomnya perlu dipertahankan. Ini adalah pola lain yang bersih, deklaratif, dan sangat skalabel. Anda juga dapat membuat Aturan Keep untuk anotasi yang sudah ada dari framework yang Anda gunakan.

  # Keep all fields of any class annotated with @Serialize

-keepclassmembers class * {

    @com.example.annotations.Serialize <fields>;

}

Memilih Opsi Penyimpanan yang Tepat

Opsi Pertahankan adalah bagian terpenting dari aturan. Memilih yang salah dapat menonaktifkan pengoptimalan secara tidak perlu.

Opsi PertahankanFungsinya
-keepMencegah class dan anggota yang disebutkan dalam deklarasi dihapus atau diganti namanya.
-keepclassmembersMencegah anggota tertentu dihapus atau diganti namanya, tetapi mengizinkan class itu sendiri dihapus, tetapi hanya pada class yang tidak dihapus.
-keepclasseswithmembersKombinasi: Mempertahankan kelas dan anggotanya, hanya jika semua anggota yang ditentukan ada.

Anda dapat menemukan informasi selengkapnya tentang opsi keep di dokumentasi kami untuk Opsi Keep.

Mengizinkan pengoptimalan dengan Pengubah

Pengubah seperti allowshrinking dan allowobfuscation melonggarkan aturan -keep yang luas, sehingga memberikan kembali kemampuan pengoptimalan ke R8. Misalnya, jika library lama memaksa Anda menggunakan -keep pada seluruh class, Anda mungkin dapat mendapatkan kembali beberapa pengoptimalan dengan mengizinkan penyusutan dan pengaburan:

  # Keep this class, but allow R8 to remove it if it's unused and allow R8 to rename it.

-keep,allowshrinking,allowobfuscation class com.example.LegacyClass

Menambahkan opsi global untuk pengoptimalan tambahan

Selain Aturan Mempertahankan, Anda dapat menambahkan tanda global ke file konfigurasi R8 untuk mendorong pengoptimalan lebih lanjut.

-repackageclasses adalah opsi canggih yang menginstruksikan R8 untuk memindahkan semua class yang di-obfuscate ke dalam satu paket. Hal ini menghemat ruang yang signifikan dalam file DEX dengan menghapus string nama paket yang berlebihan.

-allowaccessmodification memungkinkan R8 memperluas akses (misalnya, private ke public) untuk mengaktifkan inlining yang lebih agresif. Sekarang, fitur ini diaktifkan secara default saat menggunakan proguard-android-optimize.txt.

Peringatan: Penulis library tidak boleh menambahkan tanda pengoptimalan global ini ke aturan konsumen mereka, karena tanda tersebut akan diterapkan secara paksa ke seluruh aplikasi.

Dan agar lebih jelas, di Android Gradle Plugin versi 9.0, kita akan mulai mengabaikan sepenuhnya flag pengoptimalan global dari library. 

Praktik terbaik untuk pustaka

Setiap aplikasi Android bergantung pada library dengan satu atau lain cara. Jadi, mari kita bahas praktik terbaik untuk pustaka.

Untuk developer library

Jika library Anda menggunakan refleksi atau JNI, Anda bertanggung jawab untuk memberikan Aturan Keep yang diperlukan kepada konsumennya. Aturan ini ditempatkan dalam file consumer-rules.pro, yang kemudian otomatis di-bundle dalam file AAR library.

  android {

    defaultConfig {

        consumerProguardFiles("consumer-rules.pro")

    }

    ...

}

Untuk konsumen library

Memfilter Aturan Keep yang bermasalah

Jika Anda harus menggunakan library yang menyertakan Aturan Keep yang bermasalah, Anda dapat memfilternya di file build.gradle.kts mulai dari AGP 9.0. Hal ini akan memberi tahu R8 untuk mengabaikan aturan yang berasal dari dependensi tertentu.

  release {

    optimization.keepRules {

        // Ignore all consumer rules from this specific library

        it.ignoreFrom("com.somelibrary:somelibrary")

    }

}

Aturan Penyimpanan Terbaik adalah tidak ada Aturan Penyimpanan

Strategi konfigurasi R8 terbaik adalah menghilangkan kebutuhan untuk menulis Aturan Keep sama sekali. Untuk banyak aplikasi, hal ini dapat dicapai dengan memilih library modern yang lebih mengutamakan pembuatan kode daripada refleksi. Dengan pembuatan kode, pengoptimal dapat lebih mudah menentukan kode apa yang sebenarnya digunakan saat runtime dan kode apa yang dapat dihapus. Selain itu, tidak menggunakan refleksi dinamis berarti tidak ada titik entri "tersembunyi", dan oleh karena itu, tidak ada Aturan Keep yang diperlukan. Saat memilih library baru, selalu pilih solusi yang menggunakan pembuatan kode daripada refleksi.

Untuk mengetahui informasi selengkapnya tentang cara memilih library, lihat memilih library dengan bijak.

Proses debug dan pemecahan masalah konfigurasi R8

Jika R8 menghapus kode yang seharusnya dipertahankan, atau APK Anda lebih besar dari yang diharapkan, gunakan alat ini untuk mendiagnosis masalah.

Menemukan Aturan Keep duplikat dan global

Karena R8 menggabungkan aturan dari puluhan sumber, sulit untuk mengetahui set aturan "final". Menambahkan tanda ini ke file proguard-rules.pro Anda akan menghasilkan laporan lengkap:

  # Outputs the final, merged set of rules to the specified file

-printconfiguration build/outputs/logs/configuration.txt

Anda dapat menelusuri file ini untuk menemukan aturan yang berlebihan atau melacak aturan yang bermasalah (seperti -dontoptimize) kembali ke library tertentu yang menyertakannya.

Pertanyaan R8: Mengapa Anda menyimpan ini?

Jika class yang Anda harapkan dihapus masih ada di aplikasi Anda, R8 dapat memberi tahu Anda alasannya. Cukup tambahkan aturan ini:

  # Asks R8 to explain why it's keeping a specific class

class com.example.MyUnusedClass

-whyareyoukeeping 

Selama build, R8 akan mencetak rantai referensi persis yang menyebabkannya mempertahankan class tersebut, sehingga Anda dapat melacak referensi dan menyesuaikan aturan.

Untuk panduan lengkapnya, lihat bagian memecahkan masalah R8.

Langkah berikutnya

R8 adalah alat canggih untuk meningkatkan performa aplikasi Android. Efektivitasnya bergantung pada pemahaman yang benar tentang pengoperasiannya sebagai mesin analisis statis.

Dengan menulis aturan khusus tingkat anggota, memanfaatkan ancestor dan anotasi, serta memilih opsi penyimpanan yang tepat dengan cermat, Anda dapat menyimpan persis apa yang diperlukan. Praktik yang paling canggih adalah menghilangkan kebutuhan akan aturan sepenuhnya dengan memilih library berbasis codegen modern daripada pendahulunya berbasis refleksi.

Saat Anda mengikuti Pekan Sorotan Performa, pastikan untuk menonton video Pekan Sorotan hari ini di YouTube dan lanjutkan dengan tantangan R8 kami. Gunakan #optimizationEnabled untuk pertanyaan apa pun tentang cara mengaktifkan atau memecahkan masalah R8. Kami siap membantu.

Sekarang saatnya Anda melihat sendiri manfaatnya.

Kami menantang Anda untuk mengaktifkan mode penuh R8 untuk aplikasi Anda hari ini.

  1. Ikuti panduan developer kami untuk memulai: Mengaktifkan pengoptimalan aplikasi.
  2. Periksa apakah Anda masih menggunakan proguard-android.txt dan ganti dengan proguard-android-optimize.txt.
  3. Kemudian, ukur dampaknya. Jangan hanya merasakan perbedaannya, verifikasi perbedaannya. Ukur peningkatan performa Anda dengan mengadaptasi kode dari aplikasi contoh Macrobenchmark kami di GitHub untuk mengukur waktu peluncuran Anda sebelum dan sesudah.

Kami yakin Anda akan melihat peningkatan yang berarti dalam performa aplikasi Anda.

Sambil melakukannya, gunakan tag sosial #AskAndroid untuk mengajukan pertanyaan Anda. Sepanjang minggu, pakar kami memantau dan menjawab pertanyaan Anda.

Nantikan besok, saat kita akan membahas Pengoptimalan yang Dipandu Profil dengan Profil Dasar Pengukuran dan Startup, membagikan cara peningkatan performa rendering Compose selama rilis sebelumnya, dan membagikan pertimbangan performa untuk tugas latar belakang.

Ditulis oleh:

Lanjutkan membaca