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

Báo cáo vấn đề Xem nguồn Hằng đêm · 7,3 · 7.2 · 7.1 · 7 · 6,5

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

Trang này mô tả cách bazel mobile-install thực hiện quá trình phát triển lặp lại cho Android nhanh hơn nhiều. Mô tả lợi ích của phương pháp này so với những thách thức của phương pháp cài đặt ứng dụng truyền thống.

Tóm tắt

Để cài đặt các thay đổi nhỏ đối với ứng dụng Android cực nhanh, hãy làm như sau:

  1. Tìm quy tắc android_binary của ứng dụng mà bạn muốn cài đặt.
  2. Tắt Proguard bằng cách xoá thuộc tính proguard_specs.
  3. Đặt thuộc tính multidex thành native.
  4. Đặt thuộc tính dex_shards thành 10.
  5. Kết nối thiết bị chạy ART (không phải Dalvik) qua USB và bật USB gỡ lỗi trên đó.
  6. Chạy bazel mobile-install :your_target. Quá trình khởi động ứng dụng sẽ dễ dàng chậm hơn thường lệ.
  7. Chỉnh sửa mã hoặc tài nguyên Android.
  8. Chạy bazel mobile-install --incremental :your_target.
  9. Bạn có thể thoải mái khám phá mà không phải chờ đợi lâu.

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

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

Khi nghi ngờ, hãy xem xét ví dụ hoặc liên hệ với chúng tôi.

Giới thiệu

Một trong những thuộc tính quan trọng nhất trong chuỗi công cụ của nhà phát triển là tốc độ: có sự khác biệt giữa việc thay đổi mã và thấy mã chạy trong rồi phải đợi vài phút, đôi khi là nhiều giờ, rồi mới nhận được ý kiến phản hồi về việc liệu các thay đổi có đúng như bạn mong đợi hay không.

Thật không may, chuỗi công cụ Android truyền thống để tạo tệp .apk lại đòi hỏi nhiều bước đơn khối, tuần tự và tất cả các bước này phải được thực hiện để tạo ứng dụng Android. Tại Google, đợi 5 phút để tạo một dòng đơn thay đổi là bình 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 lại cho Android nhanh hơn nhiều bằng cách sử dụng kết hợp giữa cắt bớt thay đổi, phân đoạn công việc và thao tác thông minh Android nội bộ, tất cả đều không phải thay đổi mã của ứng dụng.

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

Khi xây dựng ứng dụng Android có một số vấn đề, bao gồm:

  • Tạo tệp dex. Theo mặc định, "dx" đượ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 lặp lại mọi phương thức, thậm chí mặc dù chỉ có một phương thức thay đổi.

  • Đang 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 USB 2.0 và các ứng dụng lớn hơn có thể mất nhiều thời gian để tải lên. Toàn bộ ứng dụng đã tải lên, ngay cả khi chỉ một phần nhỏ thay đổi, ví dụ: tài nguyên hoặc phương pháp duy nhất, vì vậy, đây có thể là nút thắt cổ chai lớn.

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

Phương thức của bazel mobile-install

bazel mobile-installcó các điểm cải tiến sau:

  • Tạo tệp dex phân đoạn. Sau khi tạo mã Java của ứng dụng, Bazel phân đoạn lớp tệp thành các phần có kích thước tương đối bằng nhau và gọi dx riêng biệt trên chúng. dx không được gọi trên phân đoạn không thay đổi kể từ bản dựng gần đây nhất.

  • Truyền tệp tăng dần. Tài nguyên Android, tệp .dex và mã gốc các thư viện sẽ bị xoá khỏi tệp .apk chính và được lưu trữ trong một tệp thư mục cài đặt trên thiết bị di động. Thao tác này giúp bạn có thể cập nhật mã và Android tài nguyên 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 các tệp mất ít thời gian hơn và chỉ mất các tệp .dex có đã thay đổi sẽ được biên dịch lại trên thiết bị.

  • Tải các phần của ứng dụng từ bên ngoài tệp .apk. Có một ứng dụng nhỏ còn lại đưa vào .apk để tải tài nguyên Android, mã Java và mã gốc từ thư mục cài đặt dành cho thiết bị di động trên thiết bị, sau đó chuyển quyền kiểm soát sang ứng dụng thực tế. Thao tác này sẽ minh bạch đối với ứng dụng, ngoại trừ một số trường hợp ở góc được mô tả bên dưới.

Phân đoạn Dexing

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

Phiên bản đầu tiên của thuật toán phân đoạn chỉ cần sắp xếp các tệp .class theo thứ tự bảng chữ cái, sau đó cắt danh sách thành các phần có kích thước bằng nhau, nhưng điều này đã chứng minh không tối ưu: nếu một lớp được thêm hoặc bị xoá (thậm chí là lớp được lồng hoặc ẩn danh một), thao tác này sẽ khiến tất cả các lớp theo thứ tự bảng chữ cái sau nó di chuyển 1 đơn vị, dẫn đến việc tạo lại các phân đoạn đó. Do đó, người ta quyết định phân đoạn Java thay vì từng lớp riêng lẻ. Tất nhiên, điều này vẫn dẫn đến tạo tệp dex nhiều phân đoạn nếu một gói mới được thêm hoặc xoá, nhưng làm như vậy sẽ ít hơn thường xuyên hơn so với việc thêm hoặc xoá một lớp.

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

Truyền tệp tăng dần

Sau khi tạo ứng dụng, bước tiếp theo là cài đặt ứng dụng đó, tốt nhất là bằng nỗ lực ít nhất có thể. Quá trình cài đặt bao gồm các bước sau:

  1. Đang cài đặt .apk (thường sử dụng adb install)
  2. Tải các tệp .dex, tài nguyên Android và thư viện gốc lên thư mục cài đặt trên thiết bị di động

Không có nhiều mức độ gia tăng trong bước đầu tiên: ứng dụng sẽ được cài đặt hoặc không. Bazel hiện dựa vào người dùng để cho biết có nên thực hiện bước này hay không thông qua tuỳ chọn dòng lệnh --incremental vì tuỳ chọn này không thể xác định trong tất cả các trường hợp nếu cần.

Ở bước thứ hai, các tệp của ứng dụng trong bản dựng được so sánh với một tệp trên thiết bị tệp kê khai liệt kê các tệp ứng dụng nào trên thiết bị và giá trị tổng kiểm. Mọi tệp mới đều được tải lên thiết bị, bất kỳ tệp nào đã thay đổi được cập nhật và mọi tệp đã bị xóa sẽ bị xóa khỏi thiết bị. Nếu không có tệp kê khai, hệ thống sẽ giả định rằng mọi tệp đều cần được tải lên.

Lưu ý rằng có thể đánh lừa thuật toán cài đặt gia tăng bằng cách thay đổi một tệp trên thiết bị nhưng không thay đổi giá trị tổng kiểm của tệp trong tệp kê khai. Điều này có thể có thể được bảo vệ bằng cách tính tổng kiểm tra các tệp trên nhưng thời gian này được cho là không đáng để tăng thời gian cài đặt.

Ứng dụng Stub

Ứng dụng mã giả lập là nơi bạn có thể tải các tệp dex, mã gốc và Các tài nguyên Android từ thư mục mobile-install trên thiết bị sẽ hoạt động.

Việc tải thực tế được triển khai bằng cách phân lớp con BaseDexClassLoader và là một kỹ thuật được ghi nhận hợp lý. Quá trình này xảy ra trước khi bất kỳ các lớp này được tải để mọi lớp ứng dụng có trong tệp APK đều có thể được đặt trong thư mục mobile-install trên thiết bị để có thể cập nhật không có adb install.

Điều này cần phải xảy ra trước khi bất kỳ các lớp của ứng dụng sẽ được tải, sao cho không cần lớp ứng dụng nào trong .apk nghĩa là thay đổi đối với các lớp đó sẽ yêu cầu một tệp cài đặt lại.

Bạn có thể thực hiện việc này bằng cách thay thế lớp Application được chỉ định trong AndroidManifest.xml bằng ứng dụng giả lập. Chiến dịch này kiểm soát thời điểm ứng dụng khởi động, đồng thời điều chỉnh trình tải lớp cũng như trình quản lý tài nguyên một cách phù hợp tại thời điểm sớm nhất (hàm khởi tạo) bằng cách sử dụng Phản chiếu Java vào bên trong khung Android.

Một chức năng khác của ứng dụng mã giả lập là sao chép các thư viện gốc cài đặt bằng thiết bị di động đến vị trí khác. Điều này là cần thiết vì trình liên kết động cần bit X được đặt trên các tệp, điều này không thể thực hiện cho bất kỳ vị trí nào có thể truy cập được bằng adb không phải thư mục gốc.

Sau khi hoàn tất tất cả những việc này, ứng dụng giả lập sẽ tạo thực thể cho lớp Application thực tế, thay đổi mọi tham chiếu đến chính lớp đó ứng dụng trong khung Android.

Kết quả

Hiệu suất

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

Những con số sau đã được tính 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: quá trình biên dịch lại sau thì việc thay đổi 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 giả lập không hoạt động trong mọi trường hợp. Sau đây là ví dụ về những điểm mà chế độ này không hoạt động như mong đợi:

  • Khi Context được truyền tới lớp Application trong ContentProvider#onCreate(). Phương thức này được gọi trong khi áp dụng trước khi chúng ta có cơ hội thay thế bản sao của Application do đó, ContentProvider vẫn sẽ tham chiếu đến ứng dụng mã giả lập thay vì báo cáo thực. Có thể cho rằng đây không phải là lỗi vì bạn đáng lẽ sẽ giảm Context như thế này, nhưng điều này có vẻ sẽ xảy ra sau ứng dụng tại Google.

  • Các tài nguyên do bazel mobile-install cài đặt chỉ có sẵn trong ứng dụng. Nếu các ứng dụng khác truy cập vào tài nguyên qua PackageManager#getApplicationResources(), các tài nguyên này sẽ lấy từ lượt cài đặt không tăng dần cuối cùng.

  • Các thiết bị hiện không chạy ART. Mặc dù ứng dụng giả lập hoạt động tốt trên Froyo trở lên, Dalvik có một lỗi khiến ứng dụng nghĩ rằng không chính xác nếu mã được phân phối trên nhiều tệp .dex trong một số trường hợp, ví dụ: khi chú thích Java được sử dụng trong một cụ thể . Miễn là ứng dụng của bạn không mắc các lỗi này, ứng dụng sẽ hoạt động với Dalvik, (tuy nhiên, xin lưu ý rằng việc hỗ trợ cho các phiên bản Android cũ không chính xác là tiêu điểm)