简介
应用打包发布是开发流程中的重要环节。本文详细介绍如何打包和发布 Flutter 应用到 Android 和 iOS 平台。
Android 打包
生成密钥
keytool -genkey -v -keystore key.jks \
-keyalg RSA -keysize 2048 -validity 10000 \
-alias key
配置密钥
创建 key.properties
storePassword=<store password>
keyPassword=<key password>
keyAlias=key
storeFile=<key store file location>
配置 build.gradle
def keystoreProperties = new Properties()
def keystorePropertiesFile = rootProject.file('key.properties')
if (keystorePropertiesFile.exists()) {
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
}
android {
signingConfigs {
release {
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
storeFile file(keystoreProperties['storeFile'])
storePassword keystoreProperties['storePassword']
}
}
buildTypes {
release {
signingConfig signingConfigs.release
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'),
'proguard-rules.pro'
}
}
}
打包命令
## 生成 APK
flutter build apk --release
## 生成 App Bundle
flutter build appbundle
iOS 打包
配置证书
- 在 Apple Developer 网站创建证书
- 在 Xcode 中配置证书和 Provisioning Profile
配置应用信息
<!-- ios/Runner/Info.plist -->
<key>CFBundleDisplayName</key>
<string>应用名称</string>
<key>CFBundleIdentifier</key>
<string>com.example.myapp</string>
<key>CFBundleShortVersionString</key>
<string>1.0.0</string>
<key>CFBundleVersion</key>
<string>1</string>
打包命令
flutter build ios --release
版本管理
pubspec.yaml
version: 1.0.0+1 # 版本号+构建号
版本号格式
- 主版本号.次版本号.修订号
- 构建号(整数,单调递增)
多渠道打包
Android 渠道配置
android {
flavorDimensions "default"
productFlavors {
google {
dimension "default"
manifestPlaceholders = [
CHANNEL_VALUE: "google"
]
}
huawei {
dimension "default"
manifestPlaceholders = [
CHANNEL_VALUE: "huawei"
]
}
}
}
打包命令
## 打包特定渠道
flutter build apk --flavor google
flutter build apk --flavor huawei
自动化打包
Fastlane 配置
## fastlane/Fastfile
default_platform(:android)
platform :android do
desc "Deploy to Play Store"
lane :deploy do
gradle(
task: "clean assembleRelease",
properties: {
"android.injected.signing.store.file" => ENV["KEYSTORE_FILE"],
"android.injected.signing.store.password" => ENV["STORE_PASSWORD"],
"android.injected.signing.key.alias" => ENV["KEY_ALIAS"],
"android.injected.signing.key.password" => ENV["KEY_PASSWORD"],
}
)
upload_to_play_store(
track: 'internal',
aab: '../build/app/outputs/bundle/release/app-release.aab'
)
end
end
platform :ios do
desc "Deploy to App Store"
lane :deploy do
build_ios_app(
workspace: "Runner.xcworkspace",
scheme: "Runner",
export_method: "app-store"
)
upload_to_app_store(
skip_screenshots: true,
skip_metadata: true
)
end
end
CI/CD 配置
## .github/workflows/release.yml
name: Release
on:
push:
tags:
- 'v*'
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
java-version: '17'
- uses: subosito/flutter-action@v2
- run: flutter pub get
- run: flutter test
- run: flutter build apk --release
- uses: actions/upload-artifact@v4
with:
name: release-apk
path: build/app/outputs/flutter-apk/app-release.apk
发布检查清单
通用检查
- 版本号更新
- Changelog 更新
- 隐私政策更新
- 用户协议更新
- 应用图标和启动图
- 应用名称和描述
- 测试覆盖
- 性能测试
Android 检查
- 签名配置
- 混淆配置
- 权限声明
- 应用截图
- 应用分级
iOS 检查
- 证书配置
- 设备支持
- 隐私声明
- 应用截图
- 审核信息
最佳实践
- keystore(
key.jks)加密码至少存两个地方(加密云盘 + 离线 U 盘):丢了等于这个包名永远发不了更新,Google Play 的密钥重置流程要走好几天,别赌自己的记性。 - 发版前一定在 release 模式下真机冒烟:debug 包带断言、没优化,性能差几倍,“debug 不卡”不等于”release 不卡”;尤其开了 R8 混淆后,反射、JSON 序列化缺了混淆规则会直接崩——release 包跑一遍核心流程是底线。
- 灰度发布:Google Play 先 internal track → closed → production 分阶段放量,别第一天就 100% 全量;崩了也有得救,全量崩了就只能连夜发 hotfix。
注意事项
versionCode(+后面的构建号)必须单调递增,商店靠它判断新旧:只改versionName不加构建号,上传会被拒——每次发版两个号一起涨,养成肌肉记忆。- iOS 首次提审预留 1~2 周:被拒重审又要重新排队;高频被拒原因是隐私政策链接缺失、应用描述与实际功能不符——别在 deadline 前一天才提交。
- 密钥和密码别进 git:
key.properties加进.gitignore,CI 里用环境变量/Secrets 注入;仓库一旦公开,keystore 密码就等于公开了。 - 留好回滚手段:Android 出问题直接发新版覆盖;iOS 审核慢,上一版的 archive 包和 dSYM 别删——紧急时重新提审旧版,比重新打包更快。
实战案例:桌面应用到底怎么分发
flutter_brightness 是个 Windows 桌面小工具(串口读传感器、自动调亮度),这就带来一个移动端没有的问题:怎么做分发?移动端有应用商店,桌面端得自己选。我当时在 msix 安装包和 zip 绿色包之间纠结:msix 有开始菜单、卸载入口,看起来正规,但要处理签名证书——自签名证书会被 SmartScreen 拦,买证书对个人小工具来说不划算;zip 包low是low了点,但用户解压即用,更新就是覆盖文件,零门槛。最后选了 zip,因为这个工具的用户就是我自己加几个朋友,“能跑就行”优先于”看起来正规”。trade-off 很现实:分发方式选的不是技术优劣,而是你的用户是谁、更新频率多高。如果以后要公开发布,我会再回头做 msix + 官网下载页。个人项目的打包发布,别一上来就照抄大厂流程,先回答”谁来装、多久更新一次”这两个问题。
总结
应用打包发布是一个复杂的过程,需要注意很多细节。通过合理的配置和自动化工具,可以简化发布流程,提高发布效率。
