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

Báo cáo sự cố Xem nguồn

Phát triển lặp lại nhanh 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. Tài liệu này mô tả những lợi ích của phương pháp này so với những thách thức của phương thức cài đặt ứng dụng truyền thống.

Tóm tắt

Để cài đặt nhanh các thay đổi nhỏ cho một ứ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 qua USB trên đó.
  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 các tài nguyên Android.
  8. Chạy bazel mobile-install --incremental :your_target.
  9. Thoải mái sử dụng mà không phải chờ nhiều.

Một số tuỳ 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 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 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

Khi 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ó một thế giới khác biệt giữa việc thay đổi mã và thấy mã chạy trong vòng một giây và phải đợi vài phút, đôi khi là vài giờ, trước khi bạn nhận được bất kỳ phản hồi nào về việc các thay đổi của bạn có giố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 đòi hỏi nhiều bước khối, tuần tự và tất cả đều phải được thực hiện để tạo ứng dụng Android. Tại Google, việc đợi 5 phút để tạo thay đổi một dòng là điều 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 tính năng cắt giảm thay đổi, phân đoạn tác vụ và thao tác thông minh nội bộ Android, tất cả mà không thay đổi mã của ứng dụng.

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

Quá trình tạo ứng dụng Android có một số vấn đề như sau:

  • 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ẽ tạo lại tệp dex 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 được tải lên, ngay cả khi chỉ có các phần nhỏ thay đổi, chẳng hạn như một tài nguyên hoặc một phương thức, vì vậy, đây có thể là một nút thắt cổ chai lớn.

  • Biên dịch thành mã gốc. Android L đã ra mắt 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 thay vì biên dịch ứng dụng ngay như Dalvik. Điều này làm cho ứng dụng hoạt động nhanh hơn nhiều nhưng mất nhiều thời gian cài đặt hơn. Đây là một lựa chọn đá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 nhiều lần, nhưng dẫn đến việc phát triển chậm hơn do 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 một vài lần.

Cách tiếp cận của bazel mobile-install

bazel mobile-installthực hiện những 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 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 dx trên các tệp đó. 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ị xoá khỏi tệp .apk chính và được lưu trữ trong một thư mục cài đặt riêng trên thiết bị di động. 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 các tệp mất ít thời gian hơn và chỉ các 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 mã giả lập nhỏ được đặt vào tệp .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ị, sau đó chuyển quyền kiểm soát sang ứng dụng thực tế. Tất cả thông tin này đều minh bạch với ứng dụng, ngoại trừ một vài trường hợp cụ thể như mô tả dưới đây.

Tạo tệp dex

Việc tạo tệp dex được phân đoạn khá đơn giản: sau khi tạo tệp .jar, một công cụ phân đoạn các tệp đó 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 tệp đã được thay đổi kể từ bản dựng trước. Logic xác định phân đoạn nào thành dex không dành riêng cho Android: nó 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ỉ 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 là không tối ưu: nếu một lớp được thêm hoặc xoá (thậm chí là lớp lồng ghép hoặc ẩn danh), thì tất cả các lớp sau đó sẽ dịch chuyển theo thứ tự bảng chữ cái, dẫn đến việc chuyển các phân đoạn đó một lần nữa. Do đó, công ty đã 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, thao tác này vẫn dẫn đến việc chuyển nhiều phân đoạn nếu một gói mới được thêm vào hoặc bị xoá, nhưng việc này ít thường xuyên hơn so với việc thêm hoặc xoá một lớp đơn.

Số lượng phân đoạn do tệp BUILD (bằng cách sử dụng thuộc tính android_binary.dex_shards) kiểm soát. Trong thế giới lý tưởng, Bazel sẽ tự động xác định số lượng 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ần đượ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 trong số đó, vì vậy, Bazel không thể xác định số phân đoạn tối ưu vì không biết có bao nhiêu lớp Java trong ứng dụng. Nói chung, quá trình khởi động càng nhanh và quá trình cài đặt càng chậm. Điểm ngọt ngào thường nằm trong khoảng từ 10 đến 50 phân đoạn.

Chuyển tệp dần 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ỏ í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 các tệp .dex, tài nguyên Android và thư viện gốc lên thư mục cài đặt dành cho thiết bị di động

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

Ở bước thứ hai, các tệp của ứng dụng từ bản dựng sẽ được so sánh với một tệp kê khai trên thiết bị liệt kê những tệp ứng dụng có trên thiết bị và tổng kiểm của những tệp đó. Mọi tệp mới được tải lên thiết bị, mọi tệp đã thay đổi đều được cập nhật và mọi tệp đã bị xoá khỏi thiết bị. Nếu không có tệp kê khai, thì hệ thống sẽ giả định rằng mọi tệp đều cần đượ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 một tệp trên thiết bị nhưng không thể đánh dấu giá trị tổng kiểm của tệp đó trong tệp kê khai. Điều này có thể được bảo vệ bằng cách tính toán giá trị tổng kiểm của các tệp trên thiết bị, nhưng việc này bị cho là không đáng để tăng thời gian cài đặt.

Ứng dụng tạm thời

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

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 đầy đủ hợp lý. Điều này xảy ra trước khi bất kỳ lớp nào của ứng dụng được tải, sao cho mọi lớp ứng dụng nằm trong tệp APK đều có thể được đặt vào thư mục mobile-install trên thiết bị sao cho có thể cập nhật các lớp đó 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ần lớp ứng dụng nào trong .apk, có nghĩa là các thay đổi đối với các lớp đó sẽ yêu cầu cài đặt lại hoàn toàn.

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 sẽ kiểm soát thời điểm khởi động ứng dụng, đồng thời điều chỉnh trình tải lớp và trình quản lý tài nguyên một cách phù hợp ngay tại thời điểm đầu tiên (hàm khởi tạo của ứng dụng) sử dụng phương thức phản chiếu Java ở bên trong khung Android.

Một chức năng khác mà ứng dụng mã giả lập có thể làm là sao chép các thư viện gốc được cài đặt bằng 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ể thực hiện được ở bất kỳ vị trí nào mà adb không gốc có thể truy cập.

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

Kết quả

Hiệu suất

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

Các con 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 phụ thuộc vào bản chất của sự thay đổi đó: quá trình biên dịch lại sau khi 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 phát triển không phải lúc nào cũng hiệu quả. Các trường hợp sau đây nêu bật những điểm 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ế thực thể của lớp Application, do đó, ContentProvider sẽ vẫn tham chiếu đến ứng dụng giả lập thay vì ứng dụng thực. Có thể, đây không phải là lỗi vì bạn không phải từ chối Context như thế này, nhưng có vẻ như điều này xảy ra trong một vài ứ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 thông qua PackageManager#getApplicationResources(), các tài nguyên này sẽ đến từ lượt cài đặt không tăng dần gần nhất.

  • Các 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 Froyo trở lên, nhưng Dalvik có một lỗi khiến ứng dụng không chính xác nếu mã của ứng dụng được phân phối trên nhiều tệp .dex trong một số trường hợp nhất định, chẳng hạn như khi sử dụng chú giải Java theo một cách cụ thể. Miễn là ứng dụng của bạn không đánh dấu các lỗi này, nó cũng sẽ hoạt động với Dalvik (tuy nhiên, xin lưu ý rằng việc hỗ trợ các phiên bản Android cũ không thực sự là trọng tâm của chúng tôi)