Skip to content

Most visited

Recently visited

navigation

Menciutkan Kode dan Sumber Daya Anda

Untuk membuat file APK sekecil mungkin, Anda harus mengaktifkan penciutan untuk membuang kode dan sumber daya yang tidak digunakan dalam versi rilis. Laman ini menjelaskan cara melakukannya dan bagaimana menentukan kode dan sumber daya yang dipertahankan atau dibuang selama melakukan build.

Penciutan kode tersedia bersama ProGuard, yang mendeteksi dan membuang kelas, bidang, metode, dan atribut yang tidak terpakai dari aplikasi terpaket, termasuk pustaka kode yang disertakan (menjadikannya sebuah alat yang berharga untuk bekerja dengan batas referensi 64k). ProGuard juga mengoptimalkan bytecode, membuang petunjuk kode yang tidak digunakan, dan menyamarkan kelas, bidang, dan metode lainnya dengan nama singkat. Kode yang disamarkan membuat APK sulit untuk direkayasa, yang terutama bermanfaat bila aplikasi Anda menggunakan fitur sensitif-keamanan, seperti verifikasi lisensi.

Penciutan sumber daya tersedia dengan Android Plugin for Gradle, yang membuang sumber daya tidak terpakai dari aplikasi terpaket, termasuk sumber daya yang tidak terpakai di pustaka kode. Itu bekerja bersamaan dengan penciutan kode sehingga setelah kode yang tidak terpakai dibuang, segala sumber daya yang tidak lagi dirujuk bisa dibuang secara aman.

Fitur dalam dokumen ini tergantung pada:

Menciutkan Kode Anda

Untuk mengaktifkan penciutan kode dengan ProGuard, tambahkan minifyEnabled true ke tipe versi yang sesuai dalam file build.gradle Anda.

Harap ketahui bahwa penciutan kode memperlambat waktu pembangunan, sehingga Anda harus menghindari penggunaannya pada versi debug jika memungkinkan. Namun, penting untuk diingat bahwa Anda harus mengaktifkan penciutan kode pada APK final yang digunakan untuk pengujian, karena itu mungkin memunculkan bug jika Anda tidak secara cukup menyesuaikan kode yang dipertahankan.

Misalnya, cuplikan file build.gradle berikut mengaktifkan penciutan kode untuk versi rilis:

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

Catatan: Android Studio menonaktifkan ProGuard saat menggunakan Instant Run. Jika Anda membutuhkan penciutan kode untuk pembangunan bertahap, cobalah shrinker eksperimental Gradle.

Selain properti minifyEnabled, properti proguardFiles mendefinisikan aturan ProGuard:

Untuk menambahkan lebih banyak aturan ProGuard yang dikhususkan bagi setiap varian versi, tambahkan properti proguardFiles lain di blok productFlavor yang sesuai. Misalnya, file Gradle berikut menambahkan flavor2-rules.pro ke ragam produk flavor2. Sekarang flavor2 menggunakan ketiga aturan ProGuard karena aturan yang berasal dari blok release juga diterapkan.

android {
    ...
    buildTypes {
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'),
                   'proguard-rules.pro'
        }
    }
    productFlavors {
        flavor1 {
        }
        flavor2 {
            proguardFile 'flavor2-rules.pro'
        }
    }
}

Dengan masing-masing pembangunan, ProGuard menghasilkan file-file berikut:

dump.txt
Menggambarkan struktur internal dari semua file kelas dalam APK.
mapping.txt
Menyediakan terjemahan di antara nama bidang, metode, serta kelas asli dan disamarkan.
seeds.txt
Mencantumkan daftar kelas dan anggota yang tidak disamarkan.
usage.txt
Mencantumkan daftar kode yang telah dibuang dari APK.

File-file ini disimpan di <module-name>/build/outputs/mapping/release/.

Menyesuaikan kode yang dipertahankan

Dalam beberapa situasi, file konfigurasi ProGuard default (proguard-android.txt) sudah mencukupi dan ProGuard akan membuang semua—dan hanya—kode yang tidak terpakai. Namun, banyak situasi yang sulit bagi ProGuard untuk menganalisis dengan benar dan ProGuard mungkin membuang kode yang sebenarnya dibutuhkan aplikasi Anda. Beberapa contoh ketika ProGuard mungkin salah membuang kode antara lain:

Pengujian aplikasi sebaiknya menunjukkan setiap kesalahan yang disebabkan oleh kode yang salah buang, namun Anda juga bisa memeriksa kode yang telah dibuang dengan meninjau keluaran file usage.txt yang disimpan di <module-name>/build/outputs/mapping/release/.

Untuk memperbaiki kesalahan dan memaksa ProGuard mempertahankan kode tertentu, tambahkan baris -keep di file konfigurasi ProGuard. Misalnya:

-keep public class MyClass

Atau, Anda bisa menambahkan anotasi @Keep ke kode yang ingin dipertahankan. Menambahkan @Keep pada kelas akan membuat seluruh kelas tetap seperti itu. Menambahkannya pada metode atau bidang akan menjaga metode/bidang (dan namanya) serta nama kelas tetap utuh. Perhatikan bahwa anotasi ini hanya tersedia bila menggunakan Annotations Support Library.

Ada banyak pertimbangan yang harus Anda buat saat menggunakan opsi -keep; untuk informasi selengkapnya tentang menyesuaikan file konfigurasi, bacalah ProGuard Manual. Bagian Pemecahan Masalah menjelaskan masalah umum lainnya yang mungkin Anda alami ketika kode Anda dilucuti.

Dekode pelacakan tumpukan yang disamarkan

Setelah ProGuard menciutkan kode Anda, membaca pelacakan tumpukan akan sulit (jika tidak mustahil) karena nama-nama metode sudah disamarkan. Untungnya, ProGuard membuat file mapping.txt setiap kali menjalankannya, yang menampilkan nama-nama kelas, metode, dan bidang asal yang dipetakan ke nama-nama yang disamarkan. ProGuard menyimpan file dalam direktori <module-name>/build/outputs/mapping/release/ aplikasi.

Ketahuilah bahwa file mapping.txt akan ditimpa setiap kali Anda membuat versi rilis dengan ProGuard, sehingga Anda harus berhati-hati menyimpan salinan setiap kali menerbitkan rilis baru. Dengan menyimpan salinan file mapping.txt untuk setiap versi rilis, Anda akan bisa men-debug masalah jika pengguna mengirimkan pelacakan tumpukan yang disamarkan dari versi aplikasi lama.

Saat mempublikasikan aplikasi pada Google Play, Anda bisa mengunggah file mapping.txt untuk setiap versi APK. Kemudian Google Play akan memperjelas pelacakan tumpukan yang masuk dari masalah yang dilaporkan pengguna sehingga Anda bisa memeriksanya di Google Play Developer Console. Untuk informasi selengkapnya, lihat artikel Pusat Bantuan tentang cara memperjelas pelacakan tumpukan mogok.

Untuk mengonversi sendiri pelacakan tumpukan tersamar agar bisa dibaca, gunakan skrip retrace (retrace.bat pada Windows; retrace.sh pada Mac/Linux). Lokasinya ada di direktori <sdk-root>/tools/proguard/. Skrip ini mengambil file mapping.txt dan pelacakan tumpukan Anda, yang menghasilkan pelacakan tumpukan baru yang bisa dibaca. Sintaks untuk menggunakan alat retrace adalah:

retrace.bat|retrace.sh [-verbose] mapping.txt [<stacktrace_file>]

Misalnya:

retrace.bat -verbose mapping.txt obfuscated_trace.txt

Jika Anda tidak menentukan file pelacakan tumpukan, alat retrace akan membaca dari input standar.

Mengaktifkan penciutan kode dengan Instant Run

Jika penciutan kode penting bagi Anda selagi membangun aplikasi secara bertahap, cobalah shrinker kode eksperimental yang disertakan dalam Android plugin for Gradle. Shrinker ini mendukung Instant Run, tidak seperti ProGuard.

Anda bisa mengonfigurasi shrinker plugin Android dengan menggunakan file konfigurasi yang sama seperti ProGuard. Akan tetapi, shrinker plugin Android tidak menyamarkan atau mengoptimalkan kode Anda—itu hanya membuang kode yang tidak terpakai. Jadi Anda sebaiknya hanya menggunakannya untuk versi debug, dan mengaktifkan ProGuard untuk versi rilis sehingga kode APK rilis Anda akan tersamar dan dioptimalkan.

Untuk mengaktifkan shrinker plugin Android, cukup setel useProguard ke false dalam tipe versi "debug" (dan setel minifyEnabled ke true):

android {
    buildTypes {
        debug {
            minifyEnabled true
            useProguard false
            proguardFiles getDefaultProguardFile('proguard-android.txt'),
                    'proguard-rules.pro'
        }
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'),
                    'proguard-rules.pro'
        }
    }
}

Catatan: Jika shrinker plugin Android mulanya membuang metode, namun kemudian Anda membuat perubahan kode untuk membuat metode itu bisa diakses, Instant Run akan memperlakukannya sebagai perubahan kode struktural dan melakukan cold swap.

Menciutkan Sumber Daya Anda

Penciutan sumber daya hanya bekerja bersamaan dengan penciutan kode. Setelah shrinker kode membuang semua kode yang tidak terpakai, shrinker sumber daya bisa mengidentifikasi sumber daya yang masih digunakan aplikasi. Hal ini terutama terjadi ketika Anda menambahkan pustaka kode yang berisi sumber daya—Anda harus membuang kode pustaka yang tidak terpakai sehingga sumber daya pustaka menjadi tidak dirujuk dan, dengan demikian, bisa dibuang oleh shrinker sumber daya.

Untuk mengaktifkan penciutan sumber daya, setel properti shrinkResources ke true dalam file build.gradle (di samping minifyEnabled untuk penciutan kode). Misalnya:

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

Jika Anda belum membangun aplikasi menggunakan minifyEnabled untuk penciutan kode, maka cobalah hal tersebut sebelum mengaktifkan shrinkResources, karena Anda mungkin perlu mengedit file proguard-rules.pro untuk mempertahankan kelas atau metode yang dibuat atau dipanggil secara dinamis sebelum mulai membuang sumber daya.

Catatan: Shrinker sumber daya saat ini tidak membuang sumber daya yang didefinisikan dalam folder values/ (misalnya string, dimensi, gaya, dan warna). Hal ini karena Android Asset Packaging Tool (AAPT) tidak mengizinkan Plugin Gradle untuk menentukan versi yang telah ditetapkan bagi sumber daya. Untuk detailnya, lihat masalah 70869.

Menyesuaikan sumber daya yang dipertahankan

Jika ada sumber daya tertentu yang ingin Anda simpan atau buang, buat file XML dalam proyek dengan tag <resources> dan tentukan setiap sumber daya yang ingin dipertahankan dalam atribut tools:keep dan setiap sumber daya yang ingin dibuang dalam atribut tools:discard. Kedua atribut menerima daftar nama sumber daya dengan dipisahkan koma. Anda bisa menggunakan karakter tanda bintang sebagai wild card.

Misalnya:

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"
    tools:keep="@layout/l_used*_c,@layout/l_used_a,@layout/l_used_b*"
    tools:discard="@layout/unused2" />

Simpan file ini di sumber daya proyek, misalnya, di res/raw/keep.xml. Pembangunan tidak memaket file ini ke dalam APK Anda.

Menentukan mana sumber daya yang dibuang mungkin tampak konyol ketika Anda sebenarnya bisa menghapusnya, namun ini akan berguna ketika menggunakan varian pembangunan. Misalnya, Anda mungkin menempatkan semua sumber daya ke direktori proyek biasa, kemudian membuat file keep.xml yang berbeda untuk setiap varian versi ketika Anda tahu bahwa sumber daya yang diberikan tampaknya digunakan dalam kode (dan karenanya tidak dibuang oleh shrinker) namun sebenarnya Anda tahu bahwa itu tidak akan digunakan untuk varian versi tersebut. Mungkin juga alat pembangunan salah mengidentifikasi sumber daya sebagai dibutuhkan, yang mungkin terjadi karena compiler menambahkan ID sumber daya berderet kemudian penganalisis sumber daya mungkin tidak tahu perbedaan antara sumber daya yang memang benar-benar direferensikan dan nilai integer dalam kode yang kebetulan sama nilainya.

Mengaktifkan pemeriksaan referensi yang ketat

Biasanya, shrinker sumber daya secara akurat bisa mengetahui saat sebuah sumber daya digunakan. Akan tetapi, jika kode Anda membuat panggilan ke Resources.getIdentifier() (atau jika salah satu pustaka melakukannya—pustaka AppCompat akan melakukannya), itu berarti kode Anda mencari nama sumber daya berdasarkan string yang dihasilkan secara dinamis. Ketika Anda melakukan hal ini, secara default shrinker sumber daya berperilaku defensif dan menandai semua sumber daya dengan format nama yang cocok sebagai berpotensi digunakan dan tidak boleh dihapus.

Misalnya, kode berikut menyebabkan semua sumber daya dengan awalan img_ akan ditandai sebagai digunakan.

String name = String.format("img_%1d", angle + 1);
res = getResources().getIdentifier(name, "drawable", getPackageName());

Shrinker sumber daya juga mencari melalui semua konstanta string dalam kode, serta beragam sumber daya res/raw/, mencari URL sumber daya dalam format yang sama dengan file:///android_res/drawable//ic_plus_anim_016.png. Jika itu menemukan string seperti ini atau string lain yang kelihatannya bisa digunakan untuk membangun URL seperti ini, itu tidak akan menghapusnya.

Berikut adalah contoh dari mode penciutan aman yang diaktifkan secara default. Namun, Anda bisa mematikan perlakuan "lebih baik aman daripada menyesal" ini, dan menetapkan bahwa shrinker sumber daya hanya menjaga sumber daya yang sudah pasti digunakan. Caranya, setel shrinkMode ke strict dalam file keep.xml, seperti berikut:

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"
    tools:shrinkMode="strict" />

Jika Anda mengaktifkan mode penciutan ketat dan kode Anda juga merujuk sumber daya dengan string yang dihasilkan secara dinamis, seperti yang ditampilkan di atas, maka Anda harus secara manual mempertahankan sumber daya menggunakan atribut tools:keep.

Membuang sumber daya alternatif yang tidak digunakan

Shrinker sumber daya Gradle hanya membuang sumber daya yang tidak dirujuk oleh kode aplikasi Anda, yang berarti itu tidak akan membuang sumber daya alternatif untuk konfigurasi perangkat yang berbeda. Jika perlu, Anda bisa menggunakan properti resConfigs plugin Gradle Android untuk membuang file sumber daya alternatif yang tidak diperlukan aplikasi.

Misalnya, jika Anda menggunakan pustaka yang berisi sumber daya bahasa (seperti Layanan Google Play atau AppCompat), maka APK memasukkan semua string bahasa yang diterjemahkan untuk pesan di pustaka tersebut, tidak peduli apakah bagian aplikasi yang lain diterjemahkan ke bahasa yang sama atau tidak. Jika hanya ingin mempertahankan bahasa yang didukung resmi oleh aplikasi, Anda bisa menetapkan bahasa tersebut menggunakan properti resConfig. Setiap sumber daya bahasa yang tidak ditetapkan akan dibuang.

Cuplikan berikut memperlihatkan cara membatasi sumber daya bahasa hanya ke bahasa Inggris dan Perancis:

android {
    defaultConfig {
        ...
        resConfigs "en", "fr"
    }
}

Demikian juga, Anda bisa menyesuaikan kepadatan layar atau sumber daya ABI yang akan dimasukkan ke dalam APK menggunakan APK splits untuk membuat APK berbeda untuk perangkat yang berbeda.

Menggabungkan sumber daya duplikat

Secara default, Gradle juga menggabungkan sumber daya bernama sama, seperti sumber daya dapat digambar dengan nama sama yang mungkin terletak dalam folder sumber daya yang berbeda. Perilaku ini tidak dikontrol oleh properti shrinkResources dan tidak bisa dinonaktifkan, karena diperlukan untuk mencegah kesalahan bila ada beberapa sumber daya yang cocok dengan nama kode yang Anda cari.

Penggabungan sumber daya hanya terjadi ketika dua file atau lebih berbagi nama, tipe, dan qualifier sumber daya yang serupa. Gradle memilih file yang dianggap sebagai pilihan terbaik di antara duplikasi tersebut (berdasarkan urutan prioritas yang dijelaskan di bawah) dan meneruskan hanya satu sumber daya ke AAPT untuk didistribusikan dalam file APK.

Gradle mencari sumber daya duplikasi di lokasi berikut:

Gradle menggabungkan sumber daya duplikasi dalam urutan prioritas berikut:

Dependencies → Main → Build flavor → Build type

Misalnya, jika sumber daya duplikasi muncul di sumber daya Main dan ragam versi, Gradle akan memilih yang berada di ragam versi.

Jika sumber identik muncul dalam set sumber yang sama, Gradle tidak bisa menggabungkan mereka dan mengeluarkan kesalahan penggabungan sumber daya. Hal ini bisa terjadi jika Anda mendefinisikan beberapa set sumber di properti sourceSet file build.gradle—misalnya jika src/main/res/ dan src/main/res2/ berisi sumber daya yang sama.

Memecahkan masalah penciutan sumber daya

Bila Anda menciutkan sumber daya, Gradle Console akan menampilkan ringkasan sumber daya yang dikeluarkan dari paket aplikasi. Misalnya:

:android:shrinkDebugResources
Removed unused resources: Binary resource data reduced from 2570KB to 1711KB: Removed 33%
:android:validateDebugSigning

Gradle juga membuat file diagnostik bernama resources.txt di <module-name>/build/outputs/mapping/release/ (folder yang sama dengan file keluaran ProGuard). File ini berisi rincian seperti sumber daya yang merujuk sumber daya lainnya dan sumber daya yang digunakan atau dibuang.

Misalnya, untuk mengetahui mengapa @drawable/ic_plus_anim_016 masih berada dalam APK, buka file resources.txt dan telusuri nama file tersebut. Anda mungkin mendapati bahwa itu dirujuk dari sumber daya lain, seperti berikut:

16:25:48.005 [QUIET] [system.out] @drawable/add_schedule_fab_icon_anim : reachable=true
16:25:48.009 [QUIET] [system.out]     @drawable/ic_plus_anim_016

Anda sekarang perlu mengetahui mengapa @drawable/add_schedule_fab_icon_anim bisa diakses—dan jika Anda menelusuri ke atas, Anda akan menemukan bahwa sumber daya tersebut dicantumkan pada "The root reachable resources are:". Ini berarti ada referensi kode ke add_schedule_fab_icon_anim (sehingga, R.drawable ID-nya ditemukan dalam kode yang bisa diakses).

Jika Anda tidak menggunakan pemeriksaan ketat, ID sumber daya bisa ditandai sebagai bisa diakses jika ada konstanta string yang terlihat seperti dapat digunakan untuk membuat nama sumber daya bagi sumber daya yang dimuat secara dinamis. Dalam hal ini, jika Anda mencari keluaran pembangunan untuk nama sumber daya, Anda mungkin menemukan pesan seperti ini:

10:32:50.590 [QUIET] [system.out] Marking drawable:ic_plus_anim_016:2130837506
    used because it format-string matches string pool constant ic_plus_anim_%1$d.

Jika Anda melihat salah satu string ini dan meyakini bahwa string tersebut tidak digunakan untuk memuat sumber daya yang diberikan secara dinamis, Anda bisa menggunakan atribut tools:discard untuk menginformasikan sistem pembangunan agar membuangnya, seperti yang dijelaskan di bagian tentang cara menyesuaikan sumber daya yang dipertahankan.

This site uses cookies to store your preferences for site-specific language and display options.

Get the latest Android developer news and tips that will help you find success on Google Play.

* Required Fields

Hooray!

Follow Google Developers on WeChat

Browse this site in ?

You requested a page in , but your language preference for this site is .

Would you like to change your language preference and browse this site in ? If you want to change your language preference later, use the language menu at the bottom of each page.

This class requires API level or higher

This doc is hidden because your selected API level for the documentation is . You can change the documentation API level with the selector above the left navigation.

For more information about specifying the API level your app requires, read Supporting Different Platform Versions.

Take a short survey?
Help us improve the Android developer experience.
(Sep 2017 survey)