建置與發佈 Android 應用程式
要測試應用程式,你可以在命令列使用 flutter run, 或在你的 IDE 中使用 Run 和 Debug 選項。
當你準備好要建立應用程式的 發佈 版本時, 例如要發佈到 Google Play 商店, 本頁將提供協助。在發佈之前, 你可能會想為應用程式做一些最後的修飾。 本指南將說明如何執行以下任務:
- 新增啟動器圖示
- 啟用 Material 元件 (Material components)
- 簽署應用程式
- 使用 R8 縮減程式碼
- 啟用 multidex 支援
- 檢查應用程式 manifest
- 檢查建置組態
- 建置發佈版應用程式
- 發佈到 Google Play 商店
- 更新應用程式版本號
- Android 發佈常見問答
新增啟動器圖示
#當你建立新的 Flutter 應用程式時,會有一個預設的啟動器圖示。 若要自訂這個圖示,你可以參考 flutter_launcher_icons 套件。
另外,你也可以依照以下步驟手動設定:
參閱 Material Design 產品圖示設計指引,了解圖示設計原則。
在
[project]/android/app/src/main/res/目錄下, 將你的圖示檔案放在以 設定限定詞命名的資料夾中。 預設的mipmap-資料夾展示了正確的 命名規則。在
AndroidManifest.xml中,更新application標籤的android:icon屬性,讓它參考前一步驟中的圖示(例如,<application android:icon="@mipmap/ic_launcher" ...)。為確認圖示已被替換, 請執行你的應用程式並檢查 Launcher 中的應用程式圖示。
啟用 Material 元件 (Material components)
#如果你的應用程式使用了 平台視圖 (platform views),你可能會想要依照 Android 入門指南中的步驟啟用 Material 元件 (Material components)。
例如:
在
<my-app>/android/app/build.gradle.kts中新增 Android Material 的相依套件:groovydependencies { // ... implementation("com.google.android.material:material:<version>") // ... }若要查詢最新版本,請造訪 Google Maven。
在
<my-app>/android/app/src/main/res/values/styles.xml中設定亮色主題:xml<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar"> <style name="NormalTheme" parent="Theme.MaterialComponents.Light.NoActionBar">在
<my-app>/android/app/src/main/res/values-night/styles.xml中設定深色主題:xml<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar"> <style name="NormalTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar">
簽署應用程式
#若要在 Play 商店(Play Store)發佈,您需要使用數位憑證簽署您的應用程式。
Android 會使用兩種簽署金鑰:上傳金鑰(upload key)與 應用程式簽署金鑰(app signing key)。
- 開發者需將以 上傳金鑰 簽署的
.aab或.apk檔案上傳至 Play 商店。 - 最終用戶會下載以 應用程式簽署金鑰 簽署的
.apk檔案。
如需建立您的應用程式簽署金鑰,請依照 官方 Play 商店文件 中所述,使用 Play App Signing。
如需簽署您的應用程式,請依照以下說明操作。
建立上傳 keystore
#如果您已有現有的 keystore,請跳至下一步。 若沒有,請使用下列其中一種方式建立:
依照 Android Studio 金鑰產生步驟 操作。
在命令列執行下列指令:
在 macOS 或 Linux 上,請使用以下指令:
keytool -genkey -v -keystore ~/upload-keystore.jks -keyalg RSA \ -keysize 2048 -validity 10000 -alias upload在 Windows 上,請在 PowerShell 中使用以下指令:
keytool -genkey -v -keystore $env:USERPROFILE\upload-keystore.jks ` -storetype JKS -keyalg RSA -keysize 2048 -validity 10000 ` -alias upload此指令會將
upload-keystore.jks檔案儲存在你的家目錄。如果你想將其儲存在其他位置,請更改傳遞給-keystore參數的引數。 不過,請務必將keystore檔案保密;不要將它提交到公開的原始碼控管系統!
從應用程式參考 keystore
#建立一個名為 [project]/android/key.properties 的檔案,內容包含對你的 keystore 的參考。 不要包含尖括號(< >)。 這些尖括號表示該文字僅為你的值的佔位符。
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 模式建置應用程式時,需要設定 Gradle 使用你的上傳金鑰(upload key)。 要設定 Gradle,請編輯 <project>/android/app/build.gradle.kts 檔案。
在
android屬性區塊之前,定義並載入 keystore 屬性檔案。設定
keystoreProperties物件以載入key.properties檔案。[project]/android/app/build.gradle.ktskotlinimport java.util.Properties import java.io.FileInputStream plugins { ... } val keystoreProperties = Properties() val keystorePropertiesFile = rootProject.file("key.properties") if (keystorePropertiesFile.exists()) { keystoreProperties.load(FileInputStream(keystorePropertiesFile)) } android { ... }在
android屬性區塊內,於buildTypes屬性區塊之前新增簽章(signing)設定。[project]/android/app/build.gradle.ktskotlinandroid { // ... signingConfigs { create("release") { keyAlias = keystoreProperties["keyAlias"] as String keyPassword = keystoreProperties["keyPassword"] as String storeFile = keystoreProperties["storeFile"]?.let { file(it) } storePassword = keystoreProperties["storePassword"] as String } } 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.getByName("debug") signingConfig = signingConfigs.getByName("release") } } ... }
Flutter 現在會為所有 release 版本進行簽章。
想進一步了解如何為你的應用程式簽章,請參考 Android 開發者文件中的 Sign your app。
使用 R8 壓縮你的程式碼
#R8 是 Google 推出的新一代程式碼壓縮工具。 當你建置 release APK 或 AAB 時,R8 會預設啟用。 若要停用 R8,請在執行 flutter build apk 或 flutter build appbundle 時加入 --no-shrink 旗標。
啟用 multidex 支援
#當你開發大型應用程式或使用大型插件時, 如果目標最低 API 為 20 或以下,可能會遇到 Android 的 64k 方法數限制。 在使用未啟用壓縮的 flutter run 執行應用程式的 debug 版本時,也可能遇到此限制。
Flutter 工具支援輕鬆啟用 multidex。 最簡單的方式是依照提示選擇啟用 multidex 支援。 工具會偵測到 multidex 建置錯誤,並在修改你的 Android 專案前詢問你。 選擇啟用後,Flutter 會自動依賴 androidx.multidex:multidex,並使用產生的 FlutterMultiDexApplication 作為專案的 application。
當你在 IDE 中使用 Run 和 Debug 選項嘗試建置並執行應用程式時,建置可能會失敗,並出現以下訊息:

若要從命令列啟用 multidex,請執行 flutter run --debug 並選擇一台 Android 裝置:

當系統提示時,請輸入 y。 Flutter 工具會啟用 multidex 支援並重新嘗試建置:

你也可以選擇依照 Android 官方指南手動支援 multidex, 並修改專案的 Android 目錄設定。 必須指定一個 multidex keep file,內容需包含:
io/flutter/embedding/engine/loader/FlutterLoader.class
io/flutter/util/PathUtils.class同時,也請包含應用程式啟動時所使用的其他類別。 如需手動新增 multidex 支援的詳細指引,請參考官方 Android documentation。
檢查 App Manifest
#請檢查預設的 App Manifest 檔案。
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:label="[project]"
...
</application>
...
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>請確認下列數值:
| 標籤 | 屬性 | 值 |
|---|---|---|
application | 編輯 application 標籤中的 android:label,以反映應用程式的最終名稱。 | |
uses-permission | 如果您的應用程式需要存取網際網路,請在 android:name 屬性中新增 android.permission.INTERNET permission 值。標準範本並未包含此標籤,但在開發期間允許網際網路存取,以便 Flutter 工具與執行中的應用程式進行通訊。 |
檢查或變更 Gradle 建置組態
#若要確認 Android 建置組態,請檢查預設 Gradle 建置腳本中的 android 區塊。 預設的 Gradle 建置腳本位於 [project]/android/app/build.gradle.kts。 您可以變更這些屬性的任何值。
android {
namespace = "com.example.[project]"
// Any value starting with "flutter." gets its value from
// the Flutter Gradle plugin.
// To change from these defaults, make your changes in this file.
compileSdk = flutter.compileSdkVersion
ndkVersion = flutter.ndkVersion
...
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId = "com.example.[project]"
// You can update the following values to match your application needs.
minSdk = flutter.minSdkVersion
targetSdk = flutter.targetSdkVersion
// These two properties use values defined elsewhere in this file.
// You can set these values in the property declaration
// or use a variable.
versionCode = flutterVersionCode.toInteger()
versionName = flutterVersionName
}
buildTypes {
...
}
}在 build.gradle.kts 中可調整的屬性
#| 屬性 | 目的 | 預設值 |
|---|---|---|
compileSdk | 您的應用程式所編譯的 Android API 等級。這應設為可用的最高版本。如果您將此屬性設為 31,只要您的應用程式未使用專屬於 31 的 API,即可在運行 API 30 或更早版本的裝置上執行。 | |
defaultConfig | ||
.applicationId | 最終且唯一的 application ID,用以識別您的應用程式。 | |
.minSdk | 您設計應用程式可運行的 最低 Android API 等級。 | flutter.minSdkVersion |
.targetSdk | 您測試應用程式可運行的 Android API 等級。您的應用程式應可在所有低於或等於此等級的 Android API 上運行。 | flutter.targetSdkVersion |
.versionCode | 設定 內部版本號 的正整數。此數值僅用於判斷哪個版本較新。數值越大代表版本越新。應用程式使用者不會看到此值。 | |
.versionName | 您的應用程式顯示的版本號字串。可設為原始字串或參考字串資源。 | |
.buildToolsVersion | Gradle 外掛指定專案所使用的 Android build tools 預設版本。若需指定不同版本的 build tools,請變更此值。 |
若需進一步瞭解 Gradle,請參閱 Gradle build file 中的模組層級 build 章節。
建立發行版應用程式
#當您要發佈至 Play 商店時,有兩種發行格式可選:
- App bundle(建議使用)
- APK
建立 app bundle
#本節說明如何建立發行版 app bundle。 如果您已完成簽署步驟, 則 app bundle 會被簽署。 此時,您可以考慮混淆您的 Dart 程式碼, 以增加逆向工程的難度。 混淆程式碼需在 build 指令中加入額外旗標, 並維護額外檔案以還原堆疊追蹤。
在命令列執行:
- 輸入
cd [project] - 執行
flutter build appbundle
(執行flutter build預設為發行版 build。)
您的應用程式發行 bundle 會建立於 [project]/build/app/outputs/bundle/release/app.aab。
預設情況下,app bundle 內含您的 Dart 程式碼與 Flutter 執行時,並針對 armeabi-v7a (ARM 32-bit)、arm64-v8a (ARM 64-bit) 和 x86-64 (x86 64-bit) 進行編譯。
測試 app bundle
#app bundle 可透過多種方式測試。 本節介紹其中兩種。
使用 bundle tool 離線測試
#- 若尚未下載,請從其 GitHub repository 下載
bundletool。 - 從 app bundle 產生 APK 集合。
- 將 APK 部署 至連接的裝置。
使用 Google Play 線上測試
#- 將您的 bundle 上傳至 Google Play 進行測試。 您可以使用內部測試軌道, 或 alpha、beta 頻道先行測試 bundle, 再正式發佈至生產環境。
- 依照步驟 上傳您的 bundle 至 Play 商店。
建立 APK
#雖然 app bundle 為建議格式, 但仍有部分商店尚未支援 app bundle。 此時,請為每個目標 ABI(Application Binary Interface)建立發行版 APK。
如果您已完成簽署步驟,APK 會被簽署。 此時,您可以考慮混淆您的 Dart 程式碼, 以增加逆向工程的難度。 混淆程式碼需在 build 指令中加入額外旗標。
在命令列執行:
輸入
cd [project]。執行
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 旗標會產生 fat APK,該檔案包含 針對 所有 目標 ABI 編譯的程式碼。 這類 APK 檔案體積較大, 使用者需下載與其裝置架構不相容的原生二進位檔。
在裝置上安裝 APK
#請依下列步驟將 APK 安裝至已連接的 Android 裝置。
在命令列執行:
- 使用 USB 線將 Android 裝置連接至電腦。
- 輸入
cd [project]。 - 執行
flutter install。
發佈至 Google Play 商店
#如需將應用程式發佈至 Google Play 商店的詳細說明, 請參閱 Google Play launch 文件。
更新應用程式版本號
#應用程式的預設版本號為 1.0.0。 若要更新,請前往 pubspec.yaml 檔案, 並更新下列這一行:
version: 1.0.0+1版本號由三個以點號分隔的數字組成, 例如前述範例中的 1.0.0, 後面可以接一個選填的建置號(build number), 例如前述範例中的 1,兩者之間以 + 分隔。
在 Flutter 的建置過程中,可以分別透過指定 --build-name 和 --build-number 來覆寫 版本號與建置號。
在 Android 中,build-name 會作為 versionName 使用, 而 build-number 則作為 versionCode 使用。更多資訊請參考 Android 文件中的 Version your app。
當你為 Android 重新建置應用程式時,來自 pubspec 檔案的 版本號更新會同步到 local.properties 檔案中的 versionName 與 versionCode。
Android 發佈常見問答
#以下是關於 Android 應用程式部署的一些常見問題。
什麼時候應該建置 app bundle 而不是 APK?
#Google Play 商店建議你部署 app bundle, 因為這能讓應用程式更有效率地傳送給使用者。 然而,如果你不是透過 Play 商店分發應用程式, 那麼 APK 可能是你唯一的選擇。
什麼是 fat APK?
#fat APK 是一個單一 APK 檔案,內含多個 ABI 的二進位檔。這樣的好處是單一 APK 可以在多種架構上執行, 因此相容性更廣,但缺點是檔案體積會大很多, 導致使用者安裝應用程式時需要下載與儲存更多資料。 當你選擇建置 APK 而非 app bundle 時, 強烈建議使用分割 APK(split APK)的方式, 詳見 build an APK,並使用 --split-per-abi 旗標。
支援哪些目標架構?
#當你以 release 模式建置應用程式時, Flutter 應用程式可編譯為 armeabi-v7a (ARM 32-bit)、 arm64-v8a (ARM 64-bit),以及 x86-64 (x86 64-bit)。
如何簽署由 flutter build appbundle 產生的 app bundle?
#請參考 Sign the app。
如何在 Android Studio 中建置 release 版本?
#在 Android Studio 中,開啟你應用程式資料夾下現有的 android/ 資料夾。然後,在專案面板中選擇 build.gradle (Module: app):

接著,選擇建置變體(build variant)。在主選單中點選 Build > Select Build Variant。 在 Build Variants 面板中選擇任一變體(預設為 debug):

產生的 app bundle 或 APK 檔案會位於你應用程式資料夾下的 build/app/outputs 目錄中。