cài đặt trên thiết bị di động bazel

Báo cáo vấn đề Xem nguồn Nightly · 8.3 · 8.2 · 8.1 · 8.0 · 7.6

Phát triển lặp lại nhanh chóng cho Android

Trang này mô tả cách bazel mobile-install giúp quá trình phát triển lặp đi lặp lại cho Android diễn ra nhanh hơn nhiều. Bài viết này mô tả những lợi ích của phương pháp này so với những hạn chế của các bước xây dựng và cài đặt riêng biệt.

Tóm tắt

Để cài đặt các thay đổi nhỏ cho một ứng dụng Android rất nhanh chóng, hãy làm như sau:

  1. Tìm quy tắc android_binary của ứng dụng bạn muốn cài đặt.
  2. Kết nối thiết bị với adb.
  3. Chạy bazel mobile-install :your_target. Quá trình khởi động ứng dụng sẽ chậm hơn một chút so với bình thường.
  4. Chỉnh sửa mã hoặc tài nguyên Android.
  5. Chạy bazel mobile-install :your_target.
  6. Tận hưởng quá trình cài đặt gia tăng nhanh chóng và tối giản!

Một số lựa chọn dòng lệnh cho Bazel có thể hữu ích:

  • --adb cho Bazel biết nên sử dụng tệp nhị phân adb nào
  • Bạn có thể dùng --adb_arg để thêm đối số bổ sung vào dòng lệnh của adb. Một ứng dụng hữu ích của việc này là chọn thiết bị mà bạn muốn cài đặt nếu có nhiều thiết bị kết nối với máy trạm của bạn:bazel mobile-install :your_target -- --adb_arg=-s --adb_arg=<SERIAL>

Khi nghi ngờ, hãy xem ví dụ, liên hệ với chúng tôi trên Google Groups hoặc báo cáo vấn đề trên GitHub

Giới thiệu

Một trong những thuộc tính quan trọng nhất của chuỗi công cụ dành cho nhà phát triển là tốc độ: có sự khác biệt rất lớn giữa việc thay đổi mã và xem mã đó chạy trong vòng một giây so với việc phải đợi vài phút, đôi khi là vài giờ, trước khi bạn nhận được bất kỳ thông tin phản hồi nào về việc các thay đổi của bạn có thực hiện được những gì bạn mong đợi hay không.

Rất tiếc, chuỗi công cụ Android truyền thống để tạo một tệp .apk đòi hỏi nhiều bước tuần tự, nguyên khối và bạn phải thực hiện tất cả các bước này để tạo một ứng dụng Android. Tại Google, việc chờ 5 phút để tạo một thay đổi một dòng không phải là điều bất thường đối với các dự án lớn hơn như Google Maps.

bazel mobile-install giúp quá trình phát triển lặp đi lặp lại cho Android diễn ra nhanh hơn nhiều bằng cách kết hợp tính năng cắt tỉa thay đổi, phân chia công việc và thao tác thông minh với các thành phần nội bộ của Android mà không cần thay đổi bất kỳ mã nào của ứng dụng.

Vấn đề khi cài đặt ứng dụng theo cách truyền thống

Việc tạo một ứng dụng Android có thể gặp một số vấn đề, bao gồm:

  • Tạo tệp dex. Theo mặc định, công cụ Dexer (trước đây là dx, hiện là d8 hoặc r8) sẽ được gọi chính xác một lần trong bản dựng và không biết cách sử dụng lại công việc từ các bản dựng trước: công cụ này sẽ dex mọi phương thức một lần nữa, mặc dù chỉ có một phương thức được thay đổi.

  • Tải dữ liệu lên thiết bị. adb không sử dụng toàn bộ băng thông của kết nối USB 2.0 và các ứng dụng lớn có thể mất nhiều thời gian để tải lên. Toàn bộ ứng dụng sẽ được tải lên, ngay cả khi chỉ có một số phần nhỏ thay đổi, chẳng hạn như một tài nguyên hoặc một phương thức duy nhất. Vì vậy, đây có thể là một điểm tắc nghẽn lớn.

  • Biên dịch sang mã gốc. Android L ra mắt ART, một thời gian chạy Android mới, biên dịch các ứng dụng trước thời gian thay vì biên dịch chúng ngay tại thời điểm như Dalvik. Điều này giúp các ứng dụng chạy nhanh hơn nhiều nhưng thời gian cài đặt sẽ lâu hơn. Đây là một sự đánh đổi hợp lý cho người dùng vì họ thường cài đặt ứng dụng một lần và sử dụng nhiều lần, nhưng điều này dẫn đến quá trình phát triển chậm hơn khi một ứng dụng được cài đặt nhiều lần và mỗi phiên bản chỉ chạy tối đa vài lần.

Phương pháp tiếp cận của bazel mobile-install

bazel mobile-install mang đến những điểm cải tiến sau:

  • Phân mảnh việc khử đường và dexing. Sau khi tạo mã Java của ứng dụng, Bazel sẽ phân mảnh các tệp lớp thành các phần có kích thước gần bằng nhau và gọi riêng d8 trên các phần đó. d8 không được gọi trên những mảnh không thay đổi kể từ bản dựng gần đây nhất. Sau đó, các phân đoạn này được biên dịch thành các APK phân đoạn riêng biệt.

  • Truyền tệp gia tăng. Các tài nguyên Android, tệp .dex và thư viện gốc sẽ bị xoá khỏi tệp .apk chính và được lưu trữ trong một thư mục cài đặt trên thiết bị di động riêng biệt. Nhờ đó, bạn có thể cập nhật mã và tài nguyên Android một cách độc lập mà không cần cài đặt lại toàn bộ ứng dụng. Do đó, việc chuyển tệp sẽ mất ít thời gian hơn và chỉ những tệp .dex đã thay đổi mới được biên dịch lại trên thiết bị.

  • Cài đặt phân đoạn. Tính năng cài đặt trên thiết bị di động sử dụng công cụ apkdeployer của Android Studio để kết hợp các APK phân mảnh trên thiết bị đã kết nối và mang lại trải nghiệm nhất quán.

Phân mảnh Dexing

Phân mảnh dexing khá đơn giản: sau khi các tệp .jar được tạo, một công cụ sẽ phân mảnh các tệp này thành các tệp .jar riêng biệt có kích thước gần bằng nhau, sau đó gọi d8 trên những tệp đã thay đổi kể từ bản dựng trước. Logic xác định phân đoạn nào cần dex không dành riêng cho Android: logic này chỉ sử dụng thuật toán cắt tỉa thay đổi chung của Bazel.

Phiên bản đầu tiên của thuật toán phân đoạn chỉ sắp xếp các tệp .class theo bảng chữ cái, sau đó chia danh sách thành các phần có kích thước bằng nhau, nhưng cách này không hiệu quả: nếu một lớp được thêm hoặc xoá (ngay cả lớp lồng nhau hoặc lớp ẩn danh), thì tất cả các lớp theo bảng chữ cái sau lớp đó sẽ bị dịch chuyển đi một vị trí, dẫn đến việc phân đoạn lại các mảnh đó. Do đó, chúng tôi quyết định phân đoạn các gói Java thay vì các lớp riêng lẻ. Tất nhiên, điều này vẫn dẫn đến việc lập chỉ mục nhiều mảnh nếu một gói mới được thêm hoặc xoá, nhưng điều đó ít xảy ra hơn nhiều so với việc thêm hoặc xoá một lớp duy nhất.

Số lượng phân đoạn được kiểm soát bằng cấu hình dòng lệnh, sử dụng cờ --define=num_dex_shards=N. Trong một thế giới lý tưởng, Bazel sẽ tự động xác định số lượng phân đoạn phù hợp nhất, nhưng hiện tại Bazel phải biết tập hợp các thao tác (ví dụ: các lệnh sẽ được thực thi trong quá trình tạo) trước khi thực thi bất kỳ thao tác nào trong số đó, vì vậy, Bazel không thể xác định số lượng phân đoạn tối ưu vì không biết cuối cùng sẽ có bao nhiêu lớp Java trong ứng dụng. Nói chung, càng nhiều phân đoạn thì quá trình tạo và cài đặt sẽ càng nhanh, nhưng quá trình khởi động ứng dụng sẽ chậm hơn vì trình liên kết động phải thực hiện nhiều việc hơn. Số lượng phân đoạn lý tưởng thường nằm trong khoảng từ 10 đến 50.

Triển khai gia tăng

Tiện ích apkdeployer hiện xử lý việc chuyển và cài đặt mảnh APK gia tăng như mô tả trong "Phương pháp cài đặt trên thiết bị di động". Trong khi các phiên bản (gốc) trước đây của lượt cài đặt trên thiết bị di động yêu cầu theo dõi thủ công lượt cài đặt lần đầu và áp dụng có chọn lọc cờ --incremental cho lượt cài đặt tiếp theo, thì phiên bản gần đây nhất trong rules_android đã được đơn giản hoá đáng kể. Bạn có thể dùng cùng một lệnh gọi cài đặt trên thiết bị di động, bất kể số lần ứng dụng đã được cài đặt hoặc cài đặt lại.

Nhìn chung, công cụ apkdeployer là một trình bao bọc xung quanh nhiều lệnh phụ adb. Bạn có thể tìm thấy logic điểm truy cập chính trong lớp com.android.tools.deployer.Deployer, với các lớp tiện ích khác được đặt cùng trong gói. Ngoài những thứ khác, lớp Deployer còn tiếp nhận một danh sách các đường dẫn đến các APK phân chia và một protobuf có thông tin về quá trình cài đặt, đồng thời tận dụng các tính năng triển khai cho Android App Bundle để tạo một phiên cài đặt và triển khai gia tăng các phần phân chia ứng dụng. Hãy xem các lớp ApkPreInstallerApkInstaller để biết thông tin chi tiết về cách triển khai.

Kết quả

Hiệu suất

Nhìn chung, bazel mobile-install giúp tăng tốc độ xây dựng và cài đặt các ứng dụng lớn từ 4 đến 10 lần sau một thay đổi nhỏ.

Các số liệu sau đây được tính toán cho một số sản phẩm của Google:

Tất nhiên, điều này phụ thuộc vào bản chất của thay đổi: việc biên dịch lại sau khi thay đổi một thư viện cơ sở sẽ mất nhiều thời gian hơn.

Các điểm hạn chế

Các thủ thuật mà ứng dụng gốc thực hiện không phải lúc nào cũng hiệu quả. Các trường hợp sau đây cho thấy nơi tính năng này không hoạt động như mong đợi:

  • Chỉ hỗ trợ lượt cài đặt trên thiết bị di động thông qua các quy tắc Starlark của rules_android. Hãy xem "lịch sử tóm tắt về lượt cài đặt trên thiết bị di động" để biết thêm thông tin chi tiết.

  • Chỉ hỗ trợ các thiết bị chạy ART. Tính năng cài đặt trên thiết bị di động sử dụng API và các tính năng thời gian chạy chỉ có trên những thiết bị chạy ART, chứ không phải Dalvik. Mọi thời gian chạy Android gần đây hơn Android L (API 21 trở lên) đều phải tương thích.

  • Bản thân Bazel phải được chạy bằng một thời gian chạy Java công cụ phiên bản ngôn ngữ từ 17 trở lên.

  • Các phiên bản Bazel trước 8.4.0 phải chỉ định một số cờ bổ sung cho mobile-install. Xem hướng dẫn về Bazel trên Android. Các cờ này cho Bazel biết khía cạnh cài đặt di động Starlark ở đâu và những quy tắc nào được hỗ trợ.

Một chút lịch sử về lượt cài đặt ứng dụng di động

Các phiên bản Bazel trước đây hỗ trợ sẵn các quy tắc kiểm thử và bản dựng tích hợp cho các ngôn ngữ và hệ sinh thái phổ biến như C++, Java và Android. Do đó, những quy tắc này được gọi là quy tắc gốc. Bazel 8 (phát hành năm 2024) đã loại bỏ tính năng hỗ trợ các quy tắc này vì nhiều quy tắc trong số đó đã được di chuyển sang ngôn ngữ Starlark. Hãy xem "Bài đăng trên blog về Bazel 8.0 LTS" để biết thêm thông tin chi tiết.

Các quy tắc cũ của Android gốc cũng hỗ trợ phiên bản gốc cũ của chức năng cài đặt trên thiết bị di động. Hiện tại, chiến dịch này được gọi là "chiến dịch cài đặt ứng dụng di động phiên bản 1" hoặc "chiến dịch cài đặt ứng dụng di động gốc". Chức năng này đã bị xoá trong Bazel 8, cùng với các quy tắc Android tích hợp.

Giờ đây, tất cả chức năng cài đặt trên thiết bị di động, cũng như tất cả các quy tắc kiểm thử và bản dựng Android đều được triển khai trong Starlark và nằm trong kho lưu trữ rules_android trên GitHub. Phiên bản mới nhất được gọi là "mobile-install v3" hoặc "MIv3".

Lưu ý về tên: Đã từng có một "mobile-install v2" chỉ có sẵn nội bộ tại Google, nhưng phiên bản này chưa bao giờ được xuất bản bên ngoài và chỉ có v3 tiếp tục được sử dụng cho cả việc triển khai quy tắc_android nội bộ của Google và OSS.