This tutorial produces an .ipa for App Store Connect (TestFlight and the App Store), an ad hoc IPA for registered devices, or an unsigned IPA you sign later. Target:
ipa. It builds on macOS only.
What you need#
- A Mac with Xcode (and CocoaPods if the project has a Podfile).
-
A paid Apple Developer Program membership, your Team ID (ten characters, shown in the Apple Developer portal under Membership) and an app id (
PRODUCT_BUNDLE_IDENTIFIER). - Xcode signed in to your account (Xcode → Settings → Accounts) so that automatic signing can create certificates and profiles.
1. Check the machine#
fpack doctor ipa
Doctor checks Xcode, CocoaPods, the team (ios.team_id, or the project's DEVELOPMENT_TEAM) and the signing certificates in your keychain. Problems come with the command that fixes them.
2. Tell fpack your team#
If the Xcode project already has a development team (Runner → Signing & Capabilities), nothing is needed. Otherwise set it. This also makes fpack generate the
ExportOptions.plist for you; your project is not modified.
ios:
team_id: ABCDE12345
3. Build the App Store IPA#
fpack build ipa
This runs flutter build ipa with Flutter's default export method (App Store Connect) and copies the result to
dist/1.0.0+1/my_app-1.0.0+1-ios-arm64.ipa. When the build fails, the key Xcode errors (certificates, provisioning profiles, team, pods…) are translated into concrete fixes.
4. Upload it#
Upload with Transporter (Mac App Store), with xcrun altool --upload-app, or let Xcode do it: set the export destination to
upload and fpack's generated options send the build to App Store Connect itself.
ios:
team_id: ABCDE12345
destination: upload # export (default) writes the IPA only; upload sends it to App Store Connect
You can also upload from a hook: post_package.ipa: [xcrun altool --upload-app …].
Tip
App Store Connect needs a new build number for every upload. Bump the number after + in
pubspec.yaml, or pass --build-number 43. With ios.manage_app_version_and_build_number: true
(the default) Apple may also manage it for the distribution.
Other ways to distribute#
Export methods#
| Method | For |
|---|---|
app-store-connect (default), app-store |
TestFlight and the App Store |
release-testing, ad-hoc | specific registered devices |
development, debugging | development devices |
enterprise | in-house distribution (Enterprise Program) |
fpack build ipa --export-method ad-hoc
The same setting is ios.export_method in fpack.yaml and FPACK_IOS_EXPORT_METHOD.
Manual signing with provisioning profiles#
By default Xcode manages signing. For manual signing (typical on CI) say which certificate and which profile signs each bundle id, including app extensions:
ios:
export_method: ad-hoc
team_id: ABCDE12345
signing_style: manual
signing_certificate: Apple Distribution
provisioning_profiles:
com.example.app: My App AdHoc
com.example.app.share: My App Share AdHoc
fpack writes these into the generated ExportOptions.plist (build/fpack/). Any other ExportOptions key can be added under
ios.export_options (for example iCloudContainerEnvironment: Production), and
ios.thinning, ios.upload_symbols and ios.strip_swift_symbols map to their plist keys.
Your own ExportOptions.plist#
fpack build ipa --export-options-plist ios/ExportOptions.plist
Your file wins over every generated option. Setting: ios.export_options_plist, FPACK_IOS_EXPORT_OPTIONS_PLIST.
Unsigned IPA#
fpack build ipa --no-codesign
Builds with --no-codesign and zips the Payload/ folder, for example to re-sign later in another system. Setting:
ios.codesign: false, FPACK_IOS_CODESIGN.
Flavors#
iOS flavors are Xcode schemes. fpack detects shared, per-user and workspace schemes. When a project has no custom schemes, the flavor is not passed to
flutter build ipa (with a note), so a flavor that exists only on Android does not break iOS builds. See
Flavors.
In CI#
Run on a macos-latest runner with certificates imported into a temporary keychain; the macOS credentials page shows the keychain steps (export the certificates for CI). Then:
- run: fpack build ipa --export-method app-store-connect --json > result.json
If something goes wrong#
| Message | Fix |
|---|---|
no signing certificate / No Accounts |
sign in to Xcode, or import the certificate and profile |
No profiles for 'com.example.app' were found |
with manual signing, list the bundle id (and extensions) in ios.provisioning_profiles |
| the team name in the hint is wrong | set ios.team_id (it wins over the project's DEVELOPMENT_TEAM) |
pod install fails |
run pod repo update, or cd ios && pod install to see the error |
| build number already used | bump +N in pubspec.yaml or pass --build-number |
More on the troubleshooting page.
本教程产出用于 App Store Connect(TestFlight 和 App Store)的 .ipa、面向已登记设备的 Ad Hoc IPA,或之后再签名的未签名 IPA。目标:ipa。只能在 macOS 上构建。
你需要什么#
- 装有 Xcode 的 Mac(工程有 Podfile 时还需要 CocoaPods)。
-
付费的 Apple Developer Program 会员资格、你的 Team ID(十位字符,在 Apple Developer 网站的“会员资格”里)和应用 ID(
PRODUCT_BUNDLE_IDENTIFIER)。 - Xcode 已登录你的账号(Xcode → Settings → Accounts),这样自动签名才能创建证书和描述文件。
1. 检查机器#
fpack doctor ipa
doctor 会检查 Xcode、CocoaPods、团队(ios.team_id,或工程里的 DEVELOPMENT_TEAM)以及钥匙串中的签名证书。每个问题都附带修复命令。
2. 告诉 fpack 你的团队#
如果 Xcode 工程里已经设置了开发团队(Runner → Signing & Capabilities),就不需要做任何事。否则请设置它。这同时会让 fpack 为你生成 ExportOptions.plist,你的工程不会被修改。
ios:
team_id: ABCDE12345
3. 构建 App Store 的 IPA#
fpack build ipa
这会用 Flutter 默认的导出方式(App Store Connect)运行 flutter build ipa,并把结果复制到 dist/1.0.0+1/my_app-1.0.0+1-ios-arm64.ipa。构建失败时,关键的 Xcode 错误(证书、描述文件、团队、pods…)会被翻译成具体的修复办法。
4. 上传#
用 Transporter(Mac App Store)、xcrun altool --upload-app 上传,或者让 Xcode 来做:把导出目标设为
upload,fpack 生成的导出选项就会直接把构建发送到 App Store Connect。
ios:
team_id: ABCDE12345
destination: upload # export(默认)只写出 IPA;upload 会发送到 App Store Connect
也可以在钩子里上传:post_package.ipa: [xcrun altool --upload-app …]。
提示
App Store Connect 要求每次上传都使用新的构建号。提高 pubspec.yaml 中 + 后面的数字,或传 --build-number 43。ios.manage_app_version_and_build_number: true(默认)时,App Store Connect 也可能代为管理构建号。
其他分发方式#
导出方式#
| 方式 | 用途 |
|---|---|
app-store-connect(默认)、app-store | TestFlight 和 App Store |
release-testing、ad-hoc | 指定的已登记设备 |
development、debugging | 开发设备 |
enterprise | 企业内部分发(企业计划) |
fpack build ipa --export-method ad-hoc
同样的设置在 fpack.yaml 里是 ios.export_method,变量是 FPACK_IOS_EXPORT_METHOD。
用描述文件手动签名#
默认由 Xcode 管理签名。手动签名(CI 上常见)时,要说明每个 bundle id(包括 App 扩展)由哪个证书和哪个描述文件签名:
ios:
export_method: ad-hoc
team_id: ABCDE12345
signing_style: manual
signing_certificate: Apple Distribution
provisioning_profiles:
com.example.app: My App AdHoc
com.example.app.share: My App Share AdHoc
fpack 会把这些写进生成的 ExportOptions.plist(在 build/fpack/)。其他任何 ExportOptions 键都可以放在
ios.export_options 下(例如 iCloudContainerEnvironment: Production),ios.thinning、ios.upload_symbols
和 ios.strip_swift_symbols 对应各自的 plist 键。
使用你自己的 ExportOptions.plist#
fpack build ipa --export-options-plist ios/ExportOptions.plist
你的文件优先于所有生成的选项。设置:ios.export_options_plist、FPACK_IOS_EXPORT_OPTIONS_PLIST。
未签名的 IPA#
fpack build ipa --no-codesign
使用 --no-codesign 构建并把 Payload/ 目录打成 zip,例如之后在别的系统里重新签名。设置:ios.codesign: false、FPACK_IOS_CODESIGN。
Flavor#
iOS 的 flavor 是 Xcode scheme。fpack 会检测共享、用户级和 workspace 的 scheme。工程没有自定义 scheme 时,不会把 flavor 传给 flutter build ipa(并给出提示),所以只存在于 Android 的 flavor 不会弄坏 iOS 构建。见
Flavor。
在 CI 中#
在 macos-latest 上运行,并把证书导入临时钥匙串;macOS 凭证页展示了钥匙串的步骤(为 CI 导出证书)。然后:
- run: fpack build ipa --export-method app-store-connect --json > result.json
出问题时#
| 提示 | 处理 |
|---|---|
没有签名证书 / No Accounts | 在 Xcode 里登录账号,或导入证书和描述文件 |
No profiles for 'com.example.app' were found |
手动签名时,把 bundle id(和扩展)写进 ios.provisioning_profiles |
| 提示里的团队名不对 | 设置 ios.team_id(它优先于工程里的 DEVELOPMENT_TEAM) |
pod install 失败 |
运行 pod repo update,或 cd ios && pod install 查看错误 |
| 构建号已被使用 | 提高 pubspec.yaml 中的 +N 或传 --build-number |
更多见故障排查页。