Pengembangan iteratif yang cepat untuk Android
Halaman ini menjelaskan cara bazel mobile-install
membuat pengembangan iteratif
untuk Android menjadi jauh lebih cepat. Bagian ini menjelaskan manfaat pendekatan ini versus
tantangan metode penginstalan aplikasi tradisional.
Ringkasan
Untuk menginstal perubahan kecil ke aplikasi Android dengan sangat cepat, lakukan hal berikut:
- Temukan aturan
android_binary
aplikasi yang ingin diinstal. - Nonaktifkan Proguard dengan menghapus atribut
proguard_specs
. - Tetapkan atribut
multidex
kenative
. - Tetapkan atribut
dex_shards
ke10
. - Hubungkan perangkat yang menjalankan ART (bukan Dalvik) melalui USB dan aktifkan proses debug USB di perangkat tersebut.
- Jalankan
bazel mobile-install :your_target
. Startup aplikasi akan sedikit lebih lambat dari biasanya. - Edit kode atau resource Android.
- Jalankan
bazel mobile-install --incremental :your_target
. - Nikmati tanpa perlu menunggu lama.
Beberapa opsi command line untuk Bazel yang mungkin berguna:
--adb
memberi tahu Bazel biner adb mana yang akan digunakan--adb_arg
dapat digunakan untuk menambahkan argumen tambahan ke command lineadb
. Salah satu penerapannya yang berguna adalah memilih perangkat tempat Anda ingin menginstal jika memiliki beberapa perangkat yang terhubung ke workstation:bazel mobile-install --adb_arg=-s --adb_arg=<SERIAL> :your_target
--start_app
memulai aplikasi secara otomatis
Jika ragu, lihat contoh atau hubungi kami.
Pengantar
Salah satu atribut terpenting dari toolchain developer adalah kecepatan: ada perbedaan antara mengubah kode dan melihatnya berjalan dalam satu detik serta harus menunggu beberapa menit, terkadang berjam-jam, sebelum Anda mendapatkan masukan tentang apakah perubahan Anda berfungsi seperti yang diharapkan.
Sayangnya, toolchain Android tradisional untuk mem-build .apk memerlukan banyak langkah monolitik dan berurutan, dan semua ini harus dilakukan untuk membangun aplikasi Android. Di Google, menunggu lima menit untuk membuat perubahan satu baris bukanlah hal yang aneh pada project yang lebih besar seperti Google Maps.
bazel mobile-install
membuat pengembangan berulang untuk Android jauh lebih cepat dengan
menggunakan kombinasi pemangkasan perubahan, sharding pekerjaan, dan manipulasi internal
Android yang cerdas, semuanya tanpa mengubah kode aplikasi Anda.
Masalah terkait penginstalan aplikasi tradisional
Mem-build aplikasi Android memiliki beberapa masalah, termasuk:
Dexing. Secara default, "dx" dipanggil tepat satu kali dalam build dan tidak tahu cara menggunakan kembali pekerjaan dari build sebelumnya: dexes setiap metode lagi, meskipun hanya satu metode yang diubah.
Mengupload data ke perangkat. adb tidak menggunakan bandwidth penuh dari koneksi USB 2.0, dan aplikasi yang lebih besar dapat membutuhkan banyak waktu untuk diupload. Seluruh aplikasi diupload, meskipun hanya sebagian kecil yang berubah, misalnya, resource atau metode tunggal, sehingga hal ini dapat menjadi bottleneck besar.
Kompilasi ke kode native. Android L memperkenalkan ART, runtime Android baru, yang mengompilasi aplikasi terlebih dahulu, bukan mengompilasinya tepat waktu seperti Dalvik. Hal ini membuat aplikasi jauh lebih cepat dengan mengorbankan waktu penginstalan yang lebih lama. Ini adalah konsekuensi yang baik bagi pengguna karena mereka biasanya menginstal aplikasi satu kali dan menggunakannya berkali-kali, tetapi menyebabkan pengembangan yang lebih lambat karena aplikasi diinstal berkali-kali dan setiap versi dijalankan paling sering beberapa kali.
Pendekatan bazel mobile-install
bazel mobile-install
melakukan peningkatan berikut:
Dexing sharding. Setelah membuat kode Java aplikasi, Bazel akan melakukan sharding file class menjadi bagian yang kira-kira berukuran sama dan memanggil
dx
secara terpisah.dx
tidak dipanggil pada shard yang tidak berubah sejak build terakhir.Transfer file inkremental. Resource Android, file .dex, dan library native dihapus dari .apk utama dan disimpan di direktori instal seluler yang terpisah. Dengan demikian, Anda dapat mengupdate kode dan resource Android secara independen tanpa harus menginstal ulang seluruh aplikasi. Dengan demikian, transfer file memerlukan waktu yang lebih singkat dan hanya file .dex yang telah berubah yang akan dikompilasi ulang di perangkat.
Memuat bagian aplikasi dari luar .apk. Aplikasi stub kecil dimasukkan ke dalam .apk yang memuat resource Android, kode Java, dan kode native dari direktori penginstalan seluler di perangkat, lalu mentransfer kontrol ke aplikasi yang sebenarnya. Semua ini transparan oleh aplikasi, kecuali dalam beberapa kasus sudut yang dijelaskan di bawah ini.
Dexing dengan Shard
Dexing sharding cukup sederhana: setelah file .jar dibuat, alat akan membaginya menjadi file .jar terpisah dengan ukuran yang kurang lebih sama, lalu memanggil dx
pada file yang telah diubah sejak build sebelumnya. Logika yang
menentukan shard mana ke dex tidak spesifik untuk Android: logika hanya menggunakan
algoritma pemangkasan perubahan umum dari Bazel.
Versi pertama algoritma sharding ini hanya mengurutkan file .class menurut abjad, lalu memotong daftar menjadi beberapa bagian yang berukuran sama, tetapi cara ini terbukti kurang optimal: jika sebuah class ditambahkan atau dihapus (bahkan class bertingkat atau anonim), semua class menurut abjad akan berubah satu per satu, sehingga terjadi dexing pada shard tersebut lagi. Dengan demikian, keputusan untuk melakukan sharding paket Java bukan class individual. Tentu saja, hal ini masih menghasilkan dexing banyak shard jika paket baru ditambahkan atau dihapus, tetapi frekuensinya jauh lebih jarang dibandingkan menambahkan atau menghapus satu class.
Jumlah shard dikontrol oleh file BUILD (menggunakan
atribut android_binary.dex_shards
). Dalam kondisi ideal, Bazel akan
secara otomatis menentukan jumlah shard yang terbaik. Namun, saat ini Bazel harus mengetahui
serangkaian tindakan (misalnya, perintah yang harus dijalankan selama build) sebelum
menjalankannya, sehingga tidak dapat menentukan jumlah shard yang optimal
karena tidak mengetahui jumlah class Java yang akan ada di dalam
aplikasi. Secara umum, semakin banyak shard, semakin cepat build dan
penginstalan aplikasi akan berjalan, Rentang nilai yang baik biasanya antara 10 dan 50 pecahan.
Transfer file inkremental
Setelah mem-build aplikasi, langkah berikutnya adalah menginstalnya, sebaiknya dengan upaya paling minimal. Penginstalan terdiri dari langkah-langkah berikut:
- Menginstal .apk (biasanya menggunakan
adb install
) - Mengupload file .dex, resource Android, dan library native ke direktori mobile-install
Tidak ada banyak inkrementalitas pada langkah pertama: aplikasi diinstal
atau tidak. Saat ini Bazel mengandalkan pengguna untuk menunjukkan apakah harus melakukan langkah ini
melalui opsi command line --incremental
karena tidak dapat menentukan
semua kasus jika diperlukan.
Pada langkah kedua, file aplikasi dari build dibandingkan dengan file manifes di perangkat yang mencantumkan file aplikasi mana yang ada di perangkat beserta checksum-nya. Setiap file baru akan diupload ke perangkat, semua file yang telah diubah akan diupdate, dan semua file yang telah dihapus akan dihapus dari perangkat. Jika manifes tidak ada, dianggap bahwa setiap file perlu diupload.
Perlu diketahui bahwa Anda dapat mengelabui algoritma penginstalan inkremental dengan mengubah file di perangkat, tetapi tidak dengan checksum di manifes. Hal ini bisa dilindungi dengan menghitung checksum file di perangkat, tetapi hal ini dianggap tidak sebanding dengan peningkatan waktu penginstalan.
Aplikasi Stub
Aplikasi stub adalah tempat keajaiban untuk memuat dexes, kode native, dan
resource Android dari direktori mobile-install
di perangkat.
Pemuatan yang sebenarnya diterapkan dengan membuat subclass BaseDexClassLoader
dan merupakan
teknik yang terdokumentasi dengan baik. Hal ini terjadi sebelum class aplikasi
dimuat sehingga setiap class aplikasi yang ada dalam apk dapat
ditempatkan di direktori mobile-install
di perangkat sehingga dapat diupdate
tanpa adb install
.
Hal ini harus terjadi sebelum salah satu class aplikasi dimuat sehingga tidak perlu ada class aplikasi di dalam .apk. Artinya, perubahan pada class tersebut akan memerlukan penginstalan ulang penuh.
Hal ini dilakukan dengan mengganti class Application
yang ditentukan dalam
AndroidManifest.xml
dengan
aplikasi stub. Tindakan ini
mengambil kontrol kapan aplikasi dimulai, dan menyesuaikan loader class dan
pengelola resource dengan tepat pada saat paling awal (konstruktornya) menggunakan
refleksi Java pada bagian dalam framework Android.
Hal lain yang dilakukan aplikasi stub adalah menyalin library native yang diinstal oleh penginstalan seluler ke lokasi lain. Hal ini diperlukan karena
penaut dinamis memerlukan bit X
untuk ditetapkan pada file, yang tidak dapat dilakukan
untuk lokasi mana pun yang dapat diakses oleh adb
non-root.
Setelah semua hal ini selesai, aplikasi stub kemudian membuat instance
class Application
sebenarnya, yang mengubah semua referensi ke aplikasi itu sendiri
ke aplikasi sebenarnya dalam framework Android.
Hasil
Performa
Secara umum, bazel mobile-install
menghasilkan kecepatan build
dan penginstalan aplikasi besar 4x hingga 10x lipat setelah perubahan kecil.
Angka berikut dihitung untuk beberapa produk Google:
Hal ini, tentu saja, bergantung pada sifat perubahannya: kompilasi ulang setelah mengubah library dasar memerlukan waktu lebih lama.
Batasan
Trik yang dijalankan aplikasi stub tidak selalu berhasil. Kasus berikut menyoroti bagian yang tidak berfungsi seperti yang diharapkan:
Saat
Context
ditransmisikan ke classApplication
diContentProvider#onCreate()
. Metode ini dipanggil selama startup aplikasi sebelum kita memiliki kesempatan untuk mengganti instance classApplication
. Oleh karena itu,ContentProvider
akan tetap mereferensikan aplikasi stub, bukan aplikasi yang sebenarnya. Dapat dipastikan, ini bukan bug karena Anda tidak seharusnya menurunkanContext
seperti ini, tetapi hal ini tampaknya terjadi pada beberapa aplikasi di Google.Resource yang diinstal oleh
bazel mobile-install
hanya tersedia dari dalam aplikasi. Jika resource diakses oleh aplikasi lain melaluiPackageManager#getApplicationResources()
, resource ini akan berasal dari penginstalan non-inkremental terakhir.Perangkat yang tidak menjalankan ART. Meskipun aplikasi stub berfungsi dengan baik di Froyo dan yang lebih baru, Dalvik memiliki bug yang membuat aplikasi merasa salah jika kodenya didistribusikan ke beberapa file .dex dalam kasus tertentu, misalnya, saat anotasi Java digunakan dengan cara yang tertentu. Selama tidak menggelitik bug tersebut, aplikasi Anda juga akan berfungsi dengan Dalvik (perlu diperhatikan, bahwa dukungan untuk versi Android lama bukanlah fokus kami)