Flutter Notes|Flutter-Apk 大小優化探索

靜心Study發表於2020-07-09

追逐,探索,永不停歇~

在這裡插入圖片描述

前言

還記得剛入坑 Flutter 打包時,被深深震驚了一番,臥槽,這包好大!

  • ✓ Built build/app/outputs/apk/release/app-release.apk (23.8MB).

Flutter Notes|Flutter-Apk 大小優化探索

足足將近 24 MB,第一反應真的懵逼了。

當然直接提交市場後,也是被人各種 diss,原因還是沒什麼功能,包賊大,使用者下載賊不舒服。

強烈要求優化 Apk 大小。

Flutter Notes|Flutter-Apk 大小優化探索

既然是探索,前提我還是個剛入 Flutter 坑的小白白,所以嘛,難免不全面,歡迎各位大佬拍磚、指點~

探索之路 一部曲

首先,我首次打包的方式如下:

Flutter Notes|Flutter-Apk 大小優化探索

雷同使用下面的命令(預設帶有 --release):

  • flutter build apk

一、熊貓壓縮法(減少 0.7 MB)

首先第一想法,圖片我沒做壓縮,同樣經過檢視後,發現圖片在 apk 佔比為 4.1% :

  • 2.3 % Flutter 引用到的資原始檔;
  • 1.8% Android 啟動頁的背景圖。

最後,我們通過國寶之手試試最後能減少多少?

這裡分別針對 Flutter 下圖片資源、Android/iOS 啟動頁進行壓縮。

再次執行 build apk 後,完成輸出如下日誌:

  • ✓ Built build/app/outputs/apk/release/app-release.apk (23.1MB).

再來看 Apk 中圖片的佔比以及降低到 1%:

Flutter Notes|Flutter-Apk 大小優化探索

最終 Apk 大小直接減少了 0.7 MB,還是比較爽的。

二、so 優化大法(減少 14 MB)

做 Android 的小夥伴知道,對於我們這些小廠沒能力搞動態下發 so 的小渣渣而言,只能默默逆向大廠 Apk,看看人家是怎麼做的,然後借(抄)鑑(襲)。

針對 Flutter 打出的 Apk 包,排在第一位的便是 lib,佔比 86.4%,足足有 19.6 MB:

Flutter Notes|Flutter-Apk 大小優化探索

這裡看到將我們編寫的 Dart 程式碼轉化為不同架構下的 so 庫,以供原生呼叫(我是這麼猜測的哈)。

針對不同 CPU 架構所代表含義,尤其 Flutter 打包 Apk 生成的三種 CPU 架構分別對應什麼含義:

  • x86_64: Intel 64 位,一般用於平板或者模擬器,支援 x86 以及 x86_64 CPU 架構裝置。
  • arm64-v8a: 第 8 代 64 位,包含 AArch32、AArch64 兩個執行狀態,且對應 32 、64 bit,並且支援 armeabi、armeabi-v7a 以及 arm64-v8a。
  • armeabi-v7a: 第 7 代 arm v7,使用硬體浮點運算,具有高階擴充功能,相容 armeabi 以及 armeabi-v7a,而且目前大部分手機都是這個架構。

其實我們第一次通過 flutter build apk 命令生成 apk 時,Google 這裡已經為我們提示了:

 heliquan@Mac  ~/CodePro/FlutterPro/xxx_app master ● flutter build apk
You are building a fat APK that includes binaries for android-arm, android-arm64, android-x64.
If you are deploying the app to the Play Store, it's recommended to use app bundles or split the APK to reduce the APK size.
    To generate an app bundle, run:
        flutter build appbundle --target-platform android-arm,android-arm64,android-x64
        Learn more on: https://developer.android.com/guide/app-bundle
    To split the APKs per ABI, run:
        flutter build apk --target-platform android-arm,android-arm64,android-x64 --split-per-abi
        Learn more on:  https://developer.android.com/studio/build/configure-apk-splits#configure-abi-split                                        
Running Gradle task 'assembleRelease'...                                
Running Gradle task 'assembleRelease'... Done                      13.8s
✓ Built build/app/outputs/apk/release/app-release.apk (23.1MB).
複製程式碼

接下來通過以下命令進行分別打包(構建指定 CPU 架構型別 Apk 包):

  • flutter build apk --target-platform android-arm,android-arm64,android-x64 --split-per-abi

這裡解釋下這個命令的含義:

  • 首先 flutter build apk 表示當前構建 release 包;
  • 後面 android-arm,android-arm64,android-x64 則是指定生成對應架構的 release 包;
  • 最後的 --split-per-abi 則表示告知需要按照我們指定的型別分別打包,如果移除則直接構建包含所有 CPU 架構的 Apk 包。

所以這個命令的含義就是告訴編譯器,我需要你為我針對我指定的三種不同架構分別生成對應的 Apk 包。

有的小夥伴就說了,你這空口無憑,沒證據啊。

好,我給你執行一波~

  • 驗證:flutter build apk --target-platform android-arm,android-arm64,android-x64 結果
 heliquan@Mac  ~/CodePro/FlutterPro/xxx_app   master ●  flutter build apk --target-platform android-arm,android-arm64,android-x64                
You are building a fat APK that includes binaries for android-arm, android-arm64, android-x64.
If you are deploying the app to the Play Store, it's recommended to use app bundles or split the APK to reduce the APK size.
    To generate an app bundle, run:
        flutter build appbundle --target-platform android-arm,android-arm64,android-x64
        Learn more on: https://developer.android.com/guide/app-bundle
    To split the APKs per ABI, run:
        flutter build apk --target-platform android-arm,android-arm64,android-x64 --split-per-abi
        Learn more on:  https://developer.android.com/studio/build/configure-apk-splits#configure-abi-split                                        
Removed unused resources: Binary resource data reduced from 817KB to 815KB: Removed 0%
Running Gradle task 'assembleRelease'...                                
Running Gradle task 'assembleRelease'... Done                     115.8s
✓ Built build/app/outputs/apk/release/app-release.apk (23.1MB).
複製程式碼

看見沒,事實論證結果。

最後,我們採取告知編譯器為我們生成指定 CPU 架構的 Apk 的方式,並檢視對應輸出日誌資訊:

 heliquan@Mac  ~/CodePro/FlutterPro/xxx_app   master ●  flutter build apk --target-platform android-arm,android-arm64,android-x64 --split-per-abi                                         
Removed unused resources: Binary resource data reduced from 816KB to 814KB: Removed 0%
Removed unused resources: Binary resource data reduced from 816KB to 814KB: Removed 0%
Removed unused resources: Binary resource data reduced from 816KB to 814KB: Removed 0%
Running Gradle task 'assembleRelease'...                                
Running Gradle task 'assembleRelease'... Done                      36.0s
✓ Built build/app/outputs/apk/release/app-armeabi-v7a-release.apk (9.8MB).
✓ Built build/app/outputs/apk/release/app-arm64-v8a-release.apk (10.1MB).
✓ Built build/app/outputs/apk/release/app-x86_64-release.apk (10.2MB).
複製程式碼

看看 app-armeabi-v7a-release.apk 包大小,結果是不是賊喜人?由 23.8 MB 直接減少到 9.8 MB。

隨後我們看下對應的 apk 內容:

Flutter Notes|Flutter-Apk 大小優化探索

lib 佔比也從原來的 86.4%,19.6 MB 直接減少為 67.2%,大小 6.3 MB。

Flutter Notes|Flutter-Apk 大小優化探索

三、混淆大法好(減少 0.4 MB)

還記得 Android 混淆的魅力嗎?

  • 增加逆向難度;
  • 減少 Apk 大小;
  • 。。。

對此 Flutter 也為我們提供了混淆命令:

  • flutter build apk --obfuscate --split-debug-info=//

簡單說下我個人對於此命令的理解:

  • --obfuscate:開啟混淆操作;
  • --split-debug-info=:將因混淆生成的 map 符號表快取到此位置。

這裡我們先測試下,直接構建完整包,並新增混淆操作,輸出的 apk 大小有多少:

 heliquan@Mac  ~/CodePro/FlutterPro/xxx_app   master ●  flutter build apk --obfuscate --split-debug-info=HLQ_Struggle
You are building a fat APK that includes binaries for android-arm, android-arm64, android-x64.
If you are deploying the app to the Play Store, it's recommended to use app bundles or split the APK to reduce the APK size.
    To generate an app bundle, run:
        flutter build appbundle --target-platform android-arm,android-arm64,android-x64
        Learn more on: https://developer.android.com/guide/app-bundle
    To split the APKs per ABI, run:
        flutter build apk --target-platform android-arm,android-arm64,android-x64 --split-per-abi
        Learn more on:  https://developer.android.com/studio/build/configure-apk-splits#configure-abi-split                                        
Running Gradle task 'assembleRelease'...                                
Running Gradle task 'assembleRelease'... Done                      60.3s
✓ Built build/app/outputs/apk/release/app-release.apk (21.9MB).
複製程式碼

同樣也在專案根目錄下生成了符號檔案:

Flutter Notes|Flutter-Apk 大小優化探索

相比一開始的 23.8 MB,減少了 1.9 MB。那麼我們直接針對不同 CPU 生成對應的 Apk 並新增混淆結果又是怎樣呢?

➜  xxx_app git:(master) ✗ flutter build apk --obfuscate --split-debug-info=debugInfo  --target-platform android-arm,android-arm64,android-x64 --split-per-abi                                       
Running Gradle task 'assembleRelease'...                                
Running Gradle task 'assembleRelease'... Done                      39.3s
✓ Built build/app/outputs/apk/release/app-armeabi-v7a-release.apk (9.4MB).
✓ Built build/app/outputs/apk/release/app-arm64-v8a-release.apk (9.7MB).
✓ Built build/app/outputs/apk/release/app-x86_64-release.apk (9.8MB).
複製程式碼

未混淆的 v7a 大小與開啟混淆相比,開啟混淆減少了 0.4 MB。

還不錯。

對於混淆的檔案,出問題怎麼除錯呢?

莫慌,Flutter 同樣提供了 symbolize 神器,當然這個不在涉獵範圍內,就不詳細解釋了,知道就好:

heliquan@Mac  ~/CodePro/FlutterPro/haozhuan_app   master ●  flutter symbolize -h
Symbolize a stack trace from an AOT compiled flutter application.

Usage: flutter symbolize [arguments]
-h, --help                                                                     Print this usage information.
-d, --debug-info=</out/android/app.arm64.symbols>                              A path to the symbols file generated with "--split-debug-info".
-i, --input=</crashes/stack_trace.err>                                         A file path containing a Dart stack trace.
-o, --output=<A file path for a symbolicated stack trace to be written to.>    

Run "flutter help" to see global options.
複製程式碼

End

上面叨叨半天,總結一個比較有用的命令:

  • flutter build apk --obfuscate --split-debug-info=HLQ_Struggle --target-platform android-arm,android-arm64,android-x64 --split-per-abi

含義就是,哥,幫我針對不同 CPU 架構分別打包,別忘記混淆哈,生成的符號表檔案記得幫我放在 HLQ_Struggle 目錄下。

詳細日誌如下:

 heliquan@Mac  ~/CodePro/FlutterPro/xxx_app   master ●   flutter build apk --obfuscate --split-debug-info=HLQ_Struggle --target-platform android-arm,android-arm64,android-x64 --split-per-abi                                          
Removed unused resources: Binary resource data reduced from 816KB to 814KB: Removed 0%
Removed unused resources: Binary resource data reduced from 816KB to 814KB: Removed 0%
Removed unused resources: Binary resource data reduced from 816KB to 814KB: Removed 0%
Running Gradle task 'assembleRelease'...                                
Running Gradle task 'assembleRelease'... Done                      36.9s
✓ Built build/app/outputs/apk/release/app-armeabi-v7a-release.apk (9.4MB).
✓ Built build/app/outputs/apk/release/app-arm64-v8a-release.apk (9.7MB).
✓ Built build/app/outputs/apk/release/app-x86_64-release.apk (9.8MB).
複製程式碼

當然也有小夥伴說了,打包前 clean 下,生成的包會小,實際測試一下:

 heliquan@Mac  ~/CodePro/FlutterPro/xxx_app   master ●  flutter clean           
Cleaning Xcode workspace...                                         3.3s
Deleting build...                                                2,774ms (!)
Deleting .dart_tool...                                              41ms
Deleting Generated.xcconfig...                                       0ms
Deleting flutter_export_environment.sh...                            0ms
Deleting App.framework...                                            9ms
 heliquan@Mac  ~/CodePro/FlutterPro/xxx_app   master ●   flutter build apk --obfuscate --split-debug-info=HLQ_Struggle --target-platform android-arm,android-arm64,android-x64 --split-per-abi                                          
Running Gradle task 'assembleRelease'...                                                                                                                                                  Removed unused resources: Binary resource data reduced from 816KB to 814KB: Removed 0%                             
Removed unused resources: Binary resource data reduced from 816KB to 814KB: Removed 0%                             
Removed unused resources: Binary resource data reduced from 816KB to 814KB: Removed 0%                             
Running Gradle task 'assembleRelease'...                                                                           
Running Gradle task 'assembleRelease'... Done                     215.3s (!)
✓ Built build/app/outputs/apk/release/app-armeabi-v7a-release.apk (9.4MB).
✓ Built build/app/outputs/apk/release/app-arm64-v8a-release.apk (9.7MB).
✓ Built build/app/outputs/apk/release/app-x86_64-release.apk (9.8MB).
複製程式碼

根據以上輸出結果,並沒發現減少了哪兒。

一點小經歷分享,當然肯定會有更好的操作方法,但是目前僅次於此,歡迎各位大佬交流~

Thanks

相關文章