Flutter 打包 / 发布签名完整指南

Bundle ID 示例统一使用 com.example.aioli 本文档涵盖 Android Keystore、iOS 证书、Provisioning Profile、App Store Connect API Key 的完整生成与配置流程。


目录

  1. Android 签名(Keystore)
  2. iOS 证书(Distribution Certificate)
  3. iOS Provisioning Profile
  4. App Store Connect API Key
  5. 第三方平台签名(极光等)
  6. CI/CD GitHub Secrets 汇总
  7. Flutter 项目关联配置

一、Android 签名(Keystore)

1.1 生成 Keystore 文件

前提:已安装 JDK(Android Studio 自带,或 brew install --cask temurin

keytool -genkey -v \
  -keystore orion_release.jks \
  -alias orion_key \
  -keyalg RSA \
  -keysize 2048 \
  -validity 10000

交互填写示例:

Enter keystore password:  ← 设置 storePassword(记住!)
Re-enter new password:    ← 再次确认

What is your first and last name?      Aioli Team
What is the name of your org unit?     Mobile
What is the name of your organization? Aioli
What is the name of your City?         Taipei
What is the name of your State?        Taiwan
What is the two-letter country code?   TW

Is CN=Aioli Team, ... correct? [no]: yes

Enter key password for <orion_key>:    ← 设置 keyPassword(可直接回车=同上)

生成文件:orion_release.jks(当前目录)

1.2 验证 Keystore

keytool -list -v \
  -keystore orion_release.jks \
  -alias orion_key

输出关键信息:

Alias name: orion_key
Certificate fingerprints:
  MD5:    BA:CC:E1:2F:...   ← 32字节,去冒号后32字符
  SHA1:   AA:BB:CC:DD:...   ← 20字节,去冒号后40字符
  SHA256: EE:FF:00:11:...   ← 32字节,去冒号后64字符

1.3 查看各格式签名指纹

# 查看 keystore 签名
keytool -list -v -keystore orion_release.jks -alias orion_key -storepass 你的密码

# 查看已构建 APK 的签名
apksigner verify --print-certs build/app/outputs/flutter-apk/app-release.apk

# 验证 APK 与 keystore 签名一致(SHA256 对比)
keytool -list -v -keystore orion_release.jks -alias orion_key -storepass 你的密码 \
  | grep SHA256 | tr '[:lower:]' '[:upper:]'

apksigner verify --print-certs build/app/outputs/flutter-apk/app-release.apk \
  | grep "SHA-256" | tr '[:lower:]' '[:upper:]'

1.4 生成各平台所需格式

# MD5(32字符)← 极光推送、微信开放平台等
keytool -exportcert \
  -keystore orion_release.jks \
  -alias orion_key \
  -storepass 你的密码 \
  | md5sum | awk '{print $1}'

# SHA1(40字符)← 高德地图、百度地图、Firebase
keytool -list -v -keystore orion_release.jks -alias orion_key -storepass 你的密码 \
  | grep "SHA1:" | awk '{print $2}' | tr -d ':'

# SHA256(64字符)← Google Play Console
keytool -list -v -keystore orion_release.jks -alias orion_key -storepass 你的密码 \
  | grep "SHA256:" | awk '{print $2}' | tr -d ':'

各平台签名格式速查:

平台 格式 字符数
Google Play Console SHA256,去冒号 64
极光推送 / 一键登录 MD5,去冒号,小写 32
微信开放平台 MD5,去冒号,小写 32
高德 / 百度地图 SHA1,去冒号 40
Firebase SHA1 或 SHA256 40 / 64

1.5 转 base64(用于 CI)

# macOS(直接复制到剪贴板)
base64 -i orion_release.jks | pbcopy
base64 -w0 -i orion_release.jks | pbcopy

# Linux
base64 -w 0 orion_release.jks > keystore_base64.txt

1.6 签名注意事项


二、iOS 证书(Distribution Certificate)

前提:已有 Apple Developer 账号(99$/年),当前 Mac 将持有私钥

2.1 生成 CSR(证书签名请求)

打开 Keychain Access(钥匙串访问)

菜单栏 → Keychain Access
       → Certificate Assistant(证书助理)
       → Request a Certificate From a Certificate Authority(从证书颁发机构请求证书)

填写: - User Email:Apple ID 邮箱 - Common Name:任意,如 Aioli Distribution - CA Email:留空 - 选择 Saved to disk(存储到磁盘)

保存生成 CertificateSigningRequest.certSigningRequest,同时私钥自动存入当前 Mac 的 Keychain

2.2 在 Apple Developer 后台创建证书

登录 developer.apple.com/account/resources/certificates

点击 + → 选择 Apple Distribution → 上传 .certSigningRequest 文件 → 下载 .cer 文件

2.3 导入证书到 Keychain

# 双击 .cer 文件自动导入,或命令行:
security import ~/Downloads/distribution.cer \
  -k ~/Library/Keychains/login.keychain-db

2.4 导出 .p12 文件

打开 Keychain Access → 搜索 Apple Distribution

⚠️ 必须在生成 CSR 的那台 Mac 上操作,证书左侧有展开箭头(含私钥)才能导出 .p12

右键证书 → 导出(Export)
格式选择 .p12
设置导出密码(即 IOS_DISTRIBUTION_CERT_PASSWORD)

转 base64:

base64 -i Distribution.p12 | pbcopy

2.5 .p12 灰色无法选择的解决方法

原因:当前 Mac 上只有证书,没有对应私钥。

有私钥(可导出):             没有私钥(.p12灰色):
▼ 🏅 Apple Distribution: xxx   🏅 Apple Distribution: xxx
    🔑 私钥                        (无法展开)

解决方案:

方案 A:去原来生成 CSR 的 Mac 上,同时选中证书和私钥(Cmd 多选)→ 右键导出

方案 B:在当前 Mac 重新生成 CSR → Apple Developer 后台吊销旧证书 → 用新 CSR 申请新证书 → 导入 → 导出 .p12

注意:吊销旧证书后,用旧证书签名的 Provisioning Profile 会失效,需重新生成 PP。已安装在用户设备上的 App 不受影响。


三、iOS Provisioning Profile

3.1 确认 Bundle ID(App Identifier)

登录 developer.apple.com/account/resources/identifiers

若不存在,点击 + 创建: - 类型:App IDs - Bundle ID 模式:Explicit - Bundle ID:com.example.aioli(生产)/ com.example.aioli.dev(开发,可选)

3.2 创建 Dev Provisioning Profile

登录 developer.apple.com/account/resources/profiles

点击 +

类型:iOS App Development
Bundle ID:com.example.aioli.dev(或 com.example.aioli)
Certificate:选择刚才创建的 Distribution 证书
Devices:选择测试设备
Name:Aioli Dev Profile

下载 Aioli_Dev_Profile.mobileprovision,转 base64:

base64 -i "Aioli_Dev_Profile.mobileprovision" | pbcopy

3.3 创建 Prod Provisioning Profile

类型:App Store Connect
Bundle ID:com.example.aioli
Certificate:选择 Distribution 证书
Name:Aioli AppStore Profile

下载 Aioli_AppStore_Profile.mobileprovision,转 base64:

base64 -i "Aioli_AppStore_Profile.mobileprovision" | pbcopy

3.4 查看 PP 详细信息

# 查看 PP 的 UUID、有效期、Bundle ID
security cms -D -i "Aioli_Dev_Profile.mobileprovision" \
  | grep -A1 "UUID\|application-identifier\|ExpirationDate"

四、App Store Connect API Key

用于 CI 自动上传 IPA,比账号密码更安全。

4.1 生成 API Key

登录 appstoreconnect.apple.com

左上角用户头像 → Integrations → App Store Connect API → 点击 +
Name:CI Deploy Key
Access:App Manager

4.2 记录三个关键值

位置 对应 Secret
Key ID Key 列表中,格式 AB12CD34EF APP_STORE_CONNECT_KEY_ID
Issuer ID 页面顶部,UUID 格式 APP_STORE_CONNECT_ISSUER_ID
.p8 私钥文件 点 Download API Key 下载 APP_STORE_CONNECT_KEY_BASE64

转 base64:

base64 -i AuthKey_XXXXXXXXXX.p8 | pbcopy

⚠️ .p8 文件只能下载一次,请立即备份到密码管理器。


五、第三方平台签名(极光等)

5.1 极光推送 / 一键登录(Android)

需要 MD5 格式签名(32字符小写):

keytool -exportcert \
  -keystore orion_release.jks \
  -alias orion_key \
  -storepass 你的密码 \
  | md5sum | awk '{print $1}'
# 输出示例:bacce12f3a445b6c7d8e9fa0b1c2d3e4

填入极光控制台:应用管理 → Android → 应用签名 MD5

5.2 极光推送(iOS)

iOS 端需上传 APNs 证书,在 Apple Developer 后台创建:

Certificates → + → Apple Push Notification service SSL (Sandbox & Production)
→ 选择 Bundle ID:com.example.aioli
→ 上传 CSR → 下载 .cer → 导入 Keychain → 导出 .p12

将 .p12 上传到极光控制台 → iOS → APNs 证书


六、CI/CD GitHub Secrets 汇总

进入仓库 → Settings → Secrets and variables → Actions → New repository secret

Android

Secret 名称 值来源 备注
ANDROID_KEYSTORE_BASE64 base64 -i orion_release.jks jks 文件的 base64
ANDROID_STORE_PASSWORD keytool 设置的 storePassword
ANDROID_KEY_PASSWORD keytool 设置的 keyPassword
ANDROID_KEY_ALIAS -alias 值,如 orion_key

iOS 证书

Secret 名称 值来源 备注
IOS_DISTRIBUTION_CERT_BASE64 base64 -i Distribution.p12
IOS_DISTRIBUTION_CERT_PASSWORD 导出 .p12 时设置的密码
IOS_DEV_PROVISIONING_PROFILE_BASE64 Dev PP 的 base64
IOS_PROD_PROVISIONING_PROFILE_BASE64 Prod PP 的 base64
IOS_DEV_PROFILE_NAME Aioli Dev Profile 与 PP 创建时名称一致
IOS_PROD_PROFILE_NAME Aioli AppStore Profile
IOS_DEV_BUNDLE_ID com.example.aioli.dev
IOS_PROD_BUNDLE_ID com.example.aioli
APPLE_TEAM_ID developer.apple.com → Membership 格式如 A1B2C3D4E5

App Store Connect API

Secret 名称 值来源 备注
APP_STORE_CONNECT_KEY_ID API Key 列表中 格式如 AB12CD34EF
APP_STORE_CONNECT_ISSUER_ID 页面顶部 UUID 格式
APP_STORE_CONNECT_KEY_BASE64 base64 -i AuthKey_xxx.p8 只能下载一次

已有(OSS + GitHub)

Secret 名称 备注
GH_PAT 有写权限的 Personal Access Token
OSS_ENDPOINT 阿里云 OSS endpoint
OSS_ACCESS_KEY_ID OSS AccessKey ID
OSS_ACCESS_KEY_SECRET OSS AccessKey Secret
OSS_BUCKET OSS Bucket 名称

七、Flutter 项目关联配置

7.1 Android:android/key.properties(本地开发)

storeFile=../../orion_release.jks
storePassword=你的密码
keyAlias=orion_key
keyPassword=你的密码

7.2 Android:android/app/build.gradle.kts

import java.util.Properties
import java.io.FileInputStream

val keyPropsFile = rootProject.file("key.properties")
val keyProps = Properties()
if (keyPropsFile.exists()) {
    keyProps.load(FileInputStream(keyPropsFile))
}

android {
    signingConfigs {
        create("release") {
            val storeFilePath = keyProps["storeFile"] as String?
            if (storeFilePath != null) storeFile = file(storeFilePath)
            storePassword = keyProps["storePassword"] as String?
            keyAlias      = keyProps["keyAlias"]      as String?
            keyPassword   = keyProps["keyPassword"]   as String?
        }
    }
    buildTypes {
        getByName("release") {
            signingConfig    = signingConfigs.getByName("release")
            isMinifyEnabled  = true
            isShrinkResources = true
        }
    }
}

7.3 .gitignore(必须添加)

# Android 签名(根目录)
*.jks
*.keystore
android/key.properties

# iOS 证书
*.p12
*.mobileprovision
ios/ExportOptions.plist

7.4 本地构建验证

# Android
flutter build apk --release
apksigner verify --print-certs build/app/outputs/flutter-apk/app-release.apk | grep SHA-256

# iOS
flutter build ipa --release --export-options-plist=ios/ExportOptions.plist

附:各文件备份清单

文件 存放位置 重要程度
orion_release.jks 公司密码管理器 ⭐⭐⭐⭐⭐ 丢失无法恢复
Distribution.p12 公司密码管理器 ⭐⭐⭐⭐ 可重新生成但麻烦
AuthKey_xxx.p8 公司密码管理器 ⭐⭐⭐⭐ 只能下载一次
*.mobileprovision 可随时从 Apple 后台重新下载 ⭐⭐
key.properties 本地,不提交 Git ⭐⭐⭐


Page Source