關於Flutter打包,你須要知道的基礎配置和包體積優化策略?

Hi~ 豆皮粉們!最近在學什麼,變厲害了沒?今回就請你們來讀讀由字節跳動的「saucxs」 精心製做的《Flutter打包的基礎配置和包體積優化策略》,漲漲跨端領域的知識,在你的前端「全棧」化的大路上走上一小步。html

圖片

做者:saucxs  | songEagle前端

來源:原創java

前言

讀者朋友們,大家有沒有遇到過快樂地用 flutter 項目開發完,該上線了,但你對打包過程不熟悉,遇到大大小小問題的時候?來看看我這個過來人怎麼打包加優化的吧。android

圖片

1、背景

在本地開發中,使用flutter run命令仍是 Android studio 運行或者調試,flutter 構建的是 debug 版本,也就是本地調試右上角出現 debug 標誌。git

當本地調試 OK 後,準備 release 版本,好比發佈到應用商城,或者交付用戶使用。shell

2、前期檢查工做

一、檢查AndroidManifest配置

查看<app root>/android/app/src/main/中的AndroidManifest.xml文件,並驗證這些屬性是否正確,特別是:緩存

•application 屬性,這是應用的名稱。•uses-permission 屬性,啓用 flutter 工具和 app 應用進行通訊,默認是開啓,若是不開啓,直接刪除該屬性這一行。markdown

二、查看構建配置

查看<app root>/android/app/build.gradle,驗證這些屬性是否正確:架構

•defaultConfig 屬性•applicationId:制定始終惟一的 appid。•versionCode && versionName:app 應用版本號和版本號字符串。•minSdkVersion && targetSdkVersion:指定最低的 API 級別以及應用程序設計運用的 API 級別。app

三、app簽名

建立 keystore 。若是以前已經建立過 keystore,那就跳過本步驟直接看 四、應用中引入keystore

建立一個keystore,執行命令:

For more details, please visit https://support.apple.com/kb/HT208050.
yourMacBook-Pro:~ username$ keytool -genkey -v -keystore ~/key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias key
複製代碼

生成的文件是 key.jks 默認文件地址:/Users/<你電腦名稱>/key.jks

注意:密鑰是私密文件,不要加到git中。

下面是詳細的執行過程

Last login: Mon Nov  2 14:17:41 on ttys005
The default interactive shell is now zsh.
To update your account to use zsh, please run `chsh -s /bin/zsh`.
For more details, please visit https://support.apple.com/kb/HT208050.
yourMacBook-Pro:~ username$ keytool -genkey -v -keystore ~/key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias key
輸入密鑰庫口令:  
再次輸入新口令: 
它們不匹配。請重試
輸入密鑰庫口令:  
再次輸入新口令: 
您的名字與姓氏是什麼?
  [Unknown]:  C
您的組織單位名稱是什麼?
  [Unknown]:  byte
您的組織名稱是什麼?
  [Unknown]:  byte
您所在的城市或區域名稱是什麼?
  [Unknown]:  nj
您所在的省/市/自治區名稱是什麼?
  [Unknown]:  nj
該單位的雙字母國家/地區代碼是什麼?
  [Unknown]:  cn
CN=C, OU=byte, O=byte, L=nj, ST=nj, C=cn是否正確?
  [否]:  y
正在爲如下對象生成 2,048 位RSA密鑰對和自簽名證書 (SHA256withRSA) (有效期爲 10,000 天):
         CN=C, OU=byte, O=byte, L=nj, ST=nj, C=cn
輸入 <key> 的密鑰口令
        (若是和密鑰庫口令相同, 按回車):  
再次輸入新口令: 
[正在存儲/Users/username/key.jks]
Warning:
JKS 密鑰庫使用專用格式。建議使用 "keytool -importkeystore -srckeystore /Users/username/key.jks -destkeystore /Users/username/key.jks -deststoretype pkcs12" 遷移到行業標準格式 PKCS12。
yourMacBook-Pro:~ username$
複製代碼

四、應用中引入keystore

<app dir>/android下新建 key.properties 的文件,其中包含對密鑰庫的引用:

storePassword=<你輸入的密碼>
keyPassword=<你輸入的密碼>
keyAlias=key
storeFile=/Users/<你電腦名稱>/key.jks
複製代碼

五、在構建配置中添加簽名

<app dir>/android/app/build.gradle文件作修改:

// ...
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
// 新增的內容
def keystorePropertiesFile = rootProject.file("key.properties")
def keystoreProperties = new Properties()
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
android {
    compileSdkVersion 28
// ...
// ...
    defaultConfig {
        // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
        applicationId "com.example.flutter_tester"
        minSdkVersion 18
        targetSdkVersion 28
        versionCode flutterVersionCode.toInteger()
        versionName flutterVersionName
    }
    // 新增內容 這塊就是從
    signingConfigs {
        release {
            keyAlias keystoreProperties['keyAlias']
            keyPassword keystoreProperties['keyPassword']
            storeFile file(keystoreProperties['storeFile'])
            storePassword keystoreProperties['storePassword']
        }
    }
    // 新增內容
    buildTypes {
        release {
            // TODO: Add your own signing config for the release build.
            // Signing with the debug keys for now, so `flutter run --release` works.
            signingConfig signingConfigs.release
        }
    }
複製代碼

如今應用打包的 release 版本將自動進行簽名。

3、打包命令

而後執行打包命令,構建發佈版(release)APK。若是您完成了前一節中的簽名步驟,則會對APK進行簽名。

使用命令行:

cd <app dir> (<app dir> 爲您的工程目錄).
運行flutter build apk (flutter build 默認會包含 --release選項).
複製代碼

打包好的發佈APK位於<app dir>/build/app/outputs/apk/app-release.apk

4、包體積優化策略

步驟三執行完,打包的這個過程就結束了,但爲了追求極致,咱們會發現打包以後體積有點大。

下一步,咱們來分析一下這個 APK 包的構成,咱們主要來看不混淆的狀況下。

圖片

通常靜態資源文件佔有大量內存,咱們發現圖片在 apk 佔比爲 80% + 0% = 80%

•Flutter 引用資源(assets 文件夾) 80% •Android 啓動頁背景和 app 的 logo(res 文件夾) 0%

主要是由於用了大量的圖片,而且沒有設置 Android 啓動頁背景和 app 的 logo。

(一)圖片和代碼優化

一、處理圖片資源使用外部服務

與其將圖像資產捆綁在應用程序內,不如將圖像託管在諸如 firebase 之類的外部服務上,並使用包cached_network_image 在應用程序內調用這些圖像。在首次啓動應用程序時,程序包會從提供的URL 中獲取圖像並對其進行緩存,所以您在隨後使用該應用程序時會獲得一個緩存的圖像,所以這些圖像不佔用下載空間,由於它們沒有捆綁在應用程序內。

二、壓縮 png 和 jpg

若是有的圖片不想從外部主機獲取,必須從本地獲取,所用的圖片必須壓縮 png 和 jpg,由於高質量的 png 和 jpg 會佔用應用程序的大小。

三、使用 svg 格式圖標

咱們儘可能使用矢量圖 svg,而不是使用 png,由於 svg 能夠兼容不一樣的 dpi 設備,而且能減小 apk 大小。

四、去掉未使用的包

在 pubspec.yaml 文件中不須要或者根本沒有使用的庫或者包。

五、特殊字體使用 http 緩存方式

字體也是程序大小的一個緣由,當 UX 須要使用特定的字體,咱們能夠不用把字體文件,好比 *.ttf或者 .otf 文件存儲在應用程序中,而後映射到pubspec.yaml文件中,咱們能夠經過http獲取一次,並緩存到應用程序的文件系統中。

六、使用 proguard 優化器

proguard 是 java 的優化器,優化器不會改變表現形式而且使用更緊湊的方式優化代碼。proguard 混淆原始名稱無所謂的類型,字段,方法名稱,將長命名字符串替換爲短字符串,好比換成a,b,c 以提升效率。然而包和類的名稱可能很長,可是不會影響效率。

咱們在<app dir> /android/app/build.gradle中的構建類型與如下所示相似:

buildTypes { 
        release { 
            minifyEnabled true //添加proguard
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'   //添加proguard
            signingConfig signingConfigs.release     //這是發佈的默認值
        } 
    }
複製代碼

在同一目錄中,建立文件proguard-rules.pro並添加如下代碼:

## Flutter wrapper 
 -keep class io.flutter.app.** { *; }
 -keep class io.flutter.plugin.** { *; }
 -keep class io.flutter.util.** { *; }
 -keep class io.flutter.view.** { *; }
 -keep class io.flutter.** { *; }
 -keep class io.flutter.plugins.** { *; }
# -keep class com.google.firebase.** { *; } // uncomment this if you are using firebase in the project
 -dontwarn io.flutter.embedding.**
 -ignorewarnings
複製代碼

最後咱們在 gradle.properties 文件中添加:

extra-gen-snapshot-options=--obfuscate
複製代碼

七、shrinkResources 去掉無用代碼

在 build.gradle 中

buildTypes {
        release {
            minifyEnabled true // added previously
            shrinkResources true // add this
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' // added previously
            signingConfig signingConfigs.release // added previously
        }
    }
複製代碼

PS:使用 shrinkResource 和 proguard 優化器,優化後,體積減小了0.1MB。

圖片

從147.0MB減小到146.9MB,減小的太少了。

(二)so優化

針對 Flutter 打出的 Apk 包,排在第二位的是lib,28.7MB,佔19.7%

將咱們編寫的 Dart 代碼轉化爲不一樣架構下的 so 庫,以供原生調用。

針對不一樣 CPU 架構所表明含義:

•x86_64:Intel 64 位,通常用於平板或者模擬器,支持 x86 以及 x86_64 CPU 架構設備。•arm64-v8a:第 8 代 64 位,包含 AArch3二、AArch64 兩個執行狀態,且對應 32 、64 bit,而且支持 armeabi、armeabi-v7a 以及 arm64-v8a。•armeabi-v7a:第 7 代 arm v7,使用硬件浮點運算,具備高級拓展功能,兼容 armeabi 以及 armeabi-v7a,並且目前大部分手機都是這個架構。

咱們經過如下不一樣命令分別打包,構建制定的CPU架構的APK包,

flutter build apk --target-platform android-arm,android-arm64,android-x64 --split-per-abi
複製代碼

咱們來解釋一下這個:

•flutter build apk 表示當前構建 release 包。•後面 android-arm,andriod-arm64,andriod-x64 則表示生成制定的架構的 release 包。•最後--split-per-abi 則表示按照不一樣架構分別打包,若是移除就包含全部 CPU 架構的 apk 包。

圖片

看看 app-armeabi-v7a-release.apk 包大小 126.2MB,爽啊,由 146.9 MB 直接減小到 126.2 MB。

咱們看下對應的 apk 內容:

圖片

lib 佔比也從原來的 19.7%,28.7 MB 直接減小爲 6.4%,8 MB。

(三)混淆優化

Flutter 也爲咱們提供了混淆命令:

flutter build apk --obfuscate --split-debug-info=/<project-name>/<directory>
複製代碼

簡單說明一下:

•--obfuscate:開啓混淆開關。•--split-debug-info:混淆生成的map符號表緩存到此位置。

咱們先測試一下,構建完整的apk的大小。

執行

flutter build apk --obfuscate --split-debug-info=splitMap
複製代碼

圖片

大小從 146.9MB 降到 145.9MB,減小了1MB。

在項目根目錄下生成了符號文件:

圖片

咱們再試一下,直接針對不一樣 CPU 生成對應的 Apk 並添加混淆結果。

flutter build apk --obfuscate --split-debug-info=/<project-name>/<directory> --target-platform android-arm,android-arm64,android-x64 --split-per-abi
複製代碼

咱們執行:

flutter build apk --obfuscate --split-debug-info=splitMap --target-platform android-arm,android-arm64,android-x64 --split-per-abi
複製代碼

圖片

未混淆的 v7a 大小與開啓混淆相比,126.2MB 減小到 125.9MB 。開啓混淆減小了 0.3 MB。

以爲差異不大。

5、總結

一旦打包的基礎配置完過後,基本上不用怎麼改,優化配置完過後,須要一個優化的打包命令。

以爲這是一個比較有用的打包命令:

flutter build apk --obfuscate --split-debug-info=splitMap --target-platform android-arm,android-arm64,android-x64 --split-per-abi
複製代碼

•不一樣CPU結構分別打包 •要混淆,生產的字符串Map在splitMap文件夾中

The     End

相關文章
相關標籤/搜索