尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Flutter iOS IPA命令行打包:标准路径与免Xcode实战指南

Flutter iOS IPA命令行打包:标准路径与免Xcode实战指南 1. 为什么“Flutter 打包 iOS IPA”这件事值得单独写一篇硬核实操笔记Flutter 开发 iOS 应用时打包成 IPA 文件是交付、测试、上架前绕不开的临门一脚。但很多人卡在这一步Xcode 界面操作复杂、依赖环境脆弱、命令行报错信息晦涩、CI/CD 流水线里反复失败……更关键的是“免 Xcode”这个需求不是噱头而是真实存在的工程痛点——比如你用的是 macOS 虚拟机无图形界面、团队里只有 Linux/macOS CLI 环境、或者 CI 服务器压根没装 Xcode GUI、又或者你只是想快速验证一个构建脚本是否可靠根本不想打开那个动辄 15GB 的 Xcode 应用。我做过 7 个上线的 Flutter iOS 项目从早期用 Xcode 11 手动点十几次弹窗到后来在 GitHub Actions 上用纯命令行完成签名、归档、导出全流程踩过的坑足够填满一个 Swift 编译错误日志。今天这篇不讲“Flutter 是什么”“怎么装 SDK”只聚焦一件事如何用命令行把 Flutter 项目干净、稳定、可复现地打包成 IPA并且提供两种路径——标准 Xcode 集成路径兼容性最强以及真正意义上的免 Xcode CLI 路径不依赖 Xcode.app 图形界面仅需 Command Line Tools codesign 工具链。核心关键词全部覆盖Flutter、iOS、IPA、命令、Xcode。其中“命令”不是泛指flutter build ios这种表层指令而是深入到xcodebuild archive参数组合、codesign签名链构造、altool或notarytool上传验证、security find-identity证书定位等真实生产级操作“免 Xcode”也不是跳过签名而是明确告诉你Xcode.app 本身可以不启动、不打开、不点击任何按钮只要系统有xcodebuildCLI、codesign、security、pkgutil等工具就能完成从源码到可安装 IPA 的全链路。适合谁看正在被 Xcode 卡在“Signing Capabilities”页反复刷新的中级开发者搭建 Flutter iOS 自动化构建流水线的 DevOps 工程师使用 macOS Server 或 M1/M2 Mac Mini 做构建节点、但不想装完整 Xcode 的运维同学想搞懂 IPA 内部结构、签名机制、 entitlements 权限逻辑的技术负责人甚至包括刚学完flutter create就想试试真机安装的新手——我会把每一步的“为什么”和“不这么做会怎样”都写清楚。下面进入正题。这不是教程汇编而是我把三年来在不同客户现场、不同 CI 环境、不同 Apple Developer Account 权限下验证过的方案掰开揉碎一行命令一行解释地给你还原出来。2. 整体设计思路拆解为什么必须分“标准路径”与“免 Xcode 路径”2.1 标准路径Xcode 是 Apple 官方唯一认证的“签名权威代理”Apple 对 iOS App 分发有严格信任链要求App 必须由 Apple 颁发的证书签名签名必须嵌入特定 entitlements如 push notification、keychain access最终 IPA 必须包含完整的签名资源_CodeSignature、embedded.mobileprovision、SwiftSupport 等。Xcode 之所以不可替代是因为它内部封装了三套 Apple 私有机制Provisioning Profile 解析引擎能动态解析.mobileprovision文件里的 UUID、App ID、设备列表、Entitlements 列表并自动映射到 Xcode 项目配置Automatic Signing 后台服务调用altool和iTMSTransporter与 Apple Developer Portal 实时通信自动创建/更新证书、ProfileArchive 构建沙盒在DerivedData下建立隔离构建环境确保符号表、dSYM、Bitcode 等产物路径可控避免多项目交叉污染。所以“标准路径”的本质是用 Xcode CLIxcodebuild作为受信入口调用 Apple 官方构建工具链让整个签名流程符合 Apple 审核预期。它不追求“最简”而追求“最稳”——99% 的 App Store 审核驳回根源都在签名环节不合规而非代码逻辑。提示如果你的项目启用了 Push Notification、Background Fetch、Associated Domains 等能力标准路径几乎是唯一选择。因为这些功能对应的 Entitlements 必须由 Apple Portal 生成的 Profile 显式授权手动构造极易出错。2.2 免 Xcode 路径绕过 GUI直击工具链底层靠的是对签名机制的透彻理解“免 Xcode”不是不用 Apple 工具而是不用 Xcode.app 这个巨型 IDE。macOS 系统自带的 Command Line Tools 已包含所有必需组件xcodebuildXcode 的命令行构建工具独立于 GUI 存在codesignApple 官方签名工具负责对 Mach-O 二进制、Frameworks、PlugIns 等逐层签名security管理钥匙串Keychain用于读取本地证书pkgutil校验签名完整性ditto/zip打包 IPA本质是 ZIP 归档altool已弃用或notarytool上传至 Apple Notary Service 做公证macOS 10.15 强制要求。这条路径的核心逻辑是把 Xcode 的“自动签名”过程拆解为可编程、可审计、可复现的原子步骤——先用flutter build ios --release生成未签名的.app再用xcodebuild -exportArchive导出归档此时仍无签名最后用codesign手动注入证书、Profile、Entitlements并递归签名所有子模块。它的优势非常明显构建环境轻量Command Line Tools 仅 2GBXcode.app 15GBCI/CD 可控性强所有参数明文可见无 GUI 状态干扰便于调试签名问题你能看到每一层codesign -dvvv MyApp.app的输出支持离线签名证书和 Profile 提前导出无需联网调用 Portal。但它对开发者要求更高你得懂.mobileprovision里Entitlements字段怎么映射到MyApp.entitlements文件得知道--deep参数何时该用、何时禁用用错会导致签名失效得明白ad-hoc、development、distribution三种签名类型对应的不同证书和 Profile 规则。注意免 Xcode 路径无法启用 Xcode 的 Automatic Signing 功能所有证书、Profile、Entitlements 必须手动准备、手动指定。这不是偷懒路径而是“掌控力”路径——你放弃便利性换取完全透明的构建过程。2.3 两条路径的适用边界比你想的更清晰我们常误以为“免 Xcode”是为了省空间其实真正决策依据是Apple Developer Account 权限模型和分发场景场景推荐路径原因首次提交 App Store无历史证书/Profile标准路径Xcode 能自动创建 App ID、生成证书、下载 Profile避免手动配置错误企业内部分发In-House已有完整证书体系免 Xcode 路径可固化签名脚本避免每次打开 Xcode 重新配置CI 中稳定复现TestFlight Beta 测试需频繁构建标准路径配合xcodebuild -archivePathXcode 能自动处理 TestFlight 专用 Profile 的 Bundle ID 匹配CI/CD 流水线跑在 macOS VM无 GUI免 Xcode 路径VM 通常只装 CLTXcode.app 启动失败或渲染异常需要自定义 Entitlements如添加com.apple.developer.associated-domains免 Xcode 路径手动编辑.entitlements文件比在 Xcode GUI 里勾选更精准、可 Git 版本控制我去年帮一家教育 SaaS 公司做自动化发布他们用 M1 Mac Mini 做构建节点最初强行装 Xcode.app结果每次xcodebuild clean都卡死——因为虚拟化层对 Metal 图形加速支持不全。换成免 Xcode 路径后构建时间从 8 分钟降到 3 分钟失败率从 37% 降到 0%。这不是玄学是工具链层级的确定性胜利。3. 核心细节解析与实操要点从 Flutter 项目到 IPA每一步都在做什么3.1 前置条件检查5 个必须确认的硬性门槛在敲任何一条命令前请务必确认以下五点。少一个后续 90% 的报错都源于此Flutter SDK 版本 ≥ 3.16推荐 3.22低版本对 Xcode 15 的新签名机制如notarytool替代altool支持不全。执行flutter --version查看若低于 3.16先运行flutter upgrade。注意升级后务必执行flutter pub get和flutter clean否则旧缓存可能引发Runner.app缺失Flutter.framework。macOS 系统版本 ≥ 13.0VenturaXcode 15 要求 macOS 13而免 Xcode 路径依赖的notarytool在 macOS 12 及以下不可用。sw_vers命令查看版本。若为 Monterey12.x请降级使用 Xcode 14.2 altoolApple 已于 2024 年 3 月停用altool但旧版仍可临时用。Apple Developer Account 已开通 Paid Program年费 99 美元免费账号无法生成 Distribution Certificate 和 App Store Connect API Key这是硬性限制。登录 developer.apple.com 确认账户状态。注意Team ID10 位字母数字和 Bundle ID如com.example.myapp必须提前在 Portal 创建并启用对应 Capability。本地钥匙串Keychain中存在有效的 Distribution Certificate打开Keychain Access.app→ 左侧选login→ 点击Certificates分类 → 查找以Apple Distribution: Your Name (XXXXXXXXXX)开头的证书。右键 →Get Info→ 展开Trust→ 确保When using this certificate设为Use System Defaults。若证书显示This certificate is not trusted双击证书 →Trust→Always Trust→ 输入密码确认。已下载并放置正确的 Provisioning Profile 到~/Library/MobileDevice/Provisioning Profiles/不是随便下载一个.mobileprovision就行。必须匹配Certificate与钥匙串中证书 Team ID 一致App ID与ios/Runner.xcworkspace/xcshareddata/xcschemes/Runner.xcscheme中BuildableProductRunnable的RunnableProductReference一致DevicesAd-Hoc 分发需包含目标设备 UDIDEntitlements必须包含项目实际使用的权限如aps-environment。下载后双击安装或手动复制到上述路径需mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles/。实操心得我见过最多的问题是 Profile 与证书不匹配。用命令行快速验证security find-certificate -p -p /Users/yourname/Library/Keychains/login.keychain-db | openssl x509 -noout -text | grep Subject:查看证书 Subject再用grep -A1 ApplicationIdentifier ~/Library/MobileDevice/Provisioning\ Profiles/*.mobileprovision | grep -E (YourTeamID|com\.example)查看 Profile 绑定的 Team ID 和 Bundle ID。两者必须完全一致。3.2 Flutter 项目配置ios/Runner/ 目录下的三个关键文件Flutter 项目的 iOS 部分核心配置集中在ios/Runner/目录。这三个文件改错一个打包必挂Info.plist定义 App 元信息。重点检查CFBundleIdentifier必须与 Apple Developer Portal 中创建的 App ID 完全一致大小写敏感UIBackgroundModes若用 Background Fetch需添加fetchNSAppTransportSecurity若需 HTTP 请求添加NSAllowsArbitraryLoads YES仅开发用上架必须删LSApplicationQueriesSchemes若用url_launcher打开微信、支付宝等需在此声明weixin、alipay等 scheme。Runner.xcodeproj/project.pbxprojXcode 项目配置文件。不要手动编辑所有修改应通过 Xcode GUI 或flutter build ios自动生成。常见错误是手动修改导致PBXProject结构损坏表现为xcodebuild报file not found: Runner.xcodeproj/project.pbxproj。修复方法删除ios/Podfile.lock、ios/Pods/、ios/.symlinks/然后cd ios pod install --repo-update。Entitlements-Debug.plist与Entitlements-Release.plist定义签名权限。这是免 Xcode 路径的关键。Debug 版本通常只需get-task-allow YESRelease 版本必须严格匹配 Profile 中声明的 Entitlements。例如Profile 含aps-environment则Entitlements-Release.plist必须有keyaps-environment/key stringproduction/string若用 Keychain Sharing需添加keykeychain-access-groups/key array string$(AppIdentifierPrefix)com.example.myapp/string /array注意Flutter 3.16 默认生成Entitlements-Release.plist但内容为空。你必须根据 Portal 中 Profile 的实际 Entitlements 手动补全。漏一项codesign会报resource fork, Finder information, or similar detritus not allowed。3.3 签名机制原理为什么 IPA 里要塞进 3 层签名IPA 本质是 ZIP 包解压后结构为Payload/ └── Runner.app/ ├── _CodeSignature/ ← 主签名目录 │ └── CodeResources ← 资源哈希清单 ├── Frameworks/ ← Flutter.framework 等 │ └── Flutter.framework/ │ └── _CodeSignature/ ← Framework 签名 ├── PlugIns/ ← Extension 插件 │ └── ShareExtension.appex/ │ └── _CodeSignature/ ← 插件签名 └── Runner ← Mach-O 主二进制Apple 要求每一层可执行单元都必须独立签名且签名必须嵌套验证Runner二进制签名 → 验证Runner.app完整性Flutter.framework签名 → 验证框架未被篡改ShareExtension.appex签名 → 验证扩展模块可信最外层_CodeSignature/CodeResources记录所有资源图片、plist、storyboard的 SHA256 哈希防止资源被替换。这就是为什么codesign必须递归执行# 错误只签主 App codesign -f -s Apple Distribution: Your Name (XXXXXX) Runner.app # 正确逐层签名 codesign -f -s Apple Distribution: Your Name (XXXXXX) Runner.app/Frameworks/Flutter.framework codesign -f -s Apple Distribution: Your Name (XXXXXX) Runner.app/PlugIns/ShareExtension.appex codesign -f -s Apple Distribution: Your Name (XXXXXX) --entitlements Runner.entitlements Runner.app--entitlements参数指定的.entitlements文件会被注入到Runner.app的签名中成为Runner.app/_CodeSignature/CodeResources的一部分。Apple 审核时会提取这个文件比对 Profile 中声明的权限是否超限。实操心得codesign -dvvv Runner.app是我的每日必查命令。输出中Executable行显示主二进制路径Identifier行显示 Bundle IDAuthority行显示证书名称Entitlements块显示所有权限。如果Entitlements为空说明--entitlements未生效或文件路径错误。4. 实操过程与核心环节实现两种路径的完整命令流4.1 标准路径Xcode CLI 全流程推荐新手与 App Store 首发步骤 1生成 Release 构建Flutter 层# 确保在项目根目录 cd /path/to/your/flutter/project # 清理旧构建重要避免缓存冲突 flutter clean # 生成 Release 模式 iOS 构建不签名仅编译 flutter build ios --release --no-codesign # 输出路径build/ios/archive/Runner.xcarchive # 注意此命令不启动 Xcode GUI仅调用 xcodebuild CLI--no-codesign是关键。它告诉 Flutter别碰签名我后面自己用 Xcode 处理。这避免了 Flutter 尝试用钥匙串默认证书签名导致的权限错误。步骤 2用 xcodebuild 归档并导出 IPAXcode 层# 进入 ios 目录 cd ios # 设置环境变量指定证书和 Profile export TEAM_IDYOUR_TEAM_ID # 如 A1B2C3D4E5 export BUNDLE_IDcom.example.myapp export METHODapp-store # ad-hoc, enterprise, development # 执行归档Archive xcodebuild archive \ -workspace Runner.xcworkspace \ -scheme Runner \ -configuration Release \ -archivePath build/Runner.xcarchive \ -destination generic/platformiOS \ CODE_SIGN_IDENTITYApple Distribution: Your Name (XXXXXXXXXX) \ PROVISIONING_PROFILE_SPECIFIERYour App Store Profile Name \ PRODUCT_BUNDLE_IDENTIFIER$BUNDLE_ID \ DEVELOPMENT_TEAM$TEAM_ID \ CODE_SIGN_STYLEManual \ ENABLE_BITCODENO \ OTHER_CODE_SIGN_FLAGS--keychain /Users/yourname/Library/Keychains/login.keychain-db # 执行导出Export xcodebuild -exportArchive \ -archivePath build/Runner.xcarchive \ -exportPath build/exports \ -exportOptionsPlist exportOptions.plistexportOptions.plist文件需提前创建内容如下根据分发方式调整?xml version1.0 encodingUTF-8? !DOCTYPE plist PUBLIC -//Apple//DTD PLIST 1.0//EN http://www.apple.com/DTDs/PropertyList-1.0.dtd plist version1.0 dict keymethod/key stringapp-store/string !-- ad-hoc, enterprise -- keyteamID/key stringYOUR_TEAM_ID/string keyuploadSymbols/key true/ keyuploadBitcode/key false/ keycompileBitcode/key false/ /dict /plist步骤 3验证 IPA 签名完整性# 解压 IPA本质是 ZIP unzip -q build/exports/Runner.ipa -d build/exports/Payload # 检查主 App 签名 codesign -dv --verbose4 build/exports/Payload/Runner.app # 检查 Framework 签名 codesign -dv --verbose4 build/exports/Payload/Runner.app/Frameworks/Flutter.framework # 校验整个 IPA pkgutil --check-signature build/exports/Runner.ipa正常输出应含Status: signed和Signed Chain:后跟证书链。若报CSSMERR_TP_NOT_TRUSTED说明证书未被系统信任需按 3.1 节修复钥匙串。实操心得xcodebuild archive成功率远高于 GUI 操作。GUI 常因窗口焦点、弹窗阻塞失败而 CLI 可加-quiet参数静默运行。我在 GitHub Actions 中用此命令成功率 100%而 Xcode GUI 自动化点击成功率不足 60%。4.2 免 Xcode 路径纯命令行签名推荐 CI/CD 与高级用户步骤 1生成无签名 .app同标准路径flutter clean flutter build ios --release --no-codesign # 输出build/ios/archive/Runner.xcarchive/Products/Applications/Runner.app步骤 2准备签名材料手动从钥匙串导出证书security find-certificate -p -p /Users/yourname/Library/Keychains/login.keychain-db cert.pem从 Portal 下载 Profilecurl -O https://developerservices.apple.com/download/profiles/...手动编写Runner.entitlements内容必须与 Profile 一致步骤 3逐层签名核心# 定义变量 APP_PATHbuild/ios/archive/Runner.xcarchive/Products/Applications/Runner.app CERT_NAMEApple Distribution: Your Name (XXXXXXXXXX) PROFILE_PATH/path/to/Your_Distribution_Profile.mobileprovision ENTITLEMENTS_PATHios/Runner/Entitlements-Release.plist # 1. 将 Profile 注入 App cp $PROFILE_PATH $APP_PATH/embedded.mobileprovision # 2. 签名所有 Frameworks必须先签依赖库 find $APP_PATH/Frameworks -name *.framework -type d | while read framework; do codesign -f -s $CERT_NAME --entitlements $ENTITLEMENTS_PATH $framework done # 3. 签名主 App关键--entitlements 和 --deep codesign -f -s $CERT_NAME \ --entitlements $ENTITLEMENTS_PATH \ --timestampnone \ --deep \ $APP_PATH # 4. 验证签名 codesign -dv --verbose4 $APP_PATH--deep参数作用递归签名Frameworks/、PlugIns/下所有可执行文件。但注意--deep在 Xcode 15 中可能导致 SwiftSupport 签名失败此时应去掉--deep改为显式签名每个子模块。步骤 4打包 IPA 并公证Notarization# 创建 Payload 目录 mkdir -p build/ipa/Payload cp -r $APP_PATH build/ipa/Payload/ # 打包 IPA cd build/ipa zip -qr ../Runner.ipa Payload/ # 上传公证需 Apple ID 凭据 xcrun notarytool submit ../Runner.ipa \ --key-id YOUR_APP_STORE_CONNECT_API_KEY_ID \ --issuer YOUR_ISSUER_ID \ --password keychain:notarytool-password \ --wait # Staple 公证结果到 IPA xcrun stapler staple ../Runner.ipanotarytool需提前配置 API Key在 App Store Connect →Users and Access→Keys创建保存Key ID、Issuer ID并将私钥.p8文件放入~/.appstoreconnect/api_keys/。实操心得公证是上架强制步骤。--wait参数会阻塞直到公证完成通常 5-15 分钟。若失败xcrun notarytool log --uuid UUID_FROM_SUBMIT查看详细错误。常见原因是Runner.entitlements中get-task-allow为YESRelease 版必须为NO。4.3 两种路径的输出对比与 IPA 结构验证项目标准路径输出免 Xcode 路径输出验证命令IPA 大小略大含 Bitcode、dSYM更小可禁用 Bitcodels -lh Runner.ipa签名层级Xcode 自动处理_CodeSignature完整手动控制需codesign -dvvv逐层验证codesign -dvvv Runner.appEntitlements 注入Xcode 自动从 Profile 提取必须手动匹配错一个即审核失败security cms -D -i embedded.mobileprovision | grep -A5 Entitlements公证支持xcodebuild -exportArchive自动调用notarytool需显式xcrun notarytool submitspctl -a -t exec -v Runner.ipa最终验证 IPA 是否可安装# 用 ideviceinstaller需 brew install libimobiledevice ideviceinstaller -i Runner.ipa # 或用 Apple Configurator 2 图形界面拖入若提示The bundle is damaged90% 是签名链断裂若提示Untrusted developer则是证书未被设备信任需在Settings → General → Device Management中信任。5. 常见问题与排查技巧实录那些让你加班到凌晨的报错5.1 “No signing certificate “Apple Development” found” —— 证书找不到现象xcodebuild archive报错提示找不到 Development 证书但钥匙串里明明有。原因钥匙串中证书的Trust设置为System Defaults而 CLI 环境默认不信任。或证书私钥权限被锁。解决# 重置钥匙串信任设置 security trust-settings-export /tmp/trust.plist security trust-settings-import /tmp/trust.plist # 解锁私钥输入钥匙串密码 security unlock-keychain -p your_password login.keychain-db # 强制指定钥匙串 xcodebuild ... CODE_SIGN_IDENTITYApple Development: Your Name (XXXXXX) \ OTHER_CODE_SIGN_FLAGS--keychain /Users/yourname/Library/Keychains/login.keychain-db5.2 “Provisioning profile doesnt include the currently selected device” —— 设备不匹配现象Ad-Hoc 分发时xcodebuild报错设备 UDID 不在 Profile 中。原因Profile 下载后未更新或设备 UDID 录入 Portal 时格式错误多了空格、换行。解决# 获取设备真实 UDID连接 iPhone用 iTunes 或 Finder 查看 system_profiler SPUSBDataType \| grep Serial Number -A2 # 用命令行获取需先信任电脑 idevice_id -l # 输出 UDID # 验证 Profile 包含该 UDID grep -A10 ProvisionedDevices ~/Library/MobileDevice/Provisioning\ Profiles/*.mobileprovision \| grep YOUR_UDID5.3 “Runner.app/Frameworks/Flutter.framework: resource fork, Finder information, or similar detritus not allowed” —— 资源叉错误现象codesign签名 Framework 时报此错。原因Flutter.framework被 macOS Finder 添加了资源叉Resource Fork元数据codesign拒绝签名。解决永久方案# 清理整个 Runner.app 的资源叉 xattr -rc $APP_PATH # 清理单个 Framework xattr -rc $APP_PATH/Frameworks/Flutter.framework # 验证清理结果无输出即成功 xattr -l $APP_PATH/Frameworks/Flutter.framework5.4 “The application does not have a valid signature” —— 签名无效现象IPA 安装后闪退Xcode Organizer 显示签名无效。排查链codesign -dvvv Runner.app→ 检查Authority是否为你证书security find-certificate -p -p login.keychain-db \| openssl x509 -noout -text \| grep Subject:→ 确认证书 Subject 一致grep -A5 Entitlements embedded.mobileprovision→ 比对Runner.entitlementsls -la Runner.app/Frameworks/→ 确认Flutter.framework存在且非空otool -L Runner.app/Runner→ 检查二进制链接的 Framework 路径是否正确应为rpath/Flutter.framework/Flutter。5.5 CI/CD 中 “xcodebuild: command not found” —— 工具链缺失现象GitHub Actions 或 Jenkins 报xcodebuild: command not found。原因macOS runner 默认只装 Command Line Tools未装 Xcode CLI。解决GitHub Actions 示例steps: - name: Install Xcode CLI run: | sudo xcode-select --install # 等待安装完成 sleep 60 sudo xcode-select -s /Applications/Xcode.app/Contents/Developer或直接用官方setup-xcodeaction- uses: maximilien/xcode-installv1 with: xcode-version: 15.2实操心得我在 CircleCI 上遇到过xcode-select -p返回/usr/bin但xcodebuild不在该路径。解决方案是sudo xcode-select -s /Applications/Xcode.app/Contents/Developer强制指定。CI 环境的xcode-select状态极不稳定每次构建前都应xcode-select -p which xcodebuild双重验证。6. 进阶技巧与工程化建议让打包不再是“玄学操作”6.1 构建脚本自动化一个可复用的build-ios.sh把上述流程封装为脚本是团队协作的基础。以下是我正在用的精简版去除了敏感信息#!/bin/bash # build-ios.sh set -e # 任一命令失败即退出 APP_NAMERunner BUNDLE_IDcom.example.myapp TEAM_IDA1B2C3D4E5 CERT_NAMEApple Distribution: Your Name (XXXXXXXXXX) PROFILE_NAMEMyApp App Store Distribution ENTITLEMENTSios/Runner/Entitlements-Release.plist echo ✅ 清理旧构建 flutter clean echo ✅ 生成 Release 构建 flutter build ios --release --no-codesign echo ✅ 开始 Xcode 归档 xcodebuild archive \ -workspace ios/Runner.xcworkspace \ -scheme $APP_NAME \ -configuration Release \ -archivePath build/ios/archive/$APP_NAME.xcarchive \ -destination generic/platformiOS \ CODE_SIGN_IDENTITY$CERT_NAME \ PROVISIONING_PROFILE_SPECIFIER$PROFILE_NAME \ PRODUCT_BUNDLE_IDENTIFIER$BUNDLE_ID \ DEVELOPMENT_TEAM$TEAM_ID \ CODE_SIGN_STYLEManual \ ENABLE_BITCODENO \ OTHER_CODE_SIGN_FLAGS--keychain /Users/runner/Library/Keychains/login.keychain-db echo ✅ 导出 IPA xcodebuild -exportArchive \ -archivePath build/ios/archive/$APP_NAME.xcarchive \ -exportPath build/exports \ -exportOptionsPlist ios/exportOptions.plist echo ✅ 验证签名 codesign -dv --verbose4 build/exports/Payload/$APP_NAME.app echo IPA 生成完成build/exports/$APP_NAME.ipa存为build-ios.shchmod x build-ios.sh一键执行。CI 中直接调用即可。6.2 多环境支持用.env管理不同 Profile为 Development、Ad-Hoc、App Store 创建不同exportOptions.plist并用环境变量切换# .env.development METHODdevelopment PROFILE_NAMEMyApp Dev Profile CERT_NAMEApple Development: Your Name (XXXXXXXXXX) # .env.appstore METHODapp-store PROFILE_NAMEMyApp App Store Profile CERT_NAMEApple Distribution: Your Name (XXXXXXXXXX)脚本中加载source .env.$ENVIRONMENT xcodebuild ... PROVISIONING_PROFILE_SPECIFIER$PROFILE_NAME ...6.3 签名审计每次构建后自动生成签名报告在脚本末尾加入echo 签名审计报告 build/exports/signing-report.txt echo Certificate: build/exports/signing-report.txt codesign -dvvv build/exports/Payload/$APP_NAME.app \| grep Authority: build/exports/signing-report.txt echo Entitlements: build/exports/signing-report.txt security cms -D -i build/exports/Payload/$APP_NAME
返回列表