instal seluler bazel

Laporkan masalah Lihat sumber Nightly · 8.0 · 7.4 · 7.3 · 7.2 · 7.1 · 7.0 · 6.5

Pengembangan iteratif yang cepat untuk Android

Halaman ini menjelaskan cara bazel mobile-install membuat pengembangan iteratif untuk Android jauh lebih cepat. Artikel ini menjelaskan manfaat pendekatan ini dibandingkan tantangan metode penginstalan aplikasi tradisional.

Ringkasan

Untuk menginstal perubahan kecil pada aplikasi Android dengan sangat cepat, lakukan hal berikut:

  1. Temukan aturan android_binary aplikasi yang ingin Anda instal.
  2. Nonaktifkan Proguard dengan menghapus atribut proguard_specs.
  3. Tetapkan atribut multidex ke native.
  4. Tetapkan atribut dex_shards ke 10.
  5. Hubungkan perangkat yang menjalankan ART (bukan Dalvik) melalui USB dan aktifkan proses debug USB di perangkat tersebut.
  6. Jalankan bazel mobile-install :your_target. Startup aplikasi akan sedikit lebih lambat dari biasanya.
  7. Edit kode atau resource Android.
  8. Jalankan bazel mobile-install --incremental :your_target.
  9. Nikmati tidak perlu menunggu lama.

Beberapa opsi command line ke Bazel yang mungkin berguna:

  • --adb memberi tahu Bazel biner adb yang akan digunakan
  • --adb_arg dapat digunakan untuk menambahkan argumen tambahan ke command line adb. Salah satu aplikasi yang berguna adalah memilih perangkat yang ingin Anda instal jika Anda memiliki beberapa perangkat yang terhubung ke workstation: bazel mobile-install --adb_arg=-s --adb_arg=<SERIAL> :your_target
  • --start_app otomatis memulai aplikasi

Jika ragu, lihat contoh atau hubungi kami.

Pengantar

Salah satu atribut terpenting dari toolchain developer adalah kecepatan: ada perbedaan yang sangat besar antara mengubah kode dan melihatnya berjalan dalam detik dan harus menunggu beberapa menit, terkadang berjam-jam, sebelum Anda mendapatkan masukan tentang apakah perubahan Anda melakukan hal yang Anda harapkan.

Sayangnya, toolchain Android tradisional untuk mem-build .apk memerlukan banyak langkah monolitik dan berurutan, dan semua ini harus dilakukan untuk mem-build aplikasi Android. Di Google, menunggu lima menit untuk mem-build perubahan satu baris bukanlah hal yang aneh pada project yang lebih besar seperti Google Maps.

bazel mobile-install membuat pengembangan iteratif 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 sekali dalam build dan tidak tahu cara menggunakan kembali pekerjaan dari build sebelumnya: dx akan mendekode setiap metode lagi, meskipun hanya satu metode yang diubah.

  • Mengupload data ke perangkat. adb tidak menggunakan bandwidth penuh koneksi USB 2.0, dan aplikasi yang lebih besar dapat memerlukan waktu yang lama untuk diupload. Seluruh aplikasi diupload, meskipun hanya sebagian kecil yang telah berubah, misalnya, resource atau satu metode, sehingga hal ini dapat menjadi bottleneck utama.

  • Kompilasi ke kode native. Android L memperkenalkan ART, runtime Android baru, yang mengompilasi aplikasi terlebih dahulu, bukan mengompilasi aplikasi tepat waktu seperti Dalvik. Hal ini membuat aplikasi jauh lebih cepat dengan mengorbankan waktu penginstalan yang lebih lama. Ini adalah kompromi yang baik bagi pengguna karena mereka biasanya menginstal aplikasi sekali dan menggunakannya berkali-kali, tetapi menghasilkan pengembangan yang lebih lambat saat aplikasi diinstal berkali-kali dan setiap versi dijalankan paling banyak beberapa kali.

Pendekatan bazel mobile-install

bazel mobile-installmelakukan peningkatan berikut:

  • Dexing dengan sharding. Setelah mem-build kode Java aplikasi, Bazel akan mengelompokkan file class menjadi bagian yang berukuran kira-kira sama dan memanggil dx secara terpisah di atasnya. 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 bawah direktori penginstalan seluler terpisah. Hal ini memungkinkan Anda mengupdate kode dan resource Android secara independen tanpa menginstal ulang seluruh aplikasi. Dengan demikian, transfer file memerlukan waktu lebih sedikit dan hanya file .dex yang telah berubah yang 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 untuk aplikasi, kecuali dalam beberapa kasus ekstrem yang dijelaskan di bawah.

Dexing dengan Shard

Dexing dengan shard cukup mudah: setelah file .jar di-build, alat akan me-shard-nya menjadi file .jar terpisah dengan ukuran yang kira-kira sama, lalu memanggil dx pada file yang diubah sejak build sebelumnya. Logika yang menentukan shard mana yang akan di-dex tidak khusus untuk Android: logika ini hanya menggunakan algoritma pemangkasan perubahan umum Bazel.

Versi pertama algoritma sharding hanya mengurutkan file .class secara alfabet, lalu memotong daftar menjadi bagian berukuran sama, tetapi hal ini terbukti tidak optimal: jika class ditambahkan atau dihapus (bahkan yang bertingkat atau anonim), hal ini akan menyebabkan semua class secara alfabet setelahnya bergeser satu, sehingga menyebabkan dexing shard tersebut lagi. Oleh karena itu, diputuskan untuk mengelompokkan paket Java, bukan class individual. Tentu saja, hal ini masih menghasilkan de-ekstensi banyak shard jika paket baru ditambahkan atau dihapus, tetapi hal ini jauh lebih jarang dibandingkan dengan menambahkan atau menghapus satu class.

Jumlah shard dikontrol oleh file BUILD (menggunakan atribut android_binary.dex_shards). Dalam kondisi ideal, Bazel akan otomatis menentukan jumlah shard yang terbaik, tetapi saat ini Bazel harus mengetahui kumpulan tindakan (misalnya, perintah yang akan dieksekusi selama build) sebelum mengeksekusi salah satunya, sehingga tidak dapat menentukan jumlah shard yang optimal karena tidak mengetahui jumlah class Java yang pada akhirnya akan ada di aplikasi. Secara umum, semakin banyak shard, semakin cepat build dan penginstalan, tetapi semakin lambat startup aplikasi, karena penaut dinamis harus melakukan lebih banyak pekerjaan. Titik optimal biasanya antara 10 dan 50 shard.

Transfer file inkremental

Setelah mem-build aplikasi, langkah berikutnya adalah menginstalnya, sebaiknya dengan sedikit upaya. Penginstalan terdiri dari langkah-langkah berikut:

  1. Menginstal .apk (biasanya menggunakan adb install)
  2. Mengupload file .dex, resource Android, dan library native ke direktori penginstalan seluler

Tidak ada banyak inkrementalitas pada langkah pertama: aplikasi diinstal atau tidak. Bazel saat ini mengandalkan pengguna untuk menunjukkan apakah harus melakukan langkah ini melalui opsi command line --incremental karena tidak dapat menentukan dalam semua kasus apakah diperlukan atau tidak.

Pada langkah kedua, file aplikasi dari build dibandingkan dengan file manifes di perangkat yang mencantumkan file aplikasi mana yang ada di perangkat dan checksum-nya. Setiap file baru akan diupload ke perangkat, setiap file yang telah berubah akan diperbarui, dan setiap file yang telah dihapus akan dihapus dari perangkat. Jika manifes tidak ada, setiap file diasumsikan harus diupload.

Perhatikan bahwa Anda dapat mengelabui algoritma penginstalan inkremental dengan mengubah file di perangkat, tetapi tidak checksum-nya dalam manifes. Hal ini dapat dilindungi dengan menghitung checksum file di perangkat, tetapi hal ini dianggap tidak sebanding dengan peningkatan waktu penginstalan.

Aplikasi Stub

Aplikasi stub adalah tempat terjadinya keajaiban untuk memuat dex, kode native, dan resource Android dari direktori mobile-install di perangkat.

Pemuatan yang sebenarnya diimplementasikan dengan membuat subclass BaseDexClassLoader dan merupakan teknik yang cukup terdokumentasi dengan baik. Hal ini terjadi sebelum class aplikasi dimuat, sehingga class aplikasi apa pun yang ada di apk dapat ditempatkan di direktori mobile-install di perangkat sehingga dapat diupdate tanpa adb install.

Hal ini harus terjadi sebelum class aplikasi dimuat, sehingga tidak ada class aplikasi yang perlu berada di .apk, yang berarti bahwa perubahan pada class tersebut akan memerlukan penginstalan ulang secara penuh.

Hal ini dilakukan dengan mengganti class Application yang ditentukan dalam AndroidManifest.xml dengan aplikasi stub. Tindakan ini mengambil alih kontrol saat aplikasi dimulai, dan menyesuaikan class loader dan resource manager dengan tepat pada saat paling awal (konstruktornya) menggunakan refleksi Java pada bagian internal 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 apa pun yang dapat diakses oleh adb non-root.

Setelah semua hal ini selesai, aplikasi stub kemudian membuat instance class Application yang sebenarnya, mengubah semua referensi ke dirinya sendiri menjadi aplikasi yang sebenarnya dalam framework Android.

Hasil

Performa

Secara umum, bazel mobile-install menghasilkan percepatan build dan penginstalan aplikasi besar 4x hingga 10x setelah perubahan kecil.

Angka berikut dihitung untuk beberapa produk Google:

Hal ini, tentu saja, bergantung pada sifat perubahan: kompilasi ulang setelah mengubah library dasar memerlukan lebih banyak waktu.

Batasan

Trik yang dimainkan aplikasi stub tidak berfungsi dalam setiap kasus. Kasus berikut menyoroti saat fitur ini tidak berfungsi seperti yang diharapkan:

  • Saat Context ditransmisikan ke class Application di ContentProvider#onCreate(). Metode ini dipanggil selama startup aplikasi sebelum kita memiliki kesempatan untuk mengganti instance class Application, sehingga ContentProvider akan tetap mereferensikan aplikasi stub bukan yang sebenarnya. Bisa dibilang, ini bukan bug karena Anda tidak harus mendowncast Context seperti ini, tetapi tampaknya hal ini terjadi di beberapa aplikasi di Google.

  • Resource yang diinstal oleh bazel mobile-install hanya tersedia dari dalam aplikasi. Jika resource diakses oleh aplikasi lain melalui PackageManager#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 membuatnya berpikir bahwa aplikasi salah jika kodenya didistribusikan melalui beberapa file .dex dalam kasus tertentu, misalnya, saat anotasi Java digunakan dengan cara tertentu. Selama aplikasi Anda tidak memicu bug ini, aplikasi tersebut juga akan berfungsi dengan Dalvik (namun, perhatikan bahwa dukungan untuk versi Android lama bukanlah fokus kami)