大家好!在 Day 24 和 25,我們為「省錢拍拍」App 設計了專業的圖示和無縫的啟動畫面,完成了 App 的「門面」工程。現在,我們的 App 在視覺和功能上都已準備就緒。
今天,我們將進行從「開發」到「上架」的關鍵轉變。我們不再只是用 flutter run
在模擬器上運行測試版,而是要學習如何將專案打包成一個可以上傳到 Google Play 商店的正式發布版本。
我們將專注於 Android 平台,內容涵蓋:設定版本號、建立數位簽章,並最終生成 Google 官方推薦的 AAB (Android App Bundle) 格式。
每一次發布到商店的版本,都必須有一個獨一無二的版本號。
打開專案根目錄下的 pubspec.yaml
檔案,找到 version
這一行:
# pubspec.yaml
version: 1.0.0+1
這個字串由兩部分組成,以 +
分隔:
1.0.0
: 這是 versionName
,是公開給使用者看的版本名稱,通常遵循「主版號.次版號.修訂號」的語意化版本格式。1
: 這是 versionCode
,是一個內部的整數。每一次上傳到 Google Play 的新版本,這個數字都必須比前一個版本大。對於我們的首次發布,1.0.0+1 是一個完美的起始點。
為了證明 App 是由你這位合法的開發者所發布,並且保證 App 未被竄改,所有發布版的 Android App 都必須經過數位簽章。這個簽章來自於一個你私人持有的金鑰檔案 (Keystore)。
極度重要警告
這個金鑰檔案是你 App 所有權的唯一證明。一旦遺失,你將永遠無法再更新你的 App。請務必將產生的金鑰檔案(.jks)和密碼,備份到安全、可靠的地方(例如雲端硬碟、密碼管理器等)。
我們使用 Java Development Kit (JDK) 內建的 keytool
指令來產生金鑰。請打開你的電腦終端機(不是 VS Code 內的終端機)來執行。
此指令通用於 Windows / macOS / Linux:
keytool -genkey -v -keystore snapsaver-release-key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias snapsaver_alias
執行後,指令行會要求你設定金鑰庫密碼和金鑰密碼(建議設成一樣方便記憶),以及一些個人資訊。請務必記下你設定的密碼。完成後,一個名為 snapsaver-release-key.jks
的檔案就會出現在你的使用者主目錄下。
金鑰檔案已經有了,現在要告訴我們的 Flutter 專案如何找到並使用它。
key.properties
android
資料夾下,手動建立一個名為 key.properties
的檔案。這個檔案包含密碼,絕對不能上傳到 Git。請檢查
android/.gitignore
檔案,確保其中包含key.properties
這一行。
key.properties
檔案中,填入以下內容,並換成你自己的設定:# android/key.properties
storePassword=YOUR_KEYSTORE_PASSWORD
keyPassword=YOUR_KEY_PASSWORD
keyAlias=snapsaver_alias
# storeFile 指向你上一步產生的 .jks 檔案的絕對路徑
# Windows 範例: storeFile=C\:\\Users\\YourUser\\snapsaver-release-key.jks (注意斜線需要轉義)
# macOS/Linux 範例: storeFile=/Users/YourUser/snapsaver-release-key.jks
也可以將 .jks 檔案直接移動到
android/app
資料夾下,這樣storeFile
就可以寫相對路徑,例如storeFile=../app/snapsaver-release-key.jks
android/app/build.gradle
檔案,我們需要讓 Gradle 讀取 key.properties
並在打包時使用它。這需要進行幾處修改,請仔細對照:// android/app/build.gradle
import java.util.Properties
import java.io.FileInputStream
// 1. 在檔案頂部,`apply from` 的下方,加入讀取 key.properties 的程式碼
val keystorePropertiesFile = rootProject.file("key.properties")
val keystoreProperties = Properties()
if (keystorePropertiesFile.exists()) {
keystoreProperties.load(FileInputStream(keystorePropertiesFile))
}
android {
// ...
// 為了避免不同開發環境的 NDK 版本差異導致錯誤,這裡明確指定版本
ndkVersion = "27.0.12077973" //明確設定
// 2. 在 android { ... } 區塊內,加入 signingConfigs
signingConfigs {
release {
if (keystorePropertiesFile.exists()) {
keyAlias = keystoreProperties.getProperty("keyAlias")
keyPassword = keystoreProperties.getProperty("keyPassword")
storeFile = file(keystoreProperties.getProperty("storeFile"))
storePassword = keystoreProperties.getProperty("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.getByName("release")
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
}
}
}
萬事俱備!現在,我們回到專案的根目錄,在終端機中執行 Flutter 的打包指令。我們將生成 AAB 格式,這是 Google Play 官方推薦的發布格式。它比傳統的 APK 檔案更小、更優化。
flutter build appbundle
這個指令會執行 release 模式的建構流程,並使用我們剛剛設定好的簽章金鑰。過程會需要幾分鐘。成功後,你會在終端機看到綠色的成功訊息,並且發布檔案會生成在以下路徑:
build/app/outputs/bundle/release/app-release.aab
這個 .aab
檔案,就是我們最終要上傳到 Google Play 商店的成品!
今天我們完成了從開發者到發布者的關鍵一步。我們學會了 Android 發布流程中的所有核心環節:
pubspec.yaml
中設定版本號。.jks
檔)。flutter build appbundle
指令,生成最終的發布檔案。我們的 Android App Bundle 已經準備好提交給 Google Play。
我們已經成功打包了 Android 的發布檔案,那麼在真正將這個檔案上傳到商店前,還有幾個至關重要的安全步驟需要完成。
明天,我們將學習 Firestore 安全規則的基本語法,並撰寫一條核心規則:「使用者只能讀寫屬於自己的消費紀錄」。這將徹底保護我們 App 的使用者資料隱私。