Bagaimana Berhenti Menjadi Takut pada Proguard dan Mulai Hidup


Halo, saya adalah pengembang Android dan saya tidak lagi takut pada ProGuard ...


Biasanya, utilitas ini diingat ketika dihadapkan dengan masalah dalvik dex-limit atau dengan persyaratan untuk meningkatkan keamanan aplikasi. Sayangnya, ini jauh dari pertama kali mengkonfigurasi Proguard dengan benar. Saya sering melihat berapa banyak, setelah memecahkan suatu proyek, mematikan Proguard dan menyalakan dukungan Mulditex, dan setiap kali saya sedikit sedih tentang hal itu, karena Proguard membantu mengurangi ukuran aplikasi dan meningkatkan kinerjanya.


Pada akhirnya, saya memutuskan untuk menulis artikel di mana saya dapat menaruh semua informasi berguna yang saya pelajari selama beberapa tahun bekerja dengan Proguard dan yang dapat membantu pemula dan mereka yang sudah mengetahui sesuatu.


Tentang apa ini?


Proguard adalah utilitas open-source untuk mengoptimalkan dan mengaburkan kode Java. Alat ini memproses kode Java yang sudah dikompilasi, sehingga harus bekerja dengan bahasa JVM apa pun. Lebih tepatnya, bahasa itu sendiri untuk Proguard tidak acuh, hanya bytecode yang penting. Semua manipulasi bytecode proguard dapat dibagi menjadi 3 kategori utama: Penyusutan kode , Optimasi, dan Kebingungan .


Kode menyusut


Ya, ini agak aneh untuk menulis kode dan kemudian menghapusnya, tetapi ini adalah realitas pengembangan Android. Ini, tentu saja, bukan tentang kode yang ditulis dengan tangan (walaupun ini terjadi), tetapi sekitar ton muatan mati yang dibawa oleh perpustakaan dari semua jenis. Guava , Apache Commons , Layanan Google Play dan orang lain dapat mengembang ukuran file apk dari 500kb menjadi beberapa puluh megabyte. Terkadang, program tidak bisa dikompilasi karena melebihi batas metode Dalvik . Proguard akan membantu menghapus semua kode yang tidak digunakan dan mengurangi ukuran aplikasi kembali menjadi beberapa megabyte.


Optimasi


Selain menghapus kode yang tidak perlu, Proguard dapat mengoptimalkan kode yang tersisa. Arsenalnya meliputi analisis aliran kontrol, analisis aliran data, evaluasi parsial, penugasan tunggal statis, penomoran nilai global, analisis livitas. Proguard dapat melakukan optimasi lubang intip, mengurangi jumlah alokasi variabel, menyederhanakan rekursi ekor dan banyak lagi ( wiki ). Selain operasi umum seperti itu, Proguard memiliki optimisasi yang berguna khusus untuk platform Android, misalnya, mengganti kelas enum dengan int, menghapus instruksi logging.


Kebingungan


Akhirnya, Proguard dapat mengubah semua kode Anda menjadi kekacauan yang tidak dapat dibaca dengan mengganti nama semua kelas, metode, dan bidang menjadi set huruf acak (sebenarnya tidak terlalu acak). Ini adalah opsi yang sangat berguna, karena siapa pun dapat mendekompilasi file apk Anda, dan tidak semua orang memiliki kesabaran untuk memahami kode yang dikaburkan.


Prinsip kerja


Proguard bekerja dalam 3 langkah dalam urutan yang dijelaskan di atas: kode menyusutoptimisasikebingungan . Setiap langkah bersifat opsional.


Langkah Pengoptimalan dalam kasus Android SDK dimatikan secara default.


Agar Proguard berfungsi, Anda perlu menyediakan 3 komponen:


  • Kode kompilasi Anda adalah arsip dengan file class program Anda dan semua perpustakaan yang Anda gunakan (jar, aar, apk, war, zip, dll.). Proguard hanya memodifikasi kode yang sudah dikompilasi dan tidak ada hubungannya dengan sumbernya.
  • File konfigurasi - file yang berisi semua aturan, opsi, dan pengaturan yang Anda inginkan untuk memulai pemrosesan.
  • Guci perpustakaan (aar, apks, ...) - kelas platform tempat program Anda berjalan. Dalam kasus Android, ini adalah android.jar . Arsip ini diperlukan hanya untuk analisis kode Anda yang benar, mereka tidak akan diubah (ini tidak masuk akal, karena android.jar adalah "di telepon", kami tidak memiliki akses ke sana).

Gambar dari presentasi Jeb Ware, tautan di akhir artikel
(Gambar dari presentasi Jeb Ware, tautan di akhir artikel)


Menggunakan kelas pustaka dan file konfigurasi Anda, Proguard mendefinisikan semua titik masuk ke program Anda ( seed ). Dengan kata lain, ini mendefinisikan kelas dan metode yang dapat dipanggil dari luar dan yang tidak dapat disentuh. Kemudian, dimulai dengan benih yang ditemukan, Proguard secara rekursif menelusuri semua kode Anda, menandai "menggunakan" segala sesuatu yang dapat dijangkau. Semua kode lain akan dihapus. Anda harus menentukan setidaknya satu titik masuk dalam konfigurasi. Untuk program java standar, ini adalah fungsi main . Di Android, tidak ada titik masuk tunggal ke dalam program, sebaliknya, kami memiliki komponen standar (Aktivitas, Layanan, dll.) Yang dibuat dan dipanggil oleh sistem. Untungnya, kita tidak perlu menentukan apa pun di sini sendiri, Android SDK akan membuat konfigurasi yang diperlukan untuk kita.


File pendamping


Setelah mendeteksi semua titik masuk, Proguard akan menuliskannya ke file seeds.txt .


Semua kode yang ditemukan Proguard tidak perlu ditulis ke file usage.txt . Ini adalah nama yang agak aneh untuk file yang berisi kode jarak jauh, akan lebih tepat untuk memanggilnya dengan unage.txt, tetapi kita memiliki apa yang kita miliki, ingat saja itu.


Pada langkah kebingungan, file mapping.txt akan dibuat berisi pasangan <nama kelas asli | metode | bidang> -> <nama kelas kabur | metode | bidang>. File ini berguna ketika Anda perlu menghapus program, misalnya, membaca stacktrace. Memetakan kembali file secara manual tidak diperlukan, Android SDK memiliki utilitas retrace dan proguardui untuk membantu. Selain itu, jika Anda menggunakan Fabric Crashlytics, maka plugin gradle mereka dapat menemukan dan memuat file ini secara mandiri ke konsol, sehingga Anda tidak perlu khawatir tentang hal itu.


Dalam kasus Android, file-file ini biasanya terletak di app/build/output/mapping/<product-flavor-name>/ .


Proguard juga membuat file dump.txt yang berisi semua yang dimasukkan Proguard ke arsip terakhir. Dia tidak pernah berguna bagi saya, tetapi mungkin itu akan berguna bagi seseorang.


Bagaimana kabar Android?


Plugin Android Gradle dapat menjalankan Proguard sendiri. Yang harus Anda lakukan adalah mengaktifkan opsi ini dan menentukan file konfigurasi.


 buildTypes { <...> release { minifyEnabled true proguardFiles 'proguard-rules.pro', getDefaultProguardFile('proguard-android.txt') } } 

minifyEnabled true - aktifkan Proguard pada waktu build


proguardFiles - daftar file konfigurasi. Aturan dari semua file konfigurasi akan ditambahkan ke daftar umum sesuai dengan urutannya.


proguard-rules.pro adalah file konfigurasi kami dengan aturan spesifik proyek


getDefaultProguardFile('proguard-android.txt') - fungsi yang mengembalikan file konfigurasi standar untuk aplikasi Android. Itu terletak di AndroidSDK/tools/proguard


Faktanya, Android SDK memiliki dua proguard-android.txt : proguard-android.txt dan proguard-android-optimize.txt . Yang pertama memiliki opsi -dontoptimize , yang mematikan semua optimisasi. Jika Anda ingin mengaktifkan pengoptimalan, gunakan konfigurasi kedua.


Selain konfigurasi standar ini, Android SDK (aapt) secara otomatis menghasilkan seperangkat aturan untuk sumber daya: aapt memeriksa semua file xml (termasuk manifes) untuk menemukan semua aktivitas, layanan, tampilan, dll. dan menghasilkan aturan yang diperlukan untuk mereka. Aturan yang dihasilkan dapat ditemukan di app/build/intermediates/proguard-rules/<flavor>/aapt_rules.txt . Anda tidak perlu menentukannya sendiri, Plugin Android Gradle akan menambahkan aturan ini secara otomatis.


Gambar dari presentasi Jeb Ware, tautan di akhir artikel
(Gambar dari presentasi Jeb Ware, tautan di akhir artikel)


Konfigurasi


Menyiapkan Proguard adalah bagian paling mendasar dari bekerja dengannya dan pada saat yang sama paling sulit. Konfigurasi yang salah dapat dengan mudah memutus kompilasi aplikasi dan aplikasi itu sendiri saat runtime. Semua opsi konfigurasi yang tersedia didokumentasikan secara detail tidak aktif. situs


Di antara semua opsi, saya akan memilih 3 grup paling penting:


  • menjaga aturan - Semua titik masuk yang memungkinkan ke program. Aturan memberi tahu Proguard kelas atau bagian mana dari kelas yang tidak berubah atau yang mana dari modifikasi yang valid untuk kelas tertentu.
  • penyetelan pengoptimalan - menunjukkan pengoptimalan mana yang dapat diterima, berapa banyak siklus pengoptimalan yang perlu dilakukan.
  • bekerja dengan peringatan, kesalahan, dan debugging

Patuhi aturan


Ini adalah serangkaian opsi yang dirancang untuk melindungi kode Anda dari Proguard yang kejam. Dalam bentuknya yang paling umum, aturan ini terlihat seperti ini:


 -keep [,modifier,...] class_specification 

keep adalah yang paling umum dari opsi-opsi ini (ada yang lain), memberi tahu Proguard untuk menyelamatkan kelas itu sendiri dan semua anggota kelasnya: bidang dan metode.


class_specification - templat yang menunjuk ke kelas atau bagiannya (anggota kelas). Tampilan umum template sangat besar, dapat dilihat . dokumentasi . Anda dapat menghubunginya, tetapi secara umum, Anda dapat mengingat bahwa kami memiliki kesempatan untuk membuat templat komponen ini:


  • pilih semua kelas dengan nama, paket tertentu
  • pilih semua kelas yang mewarisi / mengimplementasikan kelas / antarmuka tertentu
  • pilih semua kelas dengan pengubah spesifik dan / atau anotasi khusus
  • pilih semua metode dengan nama tertentu, pengubah, argumen dan nilai balik
  • pilih semua bidang dengan nama tertentu, pengubah, dari jenis tertentu.
  • dimungkinkan untuk menggunakan wildcard


    Sekali lagi, ini bukan deskripsi ketat dari template, melainkan daftar fitur yang kami miliki. Berikut ini beberapa contoh:



-keep public class com.example.MyActivity
simpan kelas com.example.MyActivity


-keep public class * extends android.app.Activity
simpan semua kelas publik yang mewarisi android.app.Activity


 -keep public class * extends android.view.View { public <init>(android.content.Context); public <init>(android.content.Context, android.util.AttributeSet); public <init>(android.content.Context, android.util.AttributeSet, int); public void set*(...); } 

temukan semua kelas publik yang mewarisi android.view.View dan simpan 3 konstruktor dengan parameter tertentu di dalamnya + semua metode publik, dengan pengubah void , argumen apa pun, dan nama yang dimulai dengan set . Semua bagian lain dari kelas dapat dimodifikasi.


-keep class com.habr.** { *; }
simpan semua kelas dan semua isinya dalam paket com.habr


modifiers - tambahan untuk keep-rule:


  • includedescriptorclasses - di samping kelas / metode / bidang yang ditentukan, Anda harus menyimpan semua kelas yang terjadi di deskriptornya.
  • includecode - isi metode yang ditunjukkan oleh aturan khusus ini tidak dapat disentuh juga.
  • allowshrinking - kelas yang ditunjuk oleh aturan ini bukan seed dan dapat dihapus, tetapi hanya jika mereka tidak digunakan dalam program itu sendiri. Namun, jika setelah kode-menyusutkan kode ini tetap (karena fakta bahwa seseorang menggunakannya), tidak mungkin untuk mengoptimalkan / mengaburkan kode ini.
  • allowoptimization - kelas yang dirujuk oleh aturan ini hanya dapat dioptimalkan, tetapi tidak dapat dihapus atau dikaburkan.
  • allowobfuscation - kelas yang ditunjukkan oleh aturan ini hanya dapat dikaburkan, tetapi tidak dapat dihapus atau dioptimalkan.

Selain keep , ada beberapa opsi lagi:


-keepclassmembers - menunjukkan bahwa anggota kelas harus disimpan jika kelas itu sendiri dipertahankan setelah kode menyusut.


-keepclasseswithmembers - menunjukkan bahwa Anda ingin menyimpan kelas yang isinya termasuk dalam templat yang ditentukan. Sebagai contoh, -keepclasseswithmembers class * { public <init>(android.content.Context); } -keepclasseswithmembers class * { public <init>(android.content.Context); } - menyimpan semua kelas yang memiliki konstruktor publik dengan satu argumen tipe Context .


-keepnames - kependekan -keep,allowshrinking untuk -keep,allowshrinking .


-keepclassmembernames - singkatan untuk -keepclassmembers,allowshrinking .


keepclasseswithmembernames - kependekan -keepclasseswithmembers,allowshrinking .


Penyempurnaan optimasi


Opsi paling penting di sini adalah flag -dontoptimize . Jika ada, tidak ada optimasi yang akan dilakukan dan semua opsi optimasi lainnya akan diabaikan.


Ada banyak opsi pengoptimalan, tetapi yang berikut paling berguna bagi saya:


-optimizations optimization_filter - mendaftar semua cara yang ingin Anda gunakan. Lebih baik menggunakan set yang ditentukan di proguard-android-optimize.txt atau bagian dari itu. Daftar semua optimasi dapat ditemukan di sini .


-optimizationpasses n - jumlah siklus optimisasi. Beberapa siklus dapat meningkatkan hasilnya. Pada saat yang sama, Proguard cukup pintar untuk menghentikan siklus jika melihat bahwa hasilnya belum membaik dari waktu terakhir.


-assumenosideeffects class_specification - menunjukkan bahwa metode ini tidak memiliki efek samping dan hanya mengembalikan beberapa nilai. Proguard akan menghapus panggilan ke metode ini jika mendeteksi bahwa hasilnya tidak digunakan. Mungkin penggunaan yang paling umum dari opsi ini adalah untuk menghapus semua log debug: -assumenosideeffects class android.util.Log { public static int d(...); } -assumenosideeffects class android.util.Log { public static int d(...); }


-allowaccessmodification - tampilkan segala sesuatu yang disembunyikan :) Pilihan hebat yang memungkinkan Anda untuk menyingkirkan sekelompok metode -allowaccessmodification buatan untuk kelas bersarang. Hanya bekerja bersamaan dengan -repackageclasses


-repackageclasses - -repackageclasses untuk memindahkan semua kelas ke satu paket yang ditentukan. Ini berlaku lebih untuk kebingungan, tetapi pada saat yang sama, memberikan hasil yang baik dalam pengoptimalan.


Opsi lain yang bermanfaat


-dontwarn dan -dontnote


Proguard sangat cerdas dan selalu melaporkan tempat mencurigakan selama analisis kode, terkadang ini adalah catatan, terkadang peringatan. Jika build Anda tidak berjalan dengan Proguard dihidupkan, pastikan untuk membaca semua log yang dihasilkannya, itu akan menulis apa yang salah dan, kemungkinan besar, bahkan memberi tahu Anda cara memperbaikinya. Setelah membaca semua pesan, Anda dapat memperbaiki masalah atau mengabaikan pesan dari salah satu opsi ini jika Anda yakin tidak ada masalah.


Misalnya, beberapa perpustakaan java menggunakan kelas platform yang tidak ada di android.jar dan Proguard akan memperingatkan tentang hal ini. Jika Anda yakin bahwa pustaka ini berfungsi dengan baik di lingkungan Android, Anda dapat mematikan peringatan ini - -dontwarn java.lang.management.**


-whyareyoukeeping class_specification adalah opsi yang berguna yang akan mencetak alasan mengapa Proguard memutuskan untuk tidak menyentuh kelas / metode ini.


-verbose - mencetak log dan pengecualian yang lebih rinci


-printconfiguration - mencetak daftar opsi lengkap dari semua file konfigurasi yang digunakan, termasuk aturan dari pustaka dan dihasilkan melalui aapt.


-keepattributes SourceFile, LineNumberTable - menyimpan meta-informasi (nama file, penomoran baris) untuk dapat men-debug kode dalam IDE dan mendapatkan stacktrace yang bermakna. Pastikan untuk menambahkan opsi ini.


Berlatih


Ini biasanya terjadi: nyalakan Proguard dan itu menghancurkan Anda seluruh proyek memberikan banyak kesalahan. Banyak di langkah ini mematikan Proguard dan mencoba untuk tidak kembali ke sana. Saya akan mencoba memberikan beberapa tips untuk membuat proses transisi ini lebih mudah.


Tentukan titik masuk awal


Jika Anda seorang pengembang Android, semuanya sangat sederhana - cukup pilih salah satu dari dua konfigurasi standar dari Android SDK: proguard-android.txt atau proguard-android-optimize.txt , mereka akan mengurus semua yang harus tetap tidak tersentuh.


Periksa semua perpustakaan


Baru-baru ini, semakin banyak perpustakaan didistribusikan dengan proguard-konfigurasi yang sudah jadi. Proguard dapat melihat ke dalam arsip, menemukan konfigurasi perpustakaan dan menambahkannya ke opsi lain. Periksa setiap perpustakaan yang Anda gunakan untuk konfigurasi seperti itu.


(isi file aar dari salah satu perpustakaan)
(isi file aar dari salah satu perpustakaan)


Jika Anda menggunakan Google Play Services, maka plugin com.google.gms.google-services akan memilih konfigurasi yang Anda butuhkan sendiri.


Jika penulis perpustakaan tidak mengemas konfigurasi ke dalam arsip, mungkin mereka berhati-hati dan menulis aturan di situs web mereka, di halaman repositori atau di file README. Coba cari sendiri konfigurasi untuk versi perpustakaan yang Anda gunakan.


Jika Anda tidak dapat menemukan aturan siap pakai di mana saja, Anda harus membaca log dan menyelesaikan masalah secara individual. Kemungkinan besar, Anda perlu menambahkan aturan tetap untuk kode perpustakaan yang rusak. Atau abaikan kesalahan jika tidak mengganggu program.


Periksa kode Anda


Anda lebih tahu kode apa yang dapat Anda kirim di bawah pisau, tetapi Anda harus hati-hati melihat semua tempat di mana refleksi digunakan:


  • Class.forName (...) (dokumentasi menjanjikan bahwa Proguard dapat mendefinisikan kode tersebut, namun, ada beberapa kasus, perlu diperiksa)
  • Model / entitas-kelas yang digunakan dalam serialisasi, pemetaan. Semua kelas yang nama bidangnya (kadang-kadang kelas itu sendiri) penting untuk disimpan (Gson, RealmIO, dll.)
  • panggilan perpustakaan asli melalui JNI

Tes


Jika kelas / metode hanya digunakan dalam tes dan tempat lain, Proguard akan menghapus kode ini. Ini adalah situasi umum jika Anda memiliki TDD :) Untuk kasus ini, saya memiliki konfigurasi terpisah, di mana saya menambahkan kelas-kelas yang belum terintegrasi ke dalam proyek, tidak digunakan di mana pun, tetapi yang perlu diuji.


Di Android Gradle Plugin, selain instruksi proguardFiles , masih ada testProguardFiles . Instruksi ini diperlukan untuk menentukan konfigurasi yang akan diterapkan pada aplikasi pengujian yang dihasilkan untuk menguji aplikasi Anda saat Anda menjalankan tes instrumentasi. Biasanya ini digunakan untuk mencapai optimasi / kebingungan yang sama di kedua file apk sehingga tidak ada desync di antara mereka. Tautan


Penganalisa APK


Android Studio memiliki alat yang luar biasa. Anda dapat membukanya melalui Temukan Tindakan -> Analisis APK, atau dengan membuka file apk itu sendiri di Android Studio. Analyzer menunjukkan banyak informasi berguna, tetapi sekarang kami tertarik pada kodenya. Untuk melihat apa yang akhirnya dikemas ke dalam file APK, Anda harus memilih file classes.dex



Secara default, Anda akan ditunjukkan persis kode yang dihasilkan yang telah melewati langkah penyusutan dan optimisasi. Namun, Anda dapat mengklik tombol Load Proguard mapping ... , tambah seeds.txt dan usage.txt untuk melihat kode yang telah dihapus.



Jika Proguard karena suatu alasan memodifikasi kode yang Anda butuhkan, temukan di Analyzer dan pilih Generate Proguard Keep Rule melalui RMB. Analyzer akan menghasilkan pilihan beberapa opsi untuk aturan, dari yang paling umum ke yang paling spesifik, pilih SATU dari mereka.




Untuk penulis perpustakaan


Jika Anda membuat pustaka Android, Anda dapat menambahkan konfigurasi proguard untuk klien Anda sebagai berikut:


 buildTypes { release { consumerProguardFiles 'proguard-rules.pro' } } 

Menurut pendapat saya, lebih baik untuk tidak mengoptimalkan dan mengaburkan perpustakaan Anda, tetapi untuk memberikan kesempatan ini kepada pelanggan Anda. Nada yang baik adalah menambahkan ke config apa yang masih harus ditambahkan oleh pelanggan jika mereka menyertakan Proguard. Namun, jika Anda masih ingin menambahkan keamanan, jelas bahwa Anda perlu melindungi seluruh API pulic perpustakaan Anda dari Proguard, termasuk deskriptor dan tanda tangan.


R8, DexGuard dan Redex


R8 adalah alat baru Google untuk menggantikan Proguard saat ini. Tunggu, jangan mencoba melupakan semua yang baru saja Anda baca di artikel, perlakukan saja seperti Proguard baru. Google berjanji untuk menjaga seluruh api publik, sehingga semua konfigurasi akan berfungsi seperti sebelumnya. Proyek ini masih dalam versi beta, tetapi Anda dapat mencobanya sendiri.


DexGuard adalah utilitas berbayar dari pengembang Proguard. Itu bisa digunakan bersama atau sebagai ganti Proguard. Dikatakan bahwa DexGuard dapat melakukan semua yang dapat dilakukan Proguard, tetapi lebih baik. Sayangnya, saya tidak punya kesempatan untuk mencobanya, jika ada yang punya pengalaman, silakan bagikan.


Redex adalah pengoptimal dex lain dari Facebook. Dilaporkan bahwa dengan itu Anda dapat mencapai peningkatan produktivitas hingga 25% dan mengurangi ukuran aplikasi dengan menerapkan alat ke kode yang sudah diproses oleh Proguard.


Alih-alih sebuah kesimpulan


Jangan takut menggunakan Proguard, jangan malas dan luangkan waktu untuk menyiapkan. Ini akan mengurangi ukurannya, meningkatkan kecepatan kerja, daripada menambah loyalitas pengguna Anda. Pada saat yang sama, cobalah untuk membuat konfigurasi Proguard yang efektif, jangan menulis aturan "karpet", jika tidak, Jake Wharton yang marah akan mendatangi Anda dan memarahi Anda.



Sumber daya


Situs web proguard . Ada juga informasi tentang DexGuard.
Berbagai contoh aturan
R8
Merekam presentasi tentang Bagaimana Proguard Bekerja dengan DroidCon
ProGuard menjaga aturan untuk aplikasi yang lebih kecil (Google I / O '18) rekaman presentasi
Petunjuk untuk mengaktifkan dan mengonfigurasi Proguard untuk Android
Halaman Wiki
Redex

Source: https://habr.com/ru/post/id415499/


All Articles