12/08/2018, 13:14

[Android Smaller APK] Part1: Anatomy of an APK

Tôi đọc thấy bài blog khá hay từ trang Android developer về vấn đề tối ưu file APK, sau đây tôi muốn chia sẻ với các bạn loạt bài này: Part1: Anatomy of an APK (Phân tích, giải phẫu một file APK) Par2: Minifying Code (Thu gọn mã nguồn) Part3: Removing unused resources (Loại bỏ các ...

Tôi đọc thấy bài blog khá hay từ trang Android developer về vấn đề tối ưu file APK, sau đây tôi muốn chia sẻ với các bạn loạt bài này:

  • Part1: Anatomy of an APK (Phân tích, giải phẫu một file APK)

  • Par2: Minifying Code (Thu gọn mã nguồn)

  • Part3: Removing unused resources (Loại bỏ các tài nguyên thừa)

  • Part4: Multi APK, ABI and desity splits (tài nguyên và multi APK như thế nào cho hợp lý)

  • Part5: Multi APK through product flavour

  • Part6: Image Optimization Zopfli and WebP (Tối ưu ảnh)

  • Part7: Image optimization, Shape, VectorDrawables (Tối ưu ảnh, hình, VectorDrawables)

  • Part8: Native library, open from APK( tối ưu hoá thư viện native)

Nếu hỏi các lập trình viên về dung lượng app họ viết, tôi chắc rằng hầu hết câu trả lời là họ đo dung lượng APK file được generate bởi Android Studio. Nó là câu trả lời dễ nhất, không có gì sai về techinal, nhưng có thể tôi sẽ hỏi một số câu hỏi khó hơn, ví dụ như:

  • Bao nhiêu không gian mà ứng dụng của bạn chiếm sau khi user cài lên device?
  • Bao nhiêu dữ liệu mạng mà user cần trả để tải và cài đặt ứng dụng của bạn?
  • Bao nhiêu dung lượng người dùng cần tải để update ứng dụng?
  • Ứng dụng của bạn đang chạy cần bao nhiêu dung lượng RAM?

Sau khi được hỏi câu hỏi về dung lượng file APK, nếu bạn là một lập trình viên cho thiết bị di động đủ tò mò, hẳn bạn đã từng thắc mắc về việc bỏ thời gian để tối ưu dung lượng file APK.

Có nhiều cách để tối ưu dung lượng file APK, nên nhớ không phải mọi thiết bị đều cùng dung lượng bộ nhớ, lưu trữ hoặc băng thông mạng. Hiện tại người dùng vẫn phải trả tiền cho từng megabyte dữ liệu họ download và Wifi không phả lúc nào cũng sẵn. Do đó việc tối ưu này khá có ích với mọi người dùng ứng dụng của bạn.

Trong file APK có gì?

Để tối ưu được dung lượng file APK, đầu tiên cần phân tích chúng ta có gì trong file APK, để xem phần nào có thể tối ưu được và bằng cách nào:

  • classes.dex: Bao gồm mã nguồn đã biên dịch, được chuyển đưới dạng Dex bytecode. Bạn có thể nhìn thấy nhiều hơn 1 file DEX ở trong file APK nếu bạn sử dụng thuộc tính multidex. Trong phần 2 của bài viết này tôi sẽ trình bày phần Minifying code, gồm các cách để giảm dung lượng của mã dex.
  • res/: Folder này gồm tất cả các resource XML, drawables (PNG,JPEG) với các loại khác nhau từ mdpi, hdpi, sw600dp... cho tới resource ngôn ngữ. Lưu ý bất kì XMK file nào ở trong thư mục res/ đều được chuyển thành dạng nhỏ gọn hơn, là dạng nhị phân trong quá trình biên dịch, cho nên bạn không thể mở chúng bằng editor từ APK file. Để tối ưu res/, gồm nhiều phần như bỏ các resource không dùng đến, sử dụng product flavor để tối ưu resource cho từng bản, sử dụng multi APK để phân chia resource, tối ưu ảnh. Tôi sẽ trình bày các phương pháp này trong phần 3 Removing unused resources, phần 4 Multi APK, ABI and density splits, phần 5 Multi APK throught product flavors, phần 6 Image optimization, phần 7 Image optimization, Shape, and VectorDrawbles.
  • resources.arsc: Một số tài nguyên và định nghĩa được biên dịch và lưu trữ ở đây. Các resource này lưu vào APK mà không cần nén để truy cập nhanh hơn lúc runtime. Tối ưu resources.arsc sẽ được trình bày trong phần 3.
  • AndroidManifest.xml: Tương tự với những XL resouce khác, file này cũng được chuyển thành dạng nhị phân. File Manifest sau khi đã biên dịch vẫn có thể kiểm tra các thành phần trong nó bằng lệnh sau:
$ aapt dump badging your_app.apk
  • libs/: Các file của thư viện native (file có đuôi *.so) được lưu vào thư mục con của libs/ như x86, x86_64...Thông thường, chúng được sao chép từ APK file đến thư mục /data trong lúc cái đặt. Tuy nhiên, bản thân file APK không thể mở rộng được trên thiết bị của người dùng nên nó sẽ cần gấp 2 lần không gian để lưu trữ tài nguyên này, một phần để lưu tài nguyên gốc, phần nữa để lưu phần sao chép. Trong phần 8 của loạt bài này (native library, open from APK), tôi sẽ trình bày giải pháp để tối ưu thư viện native trên Android 6.0+, với lợi ích thêm là tiết kiệm bandawidth internet trên những thiết bị có API cũ hơn.

  • assets/: Thư mục này được dùng cho tấ cả fle asset không thuộc dạng Android resource. Phần lớn điểm chung của chúng là file font, file dữ liệu của game như levels game, texture... và dữ liệu mà bạn muốn sử dụng trực tiếp như file stream.

  • META-INF: Thư mục này có ở trong file APK đã sign, nó bao gồm các danh sách file trong APK và chữ kí của chúng. Cách xác thực chữ kí ở rong Android hiện tại là xác thực từng file một, dùng file đã nén và chữ kí của chúng trong thư mục META-INF. Việc này kéo theo hệ quả hay ho sau: bởi vì mỗi thành phần trong file ZIP được lưu riêng rẽ nên nếu bạn thay đổi level nén của từng file mà không cần kí lại, lúc này quá trình xác thực chữ kí sẽ xảy ra lỗi tuy nhiên nếu bạn xoá bất kì file nào trong ZIP file sau khi nó được kí thì xác thực vẫn thành công. Thêm một lưu ý nữa về việc kí ở file APK là zipalign tool được dùng ở bước cuối cùng trong quá trình build. Nếu bạn thay đổi nội dung của file APK bằng tay thì bạn sẽ phải kí lại sau đó zipalign trước khi upload file lên chợ ứng dụng.

Tiếp tục nén file APK dùng Zopfli

Có một cách đơn giản để giảm dung lượng APK xuống với thuật toán nén khá mạnh là Zipalign. Zipalign hỗ trợ nén file trong APK bằng Zipfli, một chương trình nén Deflate của Google (nó được sử dụng trong nén Zip). Khi bạn có fle APK cuối cùng, chỉ cần chạy lệnh sau với option -z:

$ zipalign -z 4 infile.apk outfile.apk

Nếu ngại dùng tool bạn có thể thêm dòng sau vào file build.gradle:

//add zopfli to variants with release build type
android.applicationVariants.all { variant ->
    if (variant.buildType.name == 'release') {
        variant.outputs.each { output ->
            output.assemble.doLast {
                println "Zopflifying... it might take a while"
                exec {
                    commandLine output.zipAlign.zipAlignExe,'-f','-z', '4', output.outputFile.absolutePath , output.outputFile.absolutePath.replaceAll('.apk$', '-zopfli.apk')
                }
            }
        }
    }
}

Được khuyên dùng bởi Zopfli sẽ mất thời gian một chút nhưng hi vọng có thể giảm dung lượng APK. Thời gian cài đặt và hiệu năng chạy thời gian thực sẽ không bị ảnh hưởng nhiều, bởi vì tốc độ giải nén của Zopfli khá tốt so với các thuật toán nén khác.

Reference

https://medium.com/google-developers/smallerapk-part-1-anatomy-of-an-apk-da83c25e7003#.klxo7ie96

Đón theo dõi tiếp phần 2 về các phương pháp tối ưu hoá code: Mififying code.

Enjoy your line!

0