做 FlutterFlow 项目的朋友,大概率都有过这样一刻:应用在浏览器预览里跑得挺欢,打包成 APK 也顺利,结果一说到“上 App Store”,空气突然安静。我接过好几个类似的咨询,都是卡在同一个地方——FlutterFlow 生成的是完整 Flutter 工程,但苹果的上架链路需要 Xcode、开发者账号、签名证书、TestFlight 一套流程,缺哪一环都走不通。这篇文章就围绕“怎么用 FlutterFlow 把应用发布到 App Store”这件事,把从账号准备到最终提审的每一步拆开讲清楚,适合没有原生 iOS 开发经验、但想独立完成应用发布的产品经理或独立开发者。
1. 发布之前,先把整条路想清楚
1.1 FlutterFlow 到底帮你做了哪部分
很多刚接触 FlutterFlow 的人会误以为它是个“一键上架”工具:应用做完,点个按钮,App Store 上就有了。实际完全不是这样。FlutterFlow 作为低代码平台,它替你解决的是应用本身的开发与构建——UI 拖拽生成、业务逻辑编排、数据库集成、推送配置这些事。到了发布环节,它只能帮你导出 iOS 工程,或者通过 GitHub 等代码托管平台把工程同步下来。
App Store 的发布链路是这样的:开发者账号申请 → FlutterFlow 导出/同步工程 → 本地 Xcode 打开 → 签名配置 → 归档(Archive)→ 上传到 App Store Connect → TestFlight 内测 → 提交审核 → 审核通过上架。FlutterFlow 覆盖的只是前两环,后面每一环都需要你自己操作。理解这一点,你就不会在过程中产生“怎么还有这么多事”的挫败感。
顺带说一句,如果你想发布到国内安卓市场或者鸿蒙市场,那又是一套完全不同的流程,签名机制、审核规则、后台入口全都不一样。这篇文章不展开,先把 iOS 这条链路说透。
1.2 你需要准备的账号和硬件清单
先说硬性条件,缺一个都走不到最后:
- Apple Developer 开发者账号:个人账号 99 美元/年,公司账号 299 美元/年。这里有个很常见的误区——很多人拿免费的 Apple ID 去 Xcode 里签名,结果发现只能在本机调试,根本无法生成上传 App Store 的 Distribution 证书。要发布,必须是付费开发者账号。
- 一台 Mac:Xcode 只能在 macOS 上运行。官方要求是支持最新 Xcode 的 macOS 版本,但如果你是老机器,比如标题热搜里提到的 MacBook Air (13-inch, Early 2015),就需要特别注意系统版本和 Xcode 版本的匹配问题,后面我在常见问题里专门讲。
- Apple ID 开启双重认证:现在新注册的 Apple ID 基本默认开启,但老账号要自己检查。双重认证没开,Xcode 在登录 App Store Connect 时经常报认证失败。
- 稳定的网络环境:上传构建包、访问 App Store Connect 都需要网络,跨国传输偶尔会中断,要有重试的心理准备。
如果你现在一台 Mac 都没有,也不用急着放弃。市面上有云 Mac 服务,按小时计费,用来做一次性的归档上传完全够用。但如果你是打算长期迭代这个应用,我建议还是老老实实准备一台 Mac,哪怕收一台二手的也行,因为后续每个版本更新都要走一遍上传流程。
1.3 整个流程的时间线预估
第一次操作的人,我建议预留至少一周的时间,不是吓唬你,是流程里有很多“等待”环节:
- 开发者账号审核:个人账号通常几小时到一天,公司账号需要审核企业资质,可能 3-5 个工作日。
- 构建上传后处理:上传到 App Store Connect 之后,构建要经过扫描病毒、处理符号表等步骤,一般 5-30 分钟,高峰期可能更久。
- TestFlight 内测:构建处理完成后,还需要等它变成“可供测试”状态,这个状态转换通常也是几分钟到几十分钟。
- 正式审核:首次提审一般 1-3 个工作日,但如果遇到应用类型敏感、隐私问题没写清楚、或者审核排队高峰,拖到一周也不奇怪。
所以整个流程走下来,快的话 2-3 天,慢的话一周多。最好别在开发者账号还没下来的时候就把应用做完了再干等,账号申请和 FlutterFlow 开发可以并行。
2. 在 FlutterFlow 里把“发布前”的配置做对
2.1 Bundle ID、版本号与构建号要怎么填
在 FlutterFlow 里,你需要先找到Settings > App Information这个入口,重点看三个字段:
- App ID / Bundle ID:这是应用的唯一标识,推荐用反域名格式,比如
com.yourname.yourapp。一旦这个 ID 发布过任何一个应用,它就被永久占用,不能再被其他应用使用。你可以先想好一个,之后在 App Store Connect 创建应用记录时也要用同一个 ID。 - App Version:面向用户的版本号,比如
1.0.0。它必须跟 App Store Connect 里填写的版本号完全一致,否则上传时会在“版本不匹配”这一步被拦下来。 - Build Number:构建号,用于区分同版本下的不同构建。你第一次构建可以填
1,第二次修了 bug 再构建就填2。它不需要展示给用户看,但 App Store Connect 会用它区分构建记录。
很多人在这里忽略一件事:FlutterFlow 里改了 Bundle ID 或者版本号之后,一定要重新导出工程,而不是直接改本地的 Xcode 项目。我见过有朋友手动改完 Xcode 里的配置,结果 FlutterFlow 那边再同步一次代码,本地配置全部被覆盖,上传的时候又报冲突,来回折腾很久。
版本号规划上,我建议采用语义化版本,主版本.次版本.修订号。第一版就老老实实1.0.0,别上来就整2.1.0,因为后续每次提审都要比之前的版本号高,一开始定太高,后面会很被动。
2.2 图标、启动图和应用名称这些细节
苹果审核对图标的要求极其严格,这里列几个我踩过和看别人踩过的坑:
- 图标不能有透明通道:FlutterFlow 生成的图标默认是规范的,但如果你用在线工具自己制作,导出时一定要检查是否带着 Alpha 通道。带透明通道的图标上传后会在构建阶段收到警告
Invalid App Store Icon,直接导致构建无法被 TestFlight 使用。 - 图标尺寸:App Store 现在要求的图标尺寸是 1024x1024 像素,并且不能被圆角化处理,因为苹果会自动帮你加圆角。如果你自己做了圆角,审核时会被判定为图标不符合规范。
- 启动图:FlutterFlow 里默认生成的启动图是单一背景色加应用名称。要注意的是,不要把关键信息放在屏幕边缘,不同机型的刘海、圆角、底部横条都会裁掉一部分。启动图显示不正确不会直接被拒,但会给审核人员留下“应用质量不高”的印象,影响审核通过率。
- 应用名称:应用名称不能超过 30 个字符,实际显示时还会被系统截断。建议把核心关键词放在前面,比如“记账管家 - 极简账本”比“一款帮助你记录日常开支的极简账本工具” 效果好得多。这个名称在 FlutterFlow 里一般不直接配置,而是在 App Store Connect 创建应用时填写。
隐私政策也是一个容易被忽略的项。只要你的应用有用户注册、登录、收集任何数据(包括崩溃日志),App Store Connect 里就必须提供隐私政策 URL。FlutterFlow 本身能生成简单的隐私政策页面,但你要有一个可以公开访问的 URL。最简单的方式是先在 Notion、GitHub Pages 或者国内一些云服务商的静态托管上挂一个隐私政策页面,然后把链接填到 App Store Connect 的“App 隐私”栏里。
2.3 从 FlutterFlow 导出工程的两种方式
FlutterFlow 导出 iOS 工程有两种常见方式,看你自己的技术偏好来选:
- 下载 ZIP 包:在 FlutterFlow 的Build > Build & Publish页面,选择 iOS 或 iOS/Android,点击 Download 就会下载一个项目压缩包。这种方式适合第一次导出、只想快速看一眼项目的朋友。缺点是你拿到的是一份静态快照,之后 FlutterFlow 里任何改动,都需要重新下载再手工覆盖。
- 连接 GitHub/GitLab:在 Settings 里连接到你的代码仓库,之后每次需要同步,直接点 Sync 就把 FlutterFlow 的代码推送到 GitHub。本地 Xcode 里通过
git pull拉取最新代码,再继续归档上传。这种方式明显更适合要长期迭代的应用,因为我可以在 Xcode 里做一些 FlutterFlow 不方便配置的原生修改,比如某些系统权限描述,而且不会被 FlutterFlow 覆盖掉。
我个人的习惯是:能用 GitHub 同步就绝不只用 ZIP。因为 FlutterFlow 里能调的 iOS 配置还是有限的,比如某些Info.plist权限说明文案,还是需要在 Xcode 里微调。只有代码仓库托管才能让这些改动持久保存。
无论用哪种方式,导出前都要做一件事:在 FlutterFlow 里跑一次Run Test,至少确保导出的代码能通过基础编译。别把明显缺依赖的代码导出到本地,然后坐在 Xcode 前面一脸懵。
3. 用 Xcode 把项目跑起来并完成归档上传
3.1 本机环境准备:Xcode、CocoaPods 与 Flutter SDK
FlutterFlow 导出的项目本质上是 Flutter 工程,所以本机环境要先满足 Flutter 开发的基本要求。如果你是第一次在 Mac 上做 iOS 构建,建议按下面的顺序装:
- Xcode:从 App Store 安装,装完打开一次,让它自动完成组件初始化。这一步很容易被跳过但很重要,我在常见的坑里详细说。
- CocoaPods:Flutter 的 iOS 工程需要用它管理第三方原生依赖。终端运行
sudo gem install cocoapods或者brew install cocoapods都行。装完后运行pod --version确认版本号正常。 - Flutter SDK:虽然 FlutterFlow 会帮你在云端构建 Flutter 代码,但本地调试、执行
flutter doctor检查环境,仍然需要装 Flutter SDK。安装方式很简单,去 Flutter 官网下载对应 macOS 的 SDK 压缩包,解压后配置 PATH 环境变量,然后运行flutter doctor看看是不是全绿。
flutter doctor里我特别看重两个选项:Xcode - develop for iOS and macOS和CocoaPods - installed。如果这两项有问题,比如 Xcode 显示incomplete setup,说明 Xcode 组件初始化没完成,回去重新打开 Xcode 让它跑完协议确认和额外组件下载。
这里插一句热搜里提到的“macbook air (13-inch, early 2015) 可以上网但无法连接到 App Store”的情况。老机器的 macOS 版本如果停留在旧版本,从 App Store 里根本无法看到或者下载最新版 Xcode,因为新版 Xcode 要求更高的 macOS 版本。解决办法只有两个:能升级 macOS 系统就先升级;升不了就换机器,或者用云 Mac 做归档上传。这个坑在旧机器上非常典型,不要试图用旧版 Xcode 强行上传,App Store Connect 的后端会拒绝旧版本 Xcode 做出的构建包。
3.2 打开工程、配置签名与 Team
从 FlutterFlow 同步下来的工程,找到ios文件夹,里面一定有一个Runner.xcworkspace文件。记住要打开的是xcworkspace而不是xcodeproj,因为 Flutter 和 CocoaPods 依赖都用 workspace 管理,打开 xcodeproj 大概率会报缺失模块的错误。
打开工程后,按下面几步操作:
- 在 Xcode 左侧导航栏选中根节点
Runner,打开Signing & Capabilities标签页。 - 勾选Automatically manage signing,让 Xcode 自动管理证书和描述文件。手工管理证书对新手来说太容易出错了。
- Team下拉框选择你的开发者账号,这里会要求输入 Apple ID 并做双重认证,耐心走完。
- Bundle Identifier确认与 FlutterFlow 里填的完全一致,哪怕一个字符都不能差。
签名这块最常见的报错是No accounts with access to iOS Distribution或Provisioning profile doesn't include signing certificate。前者通常是账号类型不对——个人免费账号没有分发权限;后者则多出现在手动签名时证书和描述文件不匹配。用自动管理基本能规避绝大多数签名问题。
还要留意 Xcode 右侧的Minimum Deployments版本。Flutter 现在默认支持的最低版本通常是 iOS 12 或 13,如果你没改过就不用动。但要注意,如果你的用户群体里有大量旧设备用户,把最低版本定得太高会把一部分用户挡在门外。这个配置在 FlutterFlow 里也可以提前设置,导出前检查一下。
3.3 归档(Archive)并上传到 App Store Connect
签名配置完成后,就是整个流程里最紧张的时刻:归档上传。操作路径很简单,但在归档之前,有两个准备动作不能省略。
第一,确认 Xcode 已经连接到开发者账号并且能访问 App Store Connect。在 Xcode 的菜单栏选择Settings > Accounts,左侧应该能看到你的 Apple ID,右侧有App Store Connect标识。如果这里出现认证失败,或者在上传时遇到热搜里提到的xcode unable to authenticate with app store connect,先别急着查网络,我这边实测下来最常见的原因有三个:Apple ID 没开双重认证、账号需要重新登录、或者用了第三方网络代理导致 Xcode 连不上苹果的认证服务器。
第二,把 Run 目标选成 Generic iOS Device,而不是你的真机或者模拟器。如果选了模拟器,Archive 按钮是灰色的;选了真机,归档出来的包只适用于该设备架构,根本过不了上传校验。在 Xcode 顶部中间的下拉菜单里选Any iOS Device (arm64)。
然后执行:
- 菜单栏
Product > Archive,Xcode 开始编译并归档。 - 等待编译完成(第一次编译会特别慢,因为要拉取所有 Pod 依赖并编译 Flutter engine,我见过第一次编译花了 20 多分钟的)。
- 编译成功后会弹出
Organizer窗口,选中刚才的归档记录,点击右侧Distribute App。 - 在弹出的向导里选择
App Store Connect,然后一路默认选项(Upload Symbols、Include bitcode 等)点击下一步。 - 最后选择你的开发者账号和团队,点击 Upload,等待上传成功。
上传成功后,Xcode 会显示成功提示。这时候登录 App Store Connect ,在“App 构建版本”里就能看到你上传的构建包,但它的状态会先显示“正在处理”,需要等待几分钟到几十分钟。
归档上传这一步失败率最高,而且失败原因五花八门。只能说多留点耐心,按错误信息去查,绝大多数都能通过重新签名或重新导出解决。更具体的排查方法我在第五部分列一个速查表。
4. TestFlight 内测与正式提审,别跳过这一步
4.1 先用 TestFlight 把构建包装到手机上
很多人巴不得跳过 TestFlight 直接提交审核,但我每次都会劝一句:内测是不可省略的安全网,尤其是对于 FlutterFlow 这种低代码生成的应用。你在 FlutterFlow 预览器里看到的交互,和真机上的表现可能有差异,主要是性能、权限弹窗时机、摄像头/相册这类系统能力在预览器里是被模拟的,真机上才会暴露出真实状态。
TestFlight 的使用流程:
- 进入 App Store Connect,选择你的应用,进入
TestFlight标签页。 - 在“构建版本”里看到上传的包变成“可供测试”状态后,点击加号把它添加到测试组。
- 在“测试员”里添加你的 Apple ID 或者测试组的邮箱,对方会收到一封邀请邮件。
- 测试员在自己的 iPhone 上安装 TestFlight App,登录后接受邀请,就能安装你的应用了。
这里有个小技巧:在 TestFlight 里测试时,最好用一台全新的、没安装过同类应用的真机,或者至少卸载掉之前通过开发模式安装的旧包。这样做是为了验证新包能完整走一遍首次启动、权限申请、登录注册的流程。如果一个新用户第一次打开就崩溃,这种问题提审被拒的概率极高。
另外,TestFlight 构建包的有效期是 90 天。这意味着你的内测版本如果拖了太久没提审,之后要重新上传新构建才能继续测试和提交。版本迭代节奏太慢的独立开发者,很容易碰到这种“过期”问题。
4.2 提审前的资料清单:截图、描述与隐私信息
TestFlight 测完,确认基本功能没问题,接下来就是提审前的资料准备。这一步非常磨人,但资料填得越完整,审核通过率越高。
在 App Store Connect 的“App Store”标签页,需要填写的主要内容:
- 描述:要简明扼要地说清楚你的应用是干什么的。审核人员会拿着这个描述跟你的应用实际功能做对比,如果你的描述说“这是一个记账应用”,但实际打开让人摸不着头脑,很大概率被拒。
- 关键词:最多 100 个字符,逗号分隔。建议放 3-5 个核心词,不要堆砌无关热词,苹果明确反对关键词堆砌。
- 截图:必须用真实设备截图。FlutterFlow 预览器的截图尺寸往往不符合 App Store 要求,最简单的方式是用 TestFlight 装到真机上,用 Xcode 的截图工具或者直接
Command+S截取。6.7 英寸和 6.1 英寸两种尺寸的截图建议都准备。 - 隐私政策 URL:前面说过,只要有数据收集就必须要。哪怕你的应用真的不收集任何数据,苹果现在也要求在“App 隐私”模块里声明所有数据收集行为,并链接到隐私政策。
- 年龄分级:一份问卷,按实际情况勾选即可。如果应用有用户生成内容,年龄分级会偏高。
- 出口合规信息:一般选“否,未使用加密”,除非你的应用明确使用了自定义加密算法。
在“定价与销售范围”里,还有一个很多新手没注意的设置,“自动发布”。我强烈建议选择“手动发布”,这样你的应用在审核通过后不会立刻上架。如果你发现某个审核通过后出现致命 bug,还有时间改代码重新提审,避免带着问题直接展示给用户。等确认无误,再在“定价与销售范围”里手动点击“发布”。
4.3 “等待审核”期间能做什么
提交审核后,状态会变成“等待审核”,不用刷新后台干着急,这几件事你可以趁这个时间做:
- 准备应用商店的运营素材:包括宣传文案、社交媒体发帖素材、产品介绍页面。
- 检查崩溃日志和分析数据:在 Xcode 的 Organizer 里如果关联了 App Store Connect,你甚至可以在审核期间看到 TestFlight 阶段的崩溃记录。
- 准备审核备注:如果应用涉及登录,最好准备一个供审核人员使用的测试帐号,在“App 审核信息”里填好,能显著缩短审核周期。
如果审核被拒,也不用慌。App Store Connect 的消息中心会给出明确理由,比如“需要登录才能预览应用”或者“玩法说明不清晰”。按拒审理由逐条修改后,在消息中心回复即可重新提交。拒审不代表应用没救了,大多数情况是资料问题,而不是功能问题。
5. 我踩过的坑和速查表
5.1 高频报错排查清单
| 报错或问题 | 常见原因 | 处理方式 |
|---|---|---|
xcode unable to authenticate with app store connect | Apple ID 未开启双重认证、登录态过期或被验证服务拒绝 | 在 Apple ID 官网开启双重认证;在系统设置里注销并重新登录 Apple ID;在 Xcode 的 Accounts 里删除账号重新添加 |
No accounts with access to iOS Distribution | 当前登录的是免费账号,或者账号没有分发权限 | 登录付费开发者账号;检查 Team 选择是否正确 |
Invalid App Store Icon | 图标带透明通道或尺寸不是 1024x1024 | 用设计工具导出不带 Alpha 通道、不加圆角的 PNG |
ERROR ITMS-90717 | 同上,图标问题 | 同上 |
Missing required icon | 部分尺寸图标缺失 | 回到 FlutterFlow 重新上传全套图标并重新导出 |
Provisioning profile doesn't include signing certificate | 手动签名配置失误 | 开启自动签名;删除旧证书后在开发者后台重新生成 |
| 上传后构建版本在 TestFlight 不见 | 构建还没处理完 / 上传后等待时间不够 | 等 10-30 分钟;重新点击“添加”按钮刷新 |
| 老 MacBook Air (Early 2015) 能上网但连不上 App Store | macOS 系统太老,无法下载安装兼容新版 API 的应用 | 升级 macOS 到官方支持的最高版本;仍不行则换机器或使用云 Mac 服务 |
5.2 三个能明显提速的小习惯
第一个习惯是每次从 FlutterFlow 同步代码后,先跑一次flutter pub get和pod install。FlutterFlow 的云端构建和本地构建环境是有差异的,特别是依赖版本锁定,拉下来之后不定时更新很容易出现本地编译错误。主动执行这两条命令能够提前暴露问题,避免等到 Archive 那一步才报错。
第二个习惯是用语义化版本号 + 日期格式的组合来管理构建号。比如1.0.0 (20241220),这样你在 App Store Connect 后台看到一堆构建版本时,能一眼看出哪个是最近上传的。虽然苹果允许构建号重复使用,但在多个版本并行测试时就容易混乱。
第三个习惯是保留每次归档的 dSYM 文件。Xcode 的 Organizer 里每个归档包都包含 dSYM,上传后别急着删。后面如果出现崩溃日志,你需要 dSYM 来解析系统记录的崩溃堆栈。没有 dSYM,你只能看到一堆十六进制地址,什么也查不出来。这个细节对使用 Flutter 开发的应用尤其重要,因为 Flutter 层还会叠加一层 Dart 符号,没有 dSYM 把 JavaScrip 跟 Dart 对应起来,排查崩溃相当痛苦。
5.3 上架不是终点,发布后的事同样重要
应用上架后,我见过很多人的第一反应是“终于结束了”。但以我自己的经验来看,发布那刻其实是新一轮循环的开始。你要留意 App Store Connect 的“App 分析”后台,看崩溃率、卸载率、页面停留这几个基础指标;要留意用户评论里的功能请求,整理成下一版本的开发优先级;要关注苹果每年 6 月的 WWDC,因为 iOS 系统更新往往伴随着审核条款的变化。
还有个细节:FlutterFlow 依赖的 Flutter 版本是在云端打包时固定的。如果苹果在某次 iOS 更新后要求最低部署版本提高,或者 Xcode 更新后强制新构建必须用新版 SDK 编译,你需要在 FlutterFlow 里把 Flutter 版本升级一下,再重新导出、重新构建。这类“被迫升级”无法提前预判,只能保持关注。
回到文章开头那个问题——用 FlutterFlow 做应用,开发阶段确实很爽,但从“做出来”到“在 App Store 上架”,该走的路一步都少不了。我个人实际操作下来的体会是:第一次走完整个流程之后,第二次再发版本会顺畅很多,因为最难的那部分其实是账户、签名、资料规范这些一次性的学习成本。按照上面这个顺序,先把账号和签名跑通,再用 TestFlight 完成真机验证,最后把资料填完整,发布这件事并没有想象中那么吓人。