建立和發布為 Android 應用

在一般的開發過程中,我們可以使用 flutter run 指令,或者 IntelliJ 工具欄中的 RunDebug 來測試 app。這時候,Flutter 預設會為我們建立 app 的除錯版本。

當想要發布 app 時,比如 發布到 Google Play Store,可以按照以下步驟來準備 Android 平台的 發布 版本。本頁面的內容包含如下主題:

新增啟動圖示

當我們建立一個新的 Flutter app 的時候,它會有一個預設的啟動圖示。要自定義這個圖示,可以參考使用 flutter_launcher_icons 這個 package。

或者,如果我們想手動操作,可以參考以下方法:

  1. 檢視 Material Design Product Icons 指南中圖示設計部分。

  2. <app dir>/android/app/src/main/res/ 目錄下,把我們的圖示檔案放在以 設定限定符 命名的資料夾中。類似預設的 mipmap- 資料夾這樣的命名方式。

  3. AndroidManifest.xml 中,更新 application 標籤中的 android:icon 屬性來引用上一步驟中我們自己的圖示檔案 (例如,<application android:icon="@mipmap/ic_launcher" ...)。

  4. flutter run 執行 app,檢查啟動程式中的 app 圖示是否已經替換成我們自己的圖示檔案。

啟用 Material 元件

如果你的應用使用了 平台檢視 (Platform Views),你可能要透過 Android 平台的入門指南文件 中的步驟使用 Material 元件:

舉個例子:

  1. <my-app>/android/app/build.gradle 檔案中新增 Android Material 元件依賴:

dependencies {
    // ...
    implementation 'com.google.android.material:material:<version>'
    // ...
}

檢視最新的版本,請訪問 Google Maven 倉庫

  1. <my-app>/android/app/src/main/res/values/styles.xml 檔案中設定亮色主題:

-<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
+<style name="NormalTheme" parent="Theme.MaterialComponents.Light.NoActionBar">
  1. Set the dark theme in <my-app>/android/app/src/main/res/values-night/styles.xml
-<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
+<style name="NormalTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar">

Sign the app

為 app 簽名

為了將你的應用發布到 Play 商店,你需要給你的應用進行數字簽名。

Android 應用需要兩個簽名:上傳簽名應用簽名

  • 開發者上傳到 Play Store 的 .aab.apk 需要有上傳簽名。

  • 終端使用者下載的 .apk 檔案需要有 應用簽名

請參考 Play Store 的官方文件 來建立你的應用簽名。

參考以下步驟對你的應用進行簽名。

建立一個用於上傳的金鑰函式庫

如果你已經有一個金鑰函式庫了,可以直接跳到下一步,如果還沒有,需要參考下面的方式建立一個:

  1. 參考文件 在 Android Studio 上為你的應用簽名

  2. 在指令行視窗執行如下的指令:

    在 macOS 或者 Linux 系統上,執行下面的程式碼:

    keytool -genkey -v -keystore ~/upload-keystore.jks -keyalg RSA \
            -keysize 2048 -validity 10000 -alias upload
    

    在 Windows 系統上,在 PoweShell 內執行以下程式碼:

    keytool -genkey -v -keystore %userprofile%\upload-keystore.jks ^
            -storetype JKS -keyalg RSA -keysize 2048 -validity 10000 ^
            -alias upload
    

    該指令將會把 upload-keystore.jks 檔案儲存在你的主檔案夾中。如果你想要儲存在其他地方,請透過指定 -keystore 傳入引數。 注意,請保證這個檔案的私有性,不要將它送出到公共的程式碼管理空間

從 app 中引用金鑰函式庫

建立一個名為 [project]/android/key.properties 的檔案,它包含了金鑰函式庫位置的定義。在替換內容時請去除 < > 括號:

storePassword=<password-from-previous-step>
keyPassword=<password-from-previous-step>
keyAlias=upload
storeFile=<keystore-file-location>

storeFile 金鑰路徑在 macOS 上類似於 /Users/<user name>/upload-keystore.jks,在 Windows 上類似於 C:\\Users\\<user name>\\upload-keystore.jks

在 gradle 中設定簽名

在以 release 模式下建立你的應用時,修改 [project]/android/app/build.gradle 檔案,以透過 gradle 設定你的上傳金鑰。

  1. android 程式碼區塊之前將你 properties 檔案的金鑰函式庫訊息新增進去:

       def keystoreProperties = new Properties()
       def keystorePropertiesFile = rootProject.file('key.properties')
       if (keystorePropertiesFile.exists()) {
           keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
       }
    
       android {
             ...
       }
    

    key.properties 檔案載入到 keystoreProperties 物件中。

  2. 找到 buildTypes 程式碼區塊:

       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.debug
           }
       }
    

    將其替換為我們的設定內容:

       signingConfigs {
           release {
               keyAlias keystoreProperties['keyAlias']
               keyPassword keystoreProperties['keyPassword']
               storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
               storePassword keystoreProperties['storePassword']
           }
       }
       buildTypes {
           release {
               signingConfig signingConfigs.release
           }
       }
    

現在我們 app 的發布版本就會被自動簽名了。

有關應用簽名的更多訊息,請檢視 developer.android.com 的 為你的應用設定簽名

使用 R8 壓縮你的程式碼

R8 是谷歌推出的最新程式碼壓縮器,當你打包 release 版本的 APK 或者 AAB 時會預設開啟。要關閉 R8,請執行 flutter build apkflutter build appbundle 時加上 --no-shrink 引數。

啟用 multidex 支援

當你在編寫較大的應用或使用體量較大的外掛時,你可能會在最低的 API 目標版本低於 20 時,遇到 Android 的 dex 的 64k 方法數限制問題。當 flutter run 以除錯模式執行應用時,由於縮減機制沒有執行,該問題也有可能發生。

Flutter tool supports easily enabling multidex. The simplest way is to opt into multidex support when prompted. The tool detects multidex build errors and asks before making changes to your Android project. Opting in allows Flutter to automatically depend on androidx.multidex:multidex and use a generated FlutterMultiDexApplication as the project’s application.

When you try to build and run your app with the Run and Debug options in your IDE, your build might fail with the following message:

screenshot of build failure because Multidex support is required

To enable multidex from the command line, run flutter run --debug and select an Android device:

screenshot of selecting an Android device

When prompted, enter y. The Flutter tool enables multidex support and retries the build:

Flutter 工具支援以便捷的方式啟用 multidex 支援。當工具提示你需要支援時,跟隨工具的指示進行調整,是最快的方式。 Flutter 工具會檢測 multidex 的建立錯誤,並提示你是否要更改 Android 專案。在同意的情況下,專案會自動依賴 androidx.multidex:multidex,並且讓專案的 Application 繼承於 FlutterMultiDexApplication

你也可以根據 Android 的指南,手動設定你的 Android 專案以支援 multidex。請務必指定 multidex keep 檔案 以包含以下內容:

io/flutter/embedding/engine/loader/FlutterLoader.class
io/flutter/util/PathUtils.class

同時也要包含所有在應用啟動時載入的其他類。參考 multidex 文件 瞭解更詳細的手動適配指南。

檢查 app manifest 檔案

檢查位於 [project]/android/app/src/main 的預設 App Manifest 檔案 AndroidManifest.xml,並確認各個值都設定正確,特別是:

application
編輯 application 標籤中的 android:label 來設定 app 的最終名字。

uses-permission
如果你的程式碼需要網際網路互動,請加入 android.permission.INTERNET 許可權標籤。標準開發模版裡並未加入這個許可權(但是 Flutter debug 模版加入了這個許可權),加入這個許可權是為了允許 Flutter 工具和正在執行的 app 之間的通訊。

Reviewing the Gradle build configuration

檢查位於 [project]/android/app 的預設 Gradle 建立檔案 (build.gradle) 並確認各個值都設定正確:

defaultConfig 設定中

applicationId
指定唯一的 應用 ID

minSdkVersion
指定應用適配的 最低 SDK API 版本。預設為 flutter.minSdkVersion

targetSdkVersion
指定應用適配的目標 SDK 版本。預設為 flutter.targetSdkVersion

versionCode
用於 內部版本號 的正整數。該數字僅用於比較兩個版本間數字較大的為更新版本。該版本不會對使用者展示。

versionName
向用戶展示的版本號。該欄位必須設定為原始字串或字串資源的引用。

buildToolsVersion
The Gradle plugin specifies the default version of the build tools that your project uses. You can use this option to specify a different version of the build tools.

buildToolsVersion
指定你的專案使用的建立工具的版本。你也可以手動指定不同的建立工具的版本。

android 設定中

compileSdkVersion
指定 Gradle 用於編譯應用的 API 版本。預設為 flutter.compileSdkVersion

更多訊息可以參考 Gradle 建立檔案 文件中模組級建立的部分。

建立生產版本應用

當要發布到 Play Store 時,你有兩種發布方式的選擇:

  • App bundle (推薦)

  • APK

建立一個 app bundle

這個部分描述瞭如何建立一個發布的 app bundle。如果在前面的部分已經完成了簽名步驟,發布的 bundle 會被簽名。這時你也許想要 混淆你的 Dart 程式碼 以加大反編譯難度。混淆你的程式碼需要在 build 的時候新增一些標誌,並維護其他檔案以消除反編譯的堆疊跟蹤。

使用如下指令:

  1. 執行 cd [project]

  2. 執行 flutter build appbundle。 (執行 flutter build 預設建立一個發布版本。)

你的應用的 release bundle 會被建立到 <app dir>/build/app/outputs/bundle/release/app.aab.

此 app bundle 會預設地包含為 armeabi-v7a (ARM 32-bit)、arm64-v8a (ARM 64-bit) 以及 x86-64 (x86 64-bit) 編譯的 Dart 和 Fluter 執行時程式碼。

測試 app bundle

一個 app bundle 可以用多種方法測試,這裡介紹兩種。

離線使用 bundle tool

  1. 如果你還沒準備好,可以從 GitHub 倉庫 下載 bundletool

  2. 從你的 app bundle 生成 APKs

  3. 將這 APKs 部署到 已連線的裝置。

線上使用 Google Play

  1. 上傳你的 bundle 到 Google Play 去測試它。或者在正式發布之前用 alpha 或 beta 頻道去測試。

  2. 按照 這些步驟把你的 bundle 上傳到 Play Store。

建立一個 APK

雖然 app bundle 比 APKs 更被推薦使用,但是有一些 Store 目前還不支援 app bundle方式。這種情況下,要為各種目標 ABI (Application Binary Interface) 分別建立發布的 APK 檔案。

如果你完成簽名步驟,APK 就被簽名了。這時你也許想要 混淆你的 Dart 程式碼 以加大反編譯難度。混淆你的程式碼需要在建立時新增一些引數。

使用如下指令:

  1. 輸入指令 cd [project]

  2. Run flutter build apk --split-per-abi.

    執行 flutter build apk --split-per-abi
    flutter build 預設帶有 --release 引數。)

這個指令會生成如下三個 APK 檔案

  • [project]/build/app/outputs/apk/release/app-armeabi-v7a-release.apk
  • [project]/build/app/outputs/apk/release/app-arm64-v8a-release.apk
  • [project]/build/app/outputs/apk/release/app-x86_64-release.apk

如果移除 --split-per-abi 將會生成一個包含 所有 目標 ABI 的 fat APK 檔案。這種 APK 檔案將會在比單獨建立的 APK 檔案尺寸要大,會導致使用者下載一些不適用於其裝置架構的二進位檔案。

在裝置上安裝 APK 檔案

按照如下這些步驟,將前一步中建立出來的 APK 安裝到 Android 裝置上。

使用如下指令:

  1. 用 USB 線將 Android 裝置連線到電腦上;

  2. 輸入指令 cd [project]

  3. 執行 flutter install

發布到 Google Play Store

要了解如何發布一個 app 到 Google Play Store,可以參考 Google Play 發布文件

更新應用版本號

每個應用預設的初始版本號是 1.0.0。若要更新它,請轉到 pubspec.yaml 檔案並更新以下內容:

version: 1.0.0+1

版本號由三個點分隔的數字組成,例如上面範例中的 1.0.0。然後是可選的建立號,例如上面範例中的 1,以 + 分隔。

版本號與建立號都可以在 Flutter 打包時分別使用 --build-name--build-number 重新指定。

在 Android 中,build-number 被用作 versionCodebuild-name 將作為 versionName 使用。更多訊息請參考 Android 文件中的 為你的應用新增版本

當重新建立 Android 應用後,任何在 pubspec 檔案所做的版本號更新,都將會更新 local.properties 檔案中的 versionNameversionCode

Android 發布常見問題

這裡是一些關於 Android 應用發布的常見問題。

我應該什麼時候建立 app bundles 而不是 APKs?

Google Play Store 相對於 APKs 更建議你發布 app bundles,因為那樣應用會更有效率地交付給你的使用者。但是,如果你想將應用發布到其他的應用商店,APK可能是唯一選項。

什麼是 fat APK?

一個 fat APK 是一個包含了支援多個 ABI 架構的 APK 檔案。這樣做的好處是單個 APK 可以執行在多個架構上,因此具有更廣泛的相容性。但同時缺點就是檔案體積會比較大,導致使用者在安裝你的應用時會下載和儲存更多的位元組。當建立 APK 而不是 app bundles 時強烈建議分開建立 APK,如 build an APK 所描述的那樣,使用 --split-per-abi 指令。

哪些目標架構是被支援的?

當使用 release 模式建立你的應用時, Flutter app 可以基於 armeabi-v7a (ARM 32 位)、 arm64-v8a (ARM 64 位) 以及 x86-64 (x86 64 位) 被編譯。 Flutter 目前支援透過 ARM 模擬 x86 Android。

如何為一個使用 flutter build appbundle 建立的 app bundle 簽名?

請檢視 建立一個金鑰函式庫

如何使用 Android Studio 建立一個發布?

在Android Studio中, 開啟你的 app 資料夾下的 android/ 資料夾. 然後在專案面板中選擇 build.gradle (Module: app) :

screenshot of gradle build script menu

接下來,選擇建立變體。在主選單中點擊 Build > Select Build Variant。從 Build Variants 面板中選擇任意一個變體(預設是 debug)。

screenshot of build variant menu

生成的 app bundle 或 APK 檔案會在你的 app 所在資料夾下的 build/app/outputs 資料夾下。