[SmallerAPK] Phần 1: Giải phẫu file APK

Nếu tôi hỏi các lập trình viên về dung lượng của ứng dụng Android của họ, tôi chắc chắn là hầu hết mọi người trả lời về dung lượng của file APK được tạo ra bởi Android Studio. Về mặt kỹ thuật thì đó là câu trả lời đúng, tuy nhiên để có được câu trả lời chi tiết hơn, chắc tôi nên đổi sang các câu hỏi sau:

– Khi được cài đặt lên máy của người dùng, ứng dụng của bạn sẽ chiếm bao nhiêu dung lượng bộ nhớ?
– Khi người dùng tải và cài đặt ứng dụng của bạn, họ sẽ phải dùng bao nhiêu dung lượng mạng internet?
– Bản update phiên bản mới của ứng dụng của bạn có dung lượng là bao nhiêu?
– Khi ứng dụng của bạn chạy, nó sẽ chiếm bao nhiêu dung lượng bộ nhớ RAM?

Nếu bạn đang là lập trình viên di động, bạn nên cân nhắc việc có đáng bỏ thời gian để tối ưu hóa dung lượng của file APK … hay không, hay thời gian đó nên để phát triển chức năng mới? Nên nhớ rằng, các thiết bị di động có sự khác biệt về dung lượng bộ nhớ, dung lượng RAM và tốc độ kết nối mạng internet.

Vẫn có nhiều nơi trên thế giới, người dùng phải trả tiền cho từng megabyte dữ liệu họ tải về từ internet và Wifi hotpots thì không được phổ biến ở tất cả các nơi.

Nhiều thiết bị có dung lượng bộ nhớ thấp, do đó người sử dụng cần phải cân nhắc kỹ trước khi cài thêm hoặc update các ứng dụng. Do đó các lập trình viên nên dành thời gian suy nghĩ tối ưu hóa dung lượng ứng dụng, nó sẽ có ích cho tất cả mọi người.

Tất nhiên, việc xem xét cân nhắc giữa các yêu cầu chức năng và các hạn chế chúng ta gặp phải trong quá trình phát triển phần mềm dẫn tới việc khó khăn để chọn được 1 giải pháp có thể đáp ứng tất cả các yêu cầu. Đôi khi phải chấp nhận việc tải về dung lượng ban đầu lớn, để có thế tăng tốc độ cho các lần update sau. Trong trường hợp khác, việc sử dụng các tập tin không được nén trong file APK sẽ làm tăng số dung lượng cần dùng trên sdcard của thiết bị cho ứng dụng …

Trong bài viết này tôi sẽ cố gắng đưa ra 1 vài giải pháp và tình huống nên áp dụng các giải pháp đó. Việc lựa chọn giải pháp cuối cùng phụ thuộc vào các bạn – những nhà lập trình mobile, để đạt được chất lượng tốt nhất cho ứng dụng của chính bạn và lợi ích cho người sử dụng.

Trong loạt bài viết này, tôi chưa đề cập tới việc tối ưu hóa bộ nhớ RAM. Các kỹ thuật tối ưu được đưa ra dựa trên các kinh nghiệm của bản thân tôi trong quá trình lập trình mobile, các kỹ thuật này sẽ có 1 vài ảnh hưởng tốt/xấu tới bộ nhớ RAM và hiệu suất sử dụng, tôi sẽ cố gắng giải thích cụ thể các ảnh hưởng này, việc quyết định ảnh hưởng đó là tốt hay xấu sẽ dành cho các bạn đánh giá khi áp dụng vào ứng dụng của chính các bạn.

Bên trong file APK có gì?

Trước khi tìm cách loại bỏ các phần thừa thãi trong file APK, hãy cùng giải phẫu file này ra nhé. Bản chất file APK là 1 loại file nén (ZIP), bao gồm toàn bộ các file được sử dụng trong ứng dụng. Bình thường cấu trúc bên trong của file APK như sau:

  • classes.dex

Bao gồm các mã code đã được biên dịch, dưới dạng Dex (Dalvik Executable) bytecode. Bạn có thể nhìn thấy nhiều file DEX trong 1 file APK, nếu bạn sử dụng multidex vượt quá giới hạn 65536 hàm. Từ Android 5.0 trở lên, với việc giới thiệu ART runtime, chúng được biên dịch dưới dạng OTA file. Bạn có thể tìm hiểu cách giảm dung lượng lương của file dex ở “Phần 2: Rút gọn code”

  • res/

Folder này chứa toàn bộ các file XML (layout), và file ảnh (PNG, JPEG) trong các folder đặc trưng, như là -mdpi và -hdpi cho densities, -sw600dp hoặc -large cho kích cỡ màn hình, -en, -de, -pl cho ngôn ngữ. Chú ý rằng bất kỳ file XML nào trong res/ đều đã được biên dịch lại, do đó bạn không để đọc trực tiếp chúng bằng các text editor được.

“Phần 3: Xóa bỏ các resource không cần thiết” sẽ hướng dẫn bạn chắc chắn rằng mình không bị lãng phí dung lượng bởi việc sử dụng các resource thừa.

“Phần 4: Multi-APK, ABI và chia theo độ phân giải” và “Phần 5: Multi-APK ở chế độ sản phẩm”, chúng ta sẽ trao đổi về cách chia ứng dụng thành nhiều file APK mà hỗ trợ cho từng nhóm thiết bị có phần cứng khác nhau.

“Phần 6: Tối ưu hóa dung lương ảnh, Zopfli & WebP “ và “Phần 7: Tối ưu hóa dung lượng ảnh, Shape Drawable và Vector Drawables” chúng ta sẽ bàn về các kỹ thuật tối ưu hóa để giảm dung lượng của các ảnh trong ứng dụng.

  • resources.arsc

Một vài resource và file định danh (identifiers) được biên dịch và chứa lại trong file này. Bình thường nó sẽ không được nén lại và được chứa trong file APK, giúp cho việc truy xuất dữ liệu nhanh hơn. Việc nén lại file này bằng cách thủ công có thể là giải pháp đơn giản mất để giảm dụng lượng file, tuy nhiên đó không hẳn là ý kiến hay bởi 2 lý do sau. Thứ nhất, Google Play store đã có sẵn cơ chế nén các data khi trao đổi dữ liệu. Thứ hai, lưu trữ các file nén trong APK sẽ phải mất thời gian giải nén khi thực thi ứng dụng.

Phần 3 sẽ trao đổi về kỹ thuật tối ưu hóa bằng cách chỉ bao gồm mỗi các file strings cho ngôn ngữ cần thiết trong folder này.

  • AndroidManifest.xml

Tương tự như các file XML khác, file Manifest của ứng dụng sẽ được biên dịch lại thành mã máy. Google Play Store sử dụng các thông tin trong file này để xác định file APK có thể cài đặt được trên thiết bị hay không?,dựa kiểm tra loại các phần cứng, màn hình, độ phân giải của các thiết bị này. Nếu bạn muốn kiểm tra các thông tin này sau khi quá trình biên dịch, bạn có thể dụng aapt tool của Android SDK

  • libs/

Tất cả các thư viện native (*.so files) sẽ được đặt trong các folder con (cấu trúc CPU , e.g. x86, x86_64, armeabi-v7a) của folder libs/ . Bình thường nó sẽ được copy từ APK vào folder /data trong quá trình cài đặt. Tuy nhiên bản thân file APK không thể tự thay đỏi khi file nằm trong thiết bị, do đó nó sẽ cần gấp đôi dung lượng cho bất kỳ thư viện native nào. ở “Phần 8: các thư viện native” sẽ giới thiệu giải pháp cho vấn đề này ở Android 6.0+ cùng với lợi ích của việc tiết kiệm băng thông mạng internet cho các thiết bị cũ hơn.

  • assets/

Folder này chứa các file mà không được sử dụng như các file đặc trưng của Android. Các file phổ biến nhất là font chữ và data của game, hoặc bất kỳ loại data nào mà bạn muốn sử dụng trực tiếp như là file stream.

  • META-INF/

Folder này được chứa trong các file APK đã được ký (signed APK), bao gồm danh sách tất cả các file có trong APK và chữ ký của chúng. Cách xác thực chữ ký hiện tại trong Android là việc xác thực từng chữ ký với nội dung của từng file chưa được nén.

Việc này phát sinh 1 hậu quả thú vị như sau. Bởi vì từng entry trong file ZIP được lưu trữ độc lập, điều đó có nghĩa rằng bạn có thể thay đổi mức độ nén của từng file mà không cần ký lại. Việc xác thực chữ ký sẽ thất bại, tuy nhiên nếu bạn xóa 1 vài file sau khi đã ký, thì ko có vấn đề gì.

Thêm 1 điều cần lưu ý về việc ký lên file APK là zipalign tool được sử dụng cuối cùng trong quá trình build. Nếu bạn thay đổi nội dung của tập tin bằng tay, thì bạn sẽ phải ký lại, và sử dụng zipalign trước khi upload file lên Google Play Store.

Nén lại file APK bằng Zopfli

Có cách đơn giản để giảm dung lượng file APK với thuật toán nén mạnh. Zipalign hỗ trợ việc nén lại file bên trong APK với Zopfli  – một trình nén tương thích với Deflate được phát triển bởi Google. Sử dụng câu lệnh zipalign với tùy chọn -z để nén file APK:

Lưu ý rằng việc nén bằng Zopfli sẽ mất thời gian xử lý, nhưng hi vọng rằng file APK kết quả có giảm được 1 vài phần trăm dung lượng. Thời gian cài đặt và hiệu suất hoạt động sẽ không bị ảnh hưởng xấu, do tốc độ giải nén của Zopfli nằm ở mức cạnh tranh được với các thuật toán khác.


[ML] Làm quen với Machine Learning