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:
- Tìm quy tắc
android_binary
của ứng dụng mà bạn muốn cài đặt. - Tắt Proguard bằng cách xoá thuộc tính
proguard_specs
. - Đặt thuộc tính
multidex
thànhnative
. - Đặt thuộc tính
dex_shards
thành10
. - 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 đó.
- 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ệ. - Chỉnh sửa mã hoặc tài nguyên Android.
- Chạy
bazel mobile-install --incremental :your_target
. - 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ủaadb
. 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-install
có 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:
- Đang cài đặt .apk (thường sử dụng
adb install
) - 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ớpApplication
trongContentProvider#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ủaApplication
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ảmContext
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 quaPackageManager#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)