cài đặt di động bazel

Sử dụng bộ sưu tập để sắp xếp ngăn nắp các trang Lưu và phân loại nội dung dựa trên lựa chọn ưu tiên của bạn.
Báo cáo vấn đề Xem nguồn

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 lại cho Android nhanh hơn nhiều. Mô hình này mô tả các lợi ích của phương pháp này so với các 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 rất nhanh các thay đổi nhỏ cho ứng dụng Android, 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 tính năng gỡ lỗi USB trên thiết bị.
  6. 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.
  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 không phải chờ đợi nhiều.

Một số tùy chọn dòng lệnh đối với Bazel có thể hữu ích:

  • --adb cho Bazel biết tệp nhị phân adb nào nê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 việc này là chọn thiết bị mà bạn muốn cài đặt nếu bạn có nhiều thiết bị kết nối với máy trạm: bazel mobile-install --adb_arg=-s --adb_arg=<SERIAL> :your_target
  • --start_app tự động khởi động ứng dụng

Nếu nghi ngờ, hãy xem 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 của chuỗi công cụ dành cho 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 vài giây và phải đợi vài phút, đôi khi nhiều giờ, trước khi bạn nhận được bất kỳ phản hồi nào về việc liệu các thay đổi có làm đượ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 tệp .apk đòi hỏi nhiều bước nguyê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, việc chờ 5 phút để xây dựng thay đổi một dòng không phải là điều bất thường trên 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 rất nhiều bằng cách sử dụng kết hợp tính năng cắt bớt nội dung thay đổi, phân đoạn công việc và thao tác thông minh của nội bộ Android, mà không làm thay đổi mã của ứng dụng.

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

Việc tạo ứ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: nó sẽ dex lại mọi phương thức, 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 hơ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ó những 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à nút thắt cổ chai chính.

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

Phương pháp của bazel mobile-install

bazel mobile-installthực hiện các cải tiến sau:

  • Tạo tệp dex. Sau khi tạo mã Java của ứng dụng, Bazel sẽ chia 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 dx riêng trên các phần đó. dx không được gọi trên các phân đoạn không thay đổi kể từ bản dựng cuối cùng.

  • Chuyển tệp tăng dần. Các tài nguyên Android, tệp .dex và thư viện gốc sẽ bị xóa khỏi .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. Điều này giúp 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ị.

  • Tải các phần của ứng dụng từ bên ngoài tệp .apk. Một ứng dụng giả lập nhỏ xíu được đưa vào .apk tải tài nguyên Android, mã Java và mã gốc từ thư mục cài đặt trên thiết bị di động trên thiết bị di động, sau đó chuyển quyền kiểm soát sang ứng dụng thực tế. Tất cả điều này đều trong suốt đối với ứng dụng, ngoại trừ một vài trường hợp góc được mô tả dưới đây.

Tạo tệp dex

Phân đoạn tệp dex rất đơn giản: sau khi tệp .jar được tạo, một công cụ sẽ phân đoạn các tệp đó thành các tệp .jar riêng biệt có kích thước tương đương, sau đó gọi dx trên các tệp đã được thay đổi kể từ phiên bản trước đó. Logic xác định những phân đoạn thành 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ỉ đơn giản là 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. Tuy nhiên, việc này đã được chứng minh là không tối ưu: nếu một lớp được thêm hoặc xóa (ngay cả khi một lớp lồng nhau hoặc một tệp ẩn danh), thì tất cả các lớp sẽ phân chia lại theo cách khác, dẫn đến việc tạo tệp dex cho các tệp đó. Do đó, chúng tôi quyết định phân đoạn các gói Java thay vì từng lớp riêng lẻ. Tất nhiên, điều này vẫn dẫn đến việc chuyển nhiều phân đoạn thành một gói mới được thêm vào hoặc bị xoá, nhưng điều này ít xảy ra hơn so với việc thêm hoặc xoá một lớp.

Số lượng phân đoạn được kiểm soát bởi tệp BUILD (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 tốt nhất, nhưng hiện tại Bazel phải biết tập hợp các 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ỳ phân đoạn nào. Do đó, không phải lúc nào công cụ này càng lâu thì càng có nhiều thời gian để xây dựng Vị trí ngọt thường là từ 10 đến 50 phân đoạn.

Chuyể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à tốn ít công sức nhất có thể. Quá trình cài đặt bao gồm các bước sau:

  1. Cài đặt tệp .apk (thường sử dụng adb install)
  2. Tải 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 được cài đặt hay không. Hiện tại, Bazel sẽ dựa vào người dùng để cho biết liệu họ có nên thực hiện bước này hay không thông qua tùy chọn dòng lệnh --incremental vì tuỳ chọn này không thể xác định trong mọi trường hợp nếu cần.

Ở bước thứ hai, các tệp của ứng dụng trên bản dựng được so sánh với một tệp kê khai trên thiết bị có liệt kê các tệp ứng dụng nằm trên thiết bị và tổng kiểm tra của chúng. Mọi tệp mới được tải lên thiết bị, mọi tệp đã thay đổi sẽ đượ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, giả định rằng mọi tệp đều cần phải được tải lên.

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

Ứng dụng Stub

Ứng dụng mã giả lập là nơi mà người dùng có thể tải các tệp dex, mã gốc và tài nguyên Android từ thư mục mobile-install trên thiết bị một cách kỳ diệu.

Quá trình 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 lại hợp lý. Điều này xảy ra trước khi tải bất kỳ lớp nào của ứng dụng để bất kỳ lớp ứng dụng nào nằm 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 mà không cần adb install.

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

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 mã giả lập. Điều này kiểm soát thời điểm khởi động ứng dụng và đ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 ngay tại thời điểm sớm nhất (trình tạo của ứng dụng) bằng cách sử dụng phản chiếu Java trên nội bộ khung Android.

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

Sau khi thực hiện xong tất cả những thao tác này, ứng dụng mã giả lập sẽ tạo bản sao lớp Application thực tế, thay đổi tất cả các tệp tham chiếu thành chính ứng dụng đó trong khung Android.

Kết quả

Hiệu suất

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

Các số 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 còn phụ thuộc vào bản chất của thay đổi: quá trình biên dịch lại sau khi thay đổi thư viện cơ 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 phải lúc nào cũng hoạt động. Các trường hợp sau đây làm nổi bật những trường hợp mà tính năng không hoạt động như mong đợi:

  • Khi Context được truyền đến lớp Application trong ContentProvider#onCreate(). Phương thức này được gọi trong quá trình khởi động ứng dụng trước khi chúng ta có cơ hội thay thế bản sao của lớp Application, do đó, ContentProvider sẽ vẫn tham chiếu đến ứng dụng mã giả lập thay vì ứng dụng thực. Có thể nói, đây không phải là lỗi vì bạn không được hỗ trợ cho việc giảm tốc độ của Context như thế này, nhưng có vẻ như điều này xảy ra trong một số ứng dụng của 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 tài nguyên thông qua PackageManager#getApplicationResources(), các tài nguyên này sẽ được lấy từ lần cài đặt không tăng dần.

  • Thiết bị không chạy ART. Mặc dù ứng dụng mã giả lập hoạt động tốt trên trở lên, Dalvik vẫn gặp lỗi khiến ứng dụ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, chẳng hạn như khi bạn sử dụng chú thích Java theo cách cụ thể. Miễn là ứng dụng của bạn không phát hiện thấy các lỗi này, thì ứng dụng cũng hoạt động với Dalvik (nhưng hãy lưu ý rằng việc hỗ trợ cho các phiên bản Android cũ không phải là tiêu điểm chính xác của chúng tôi)