跳转到正文
YGJoon 技术博客

Flutter 应用打包发布详解

发布于:
·1.4k 字 · 约 4 分钟·作者:
Android:keytool 生成签名,flutter build 打 apk/appbundle;iOS 证书与 Archive 流程走完
Flutter 应用打包发布详解文章封面
目录

简介

应用打包发布是开发流程中的重要环节。本文详细介绍如何打包和发布 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 打包

配置证书

  1. 在 Apple Developer 网站创建证书
  2. 在 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

发布检查清单

通用检查

Android 检查

iOS 检查

最佳实践

  1. keystore(key.jks)加密码至少存两个地方(加密云盘 + 离线 U 盘):丢了等于这个包名永远发不了更新,Google Play 的密钥重置流程要走好几天,别赌自己的记性。
  2. 发版前一定在 release 模式下真机冒烟:debug 包带断言、没优化,性能差几倍,“debug 不卡”不等于”release 不卡”;尤其开了 R8 混淆后,反射、JSON 序列化缺了混淆规则会直接崩——release 包跑一遍核心流程是底线。
  3. 灰度发布:Google Play 先 internal track → closed → production 分阶段放量,别第一天就 100% 全量;崩了也有得救,全量崩了就只能连夜发 hotfix。

注意事项

  1. versionCode(+ 后面的构建号)必须单调递增,商店靠它判断新旧:只改 versionName 不加构建号,上传会被拒——每次发版两个号一起涨,养成肌肉记忆。
  2. iOS 首次提审预留 1~2 周:被拒重审又要重新排队;高频被拒原因是隐私政策链接缺失、应用描述与实际功能不符——别在 deadline 前一天才提交。
  3. 密钥和密码别进 git:key.properties 加进 .gitignore,CI 里用环境变量/Secrets 注入;仓库一旦公开,keystore 密码就等于公开了。
  4. 留好回滚手段:Android 出问题直接发新版覆盖;iOS 审核慢,上一版的 archive 包和 dSYM 别删——紧急时重新提审旧版,比重新打包更快。

实战案例:桌面应用到底怎么分发

flutter_brightness 是个 Windows 桌面小工具(串口读传感器、自动调亮度),这就带来一个移动端没有的问题:怎么做分发?移动端有应用商店,桌面端得自己选。我当时在 msix 安装包和 zip 绿色包之间纠结:msix 有开始菜单、卸载入口,看起来正规,但要处理签名证书——自签名证书会被 SmartScreen 拦,买证书对个人小工具来说不划算;zip 包low是low了点,但用户解压即用,更新就是覆盖文件,零门槛。最后选了 zip,因为这个工具的用户就是我自己加几个朋友,“能跑就行”优先于”看起来正规”。trade-off 很现实:分发方式选的不是技术优劣,而是你的用户是谁、更新频率多高。如果以后要公开发布,我会再回头做 msix + 官网下载页。个人项目的打包发布,别一上来就照抄大厂流程,先回答”谁来装、多久更新一次”这两个问题。

总结

应用打包发布是一个复杂的过程,需要注意很多细节。通过合理的配置和自动化工具,可以简化发布流程,提高发布效率。


分享这篇文章:


相关文章

上一篇
Flutter 实现自定义时间选择器
下一篇
Flutter 设备通信详解