1. 无效二进制文件到底是什么:先别慌,这是苹果没把话说清楚
前阵子帮团队处理一个上架卡点:ipa 包通过 Transporter 上传到 App Store Connect 之后,后台状态栏明晃晃地显示 Invalid Binary,也就是我们常说的“无效二进制文件”。邮箱里只收到一封模板邮件,大意是“你的交付存在问题”,具体原因却一个字没写。当时离计划上线只剩一天,说心态不崩是假的。
后来静下心排查,发现问题其实出在工程配置上,不是什么硬核调优,但搜起来确实费时间。所以我决定把这套排查流程完整写出来,从“无效二进制到底是什么”讲起,然后带着你一步一步定位、修复、重新打包上传。这篇文章适合第一次遇到 Invalid Binary 的 iOS 开发者,也适合被这个问题折腾到想摔键盘的运维和 CI/CD 负责人。
1.1 它不是单一错误,而是一类“整包体检”问题
很多人第一次看到 Invalid Binary 会以为是自己代码写崩了,其实不是。苹果在上传成功后,并不会立刻把包放上 TestFlight,而是会先对 ipa 做一轮自动化检查。这一轮检查覆盖的范围很广:Bundle ID 是否和后台 App ID 对上、Info.plist 里的权限描述是否完整、签名证书是不是 Distribution、包里的可执行文件架构是否符合要求、1024 图标是不是带透明通道、启动屏配置是否存在、是否用了 beta 版 SDK、是否包含私有 API 等。
只要其中任何一项没通过,后台就会把构建状态标记成 Invalid Binary。这个状态相当于一颗“垃圾桶式状态”:它只告诉你“这包不合格”,但不会告诉你具体是哪一处不合格。你可能会在邮件里看到一两个 ITMS 开头的错误码,也可能什么都看不到,后台只有一行冷冰冰的状态提示。
这也是为什么很多人遇到这问题会抓狂:如果你把无效二进制当成一个具体的错误,顺着一个方向去查,很容易陷入死胡同。正确的思路是把这当成“整包体检未通过”,然后按流程把几个高频检查项全过一遍。
1.2 Invalid Binary 之后的典型流程
一旦构建被标记为 Invalid Binary,这个构建号就算废了。你无法在 TestFlight 里选择它,也无法用它去提交 App Store 审核。更关键的是,你不能把原来的 ipa 重新上传一次,并指望它能覆盖掉原来那个无效构建。App Store Connect 的后端是拿构建号来区分包的,同一个构建号在你的 App 记录里已经存在了,哪怕你重新打包,服务器也只会保留最早收到的那个无效版本。
所以遇到 Invalid Binary 之后,正确的操作顺序只有一条:定位问题、修复问题、把构建号递增、重新 Archive、重新导出、重新上传。这也是为什么我会在后面的实操环节反复强调“先递增 Build 号再上传”,很多人就是因为第一次失败后没改构建号,结果上传后后台还是显示旧的失败状态,白白浪费了半小时。
1.3 最容易踩坑的场景
以我这几年的经验,无效二进制最容易出现在下面几类场景里:
- 新项目第一次上架,Bundle ID、证书、描述文件是多方协作配置的,任何一个环节对不上,都会触发检查失败。
- 升级了 Xcode 或者 macOS 大版本之后第一次打包,工程里有些旧配置可能不再兼容新版构建工具。
- 用 CI 机器打包,多台机器上 Xcode 版本或导出方式不一致,导致生成出来的 ipa 差了一点。
- 换过开发者账号或者重新生成了证书、描述文件,旧文件的缓存还在,签名信息出现错位。
- 项目里接了大量第三方 SDK 或者做了资源目录特殊定制,某个小文件格式不对,就可能被“一刀切”。
这些问题单独看都不复杂,但混合在一起时,排查成本就上来了。后面几个小节,我把排查方法按顺序拆开,你照着做就行。
2. 先别急着重新打包:三步定位问题到底出在哪
很多人一看到 Invalid Binary,第一反应是“把构建号加一,再传一次”。如果问题原因是偶发的系统抽风,这招确实有效;但在大多数情况下,问题会原样复现。所以我建议你先把下面这三步做完,基本能在十分钟内定位到问题大概在哪个方向。
2.1 第一步:查邮件和后台的 Activity,抓 ITMS 错误码
先从 App Store Connect 的邮件开始。苹果发的邮件一般会以 “Dear Developer” 开头,主题通常是 “App Store Connect: [App 名称] has one or more issues”。邮件正文里,如果检查发现了具体问题,会列出来,比如:
- ERROR ITMS-90022: Missing Info.plist key. Add NSPhotoLibraryUsageDescription...
- ERROR ITMS-90023: Missing Info.plist key. Add NSBluetoothAlwaysUsageDescription...
- ERROR ITMS-90062: Invalid Bundle...
- WARNING ITMS-90078: Missing Purpose String...
这些错误码非常关键,我后面会专门整理一张速查表。你先把邮件里所有的 ERROR 和 WARNING 全部复制出来,丢到备忘录里。如果邮件里没有错误码,那就到 App Store Connect 的“活动”页面,找到最近一次构建记录,点击状态详情,有时候能看到更完整的原始日志。Transporter 在上传成功后,如果后续处理失败,也会在“查看最近活动”里留下记录,别漏掉这个入口。
2.2 第二步:在本地解包 ipa,核对关键元数据
邮件和后台没有给明确线索时,本地解包 ipa 是最直接的核实手段。别把 ipa 当成黑盒,其实它就是个 zip 包。在终端里执行:
unzip MyApp.ipa -d ipa_unzipped cd ipa_unzipped/Payload/MyApp.app然后查看 Info.plist:
/usr/libexec/PlistBuddy -c "Print" Info.plist或者用系统自带的:
plutil -p Info.plist我一般重点核对这几个字段:
CFBundleIdentifier:必须和 App Store Connect 里创建的 App ID 完全一致。比如后台是com.company.app,包里的 Bundle ID 写成com.company.app.test,上传后基本就是 Invalid Binary。CFBundleShortVersionString:这是用户看到的版本号,比如 1.0.0。CFBundleVersion:这是构建号,必须是纯数字加小数点,不能出现空格、字母等字符。MinimumOSVersion:部署目标版本。如果这个值设置得过低,而构建产物又不支持该系统的某些能力,也容易触发检查失败。DTPlatformName:正常应该是iphoneos。如果变成iphonesimulator,那说明你导出的包根本不是真机包。
核对完这几个字段,再检查一下可执行文件的架构:
lipo -info MyApp这里的MyApp是 app 包里的可执行文件名,通常和 target 名称一致。真机 Release 包应该输出arm64,最多再带一个arm64e。如果看到x86_64或者i386,说明包里有模拟器架构,苹果不接受这种包上架。
2.3 第三步:用 codesign 检查签名与权限
签名信息也是无效二进制的高频雷区。用下面两条命令可以快速确认:
codesign -dv --verbose=4 MyApp codesign -d --entitlements :- MyApp 2>/dev/null重点看三条信息:
Signature对应的证书名称,应该是 Apple Distribution 证书,而不是 Apple Development。TeamIdentifier,必须和 App Store Connect 里的开发者团队 ID 一致。Application-identifier的值,应该与描述文件里的 App ID 前缀和 Bundle ID 拼接结果一致。
如果你看到 “adhoc” 或者证书名称是 “iPhone Developer” 开头,那基本不用继续猜了,重新签名再导出吧。另外也可以用这条命令查看描述文件信息:
security cms -D -i embedded.mobileprovision里面ProvisionedDevices字段如果存在,说明这是开发描述文件,不是 App Store 发布描述文件。用开发描述文件打包上传,也是必挂的。
2.4 第四步:没找到原因也要递增构建号再传
如果你完成了上面三步,但仍然没有明确结论,那我建议别在同一构建号上反复试。App Store Connect 对构建号有“唯一性”要求,同一 App 下不能出现两个相同构建号。失败后的包如果还留着,同一个构建号再传一次,通常只会看到旧状态。
这时候最稳妥的做法是打开 Xcode 工程,在 General 标签页把 Build 加一,比如从 10 改成 11。Version 可以不变,因为版本号是给用户看的,构建号才是给苹果系统区分包用的。改完构建号之后,再重新执行一次完整的 Archive、Export、Upload。不要图省事只动构建号而不做其他修改,至少你这次上传的“身份”是新的,排查过程也会更干净。
3. 高频原因和解决实操:从工程配置到打包链路
这一节我们把无效二进制最常见的几种原因拆开讲。每一条我都会写清楚“为什么会被拒”和“怎么改”,你可以在自己的工程里逐个比对。
3.1 权限描述文案缺失:ITMS-90022 和 ITMS-90023 的重灾区
从 iOS 10 开始,苹果强制要求开发者在使用用户隐私数据时,必须在 Info.plist 里提供用途描述。如果你在代码里调用了相机、相册、位置、麦克风、蓝牙、日历、提醒事项等接口,却缺少对应的NSCameraUsageDescription、NSPhotoLibraryUsageDescription、NSLocationWhenInUseUsageDescription之类的 key,上传到 App Store Connect 时会直接报 ITMS-90022 或 ITMS-90023。
这种问题修复起来不难,就是在 Info.plist 里加上 key。比如 Xcode 的 Info 面板里,直接新增一行:
<key>NSCameraUsageDescription</key> <string>用于拍摄头像和扫描二维码</string>注意几个坑:
- 描述内容不能是空字符串,也不能只写“需要权限”这类敷衍文案。审核时可能会以“用途说明不清晰”为由拒绝。
- 同一个 key 只能有一个值,如果有多个 target,要确保最终打进包里的 Info.plist 也是全的。
- 如果项目里用了聚合打包脚本,可能会在 Copy Bundle Resources 阶段覆盖 Info.plist,这种隐藏问题最难查。
3.2 App 图标有透明通道,或者尺寸不是 1024 平方
App Store 要求应用图标必须是 1024x1024 像素、不带 alpha 通道的正方形 PNG。很多设计工具导出 PNG 时默认保留透明通道,如果你的图标里包含透明区域,上传后就会被判定为无效二进制。
怎么查?两步:
sips -g pixelWidth -g pixelHeight AppIcon1024.png sips -g hasAlpha AppIcon1024.pnghasAlpha如果返回yes,就要把透明通道去掉。最简单的办法是在“预览”App 里打开图片,选择“文件 -> 导出”,格式选 PNG,并取消勾选透明,然后再导入回Assets.xcassets。如果团队用设计软件统一出图,让设计师在导出时把透明选项关掉会更省事。
另外还要确认图标没有放在 App 包根目录,而是必须放在 Assets 的 AppIcon 集中。老项目如果沿用了旧的iTunesArtwork方式,很容易在这个环节挂掉。
3.3 最低系统版本、架构与支持的设备不匹配
随着 Xcode 版本更新,编译器默认输出的架构也在变化。现在的稳定版 Xcode 在 iOS 真机 Release 包中默认只输出arm64,老项目如果曾经手动改过Architectures或Valid Architectures,就可能残留armv7、x86_64等架构。App Store Connect 看到不支持的架构,直接判成 Invalid Binary。
建议在 Build Settings 里检查这几个配置:
Supported Platforms:Release 必须是 iOS。Architectures:Standard architectures即可,不要强行改成$(ARCHS_STANDARD_INCLUDING_64_BIT)。Excluded Architectures:Release 状态下不能排除arm64。有些模板会在 Debug 下排除arm64以提高模拟器编译速度,这没问题,但 Release 一定要排除x86_64和i386。
UIRequiredDeviceCapabilities也是一个隐藏雷点。这个字段如果写错了设备能力值,比如写了armv7,而包本身不支持 armv7,会导致设备兼容性检查失败。如果你不确定,直接用对话框里的默认值,或者干脆不设这个 key。
3.4 启动屏配置不达标
启动屏不是单纯为了好看,它直接关系到 App 是否能适配不同尺寸的屏幕。使用 Launch Screen storyboard 是最推荐的方式,但如果你的工程配置里 Launch Screen File 是空的,或者文件被删掉了,上传时可能出现“bundle 缺少启动图”或类似问题。
从 iOS 14 开始,苹果也允许在 Info.plist 里用UILaunchScreen字典来配置,甚至可以直接设成一个空字典{},让系统自动生成留白启动屏。在 Info.plist 里加一条:
<key>UILaunchScreen</key> <dict/>这个方法对很多老项目很实用,不需要额外维护 storyboard。但要注意,如果你的 App 需要向用户展示品牌形象或背景色,还是建议用正常的 Launch Screen storyboard,不要为了过审而牺牲体验。
3.5 签名、描述文件和导出方式用错
无效二进制里,签名问题可能是最让人无语的。因为你在本地可能已经把 App 跑得很顺,但从 Xcode 导出到上传的过程中,很容易因为“手动签名 vs 自动签名”的选择不同,导致最终 ipa 的签名变成 Development 类型。
在 Xcode 里导出时,如果选择的是 “Development” 而不是 “App Store Connect” 或者 “Distribution”,就会生成开发包。开发包也不是不能上传,但上传后极大概率被标记为无效二进制。正确操作是:
- Product -> Archive。
- 打开 Organizer,点 “Distribute App”。
- 选择 “App Store Connect” -> “Upload” 或 “Export”。
- 签名方式选择 “Automatically manage signing” 或手动选择 Distribution 证书和 App Store 描述文件。
如果用命令行导出,推荐在exportOptions.plist里明确指定:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>method</key> <string>app-store</string> <key>teamID</key> <string>你的TeamID</string> <key>signingStyle</key> <string>manual</string> </dict> </plist>然后执行:
xcodebuild -exportArchive \ -archivePath App.xcarchive \ -exportOptionsPlist exportOptions.plist \ -exportPath export_dir如果你用了第三方自动签名工具或者对 ipa 做过重签名,那我劝你打包上架前最好还是走 Xcode 原始导出链路。App Store 上传包不等于“能装到手机就行”,苹果对签名和包结构的检查比普通侧载严格得多,有些本地工具改过的包,传上去就是无效二进制。
3.6 SDK 版本和构建工具链过旧或过新
苹果经常在邮件里直接写明 “Invalid SDK Version”。最常见的原因是用了 beta 版 Xcode 打包,或者机器上同时装了多个 Xcode,导出时选错了 Developer Directory。
遇到这种问题,先xcode-select -p看看当前命令行的 Xcode 路径指向哪里。然后确认 Xcode 版本是稳定版,并且不是 beta。如果项目必须用某个特定版本的 Xcode,最好在 CI 机器上固定好版本,不要使用/usr/bin/xcodebuild这类外部默认路径,而是直接指定:
/Applications/Xcode_15.4.app/Contents/Developer/usr/bin/xcodebuild用新版本 Xcode 构建老项目时,也可能因为旧的构建系统设置、废弃的脚本而产出不符合要求的包。最直接的办法是把工程的构建系统切到 “New Build System”,然后跑一次干净构建。
3.7 包内容混入了不该有的东西
这一类问题比较隐蔽,常见报错像:
- “The bundle contains a disallowed file.”
- “Invalid Bundle. The app bundle should not contain nested frameworks or bundles.”
- “ERROR ITMS-90125: The binary is invalid. The executable contains bitcode that was not compiled...”
这些通常是因为你的 ipa 里出现了不该出现的文件:临时脚本、.DS_Store、Utils 目录、手工塞进去的动态库、重复的框架等。可以在 ipa 解包后直接看文件列表:
find ipa_unzipped -type f | sed 's#ipa_unzipped/##' | sort如果看到.sh、.log、.txt这类与运行时无关的文件,尽可能删掉再重新打包。平时打包前最好做一次 Clean Build Folder,避免增量编译把旧产物残留到 app 包里。
4. 一次完整的重新打包实操记录
有理论不说实操,等于白说。下面我用一个我最近处理过的真实场景来演示,从一个失败的老项目到成功上传到 App Store Connect,完整流程是什么样。
4.1 场景描述与第一步:先做本地备份
那是一个接手不到一周的旧项目,目标系统最低支持 iOS 13,之前一直在用 Xcode 14 打包。某天同事升级到了 Xcode 15,打出来的包传到后台就变 Invalid Binary。邮件里只有一个 ERROR ITMS-90022,提示NSPhotoLibraryUsageDescription缺失。
我先不着急改代码,先确认当前工程状态:打开 Xcode,查看 Info 面板,发现 App 确实在代码里用了PHPhotoLibrary相关 API,但 Info.plist 里没有权限描述。于是我先在工程里加上:
<key>NSPhotoLibraryUsageDescription</key> <string>需要访问相册以选择和保存图片</string>加完后没有直接打包,因为团队里还有其他人可能在改动代码。我先git status确认变更范围,然后把改动提交到一个独立分支,避免后面返工。
4.2 修改图标和启动屏配置
在加权限描述的过程中,我又顺手检查了 AppIcon。结果发现 1024 图标居然是从旧版设计稿里截出来的,sips -g hasAlpha显示yes。这显然也是个隐患。我让设计师重新导出一张不带透明通道的 1024 图标,替换到 Assets 里。
启动屏我也检查了一下。这个项目比较老,LaunchScreen.storyboard 还在,但 Target 的 Launch Screen File 配置指向了一个不存在的文件名。我把引用改回正确的LaunchScreen.storyboard,同时又在 Info.plist 里加了UILaunchScreen空字典作为兜底。这不会影响 storyboard 的优先级,但能避免个别版本在 Info.plist 解析时出现偏差。
4.3 清理构建目录并重新归档
配置改完之后,我没有直接在 Xcode 里点 Run 或 Archive,而是先做了一次彻底清理:
xcodebuild clean -workspace MyApp.xcworkspace -scheme MyApp同时在 Xcode 里用快捷键Shift + Cmd + K执行 Clean Build Folder。这一步很关键,尤其是老项目,很多时候无效二进制是因为增量编译把旧的模拟器架构和旧的资源文件带进了最后的 archive。
然后确保 scheme 选择的设备是Any iOS Device (arm64),也就是通用 iOS 设备,不能再选模拟器。直接 Product -> Archive,等待构建完成。执行 Archive 时,我观察 Xcode 的日志输出,确认编译的架构是 arm64,而没有出现 x86_64。
归档完成后,Xcode Organizer 会自动弹出来。我选中这个 archive,点 “Distribute App”,选择 “App Store Connect”,再选择 “Upload”。因为个人偏好用命令行,我是用xcodebuild -exportArchive导出的 ipa,但核心思路一样。
4.4 用 Transporter 上传并查看日志
导出成功的 ipa 就在export_dir/MyApp.ipa。我打开 Transporter,点加号选择这个 ipa。Transporter 会做一次上传前的本地校验,如果 ipa 里有明显问题,它会先报出来。这一步就能把一部分错误拦截在本地,省去远程等待。
上传完成后,我不急着关 Transporter,而是点窗口左下角的“查看最近活动”,把日志滚动到最底部,确认没有 Warning 或 Error。然后回到 App Store Connect 的“活动”页面,等待状态从 Processing 变成可用的构建。大约等了十分钟,构建状态显示为正常的可提交状态,而不是 Invalid Binary。
4.5 如果 Transporter 也报错怎么办
Transporter 报错的情况和后台不太一样,它更像“文件格式不对、网络中断、账号权限不足”这一类问题。常见的本地报错包括:
App Store Connect operation failed:通常是网络或账号 token 失效,退出 Transporter 重新登录再试。The package is invalid:ipa 本身格式不对,检查是不是把 xcarchive 当 ipa 上传了。Authentication failed:使用 Transporter 登录时,需要 Apple ID 开启双重认证,并使用 App 专用密码。
如果你没有安装 Transporter,也可以使用命令行工具altool,不过新版 Xcode 对altool的提示是已废弃,我建议还是直接用 Transporter,简单可靠,日志也更完整。
5. 常见错误码速查表和避坑经验
有些朋友其实就是想要一张“错误码对照表”,遇到问题能快速翻。下面这张表是我根据实际经验整理的高频场景,不一定覆盖所有情况,但至少能覆盖我遇到过的八成问题。
| 报错关键字 / 错误码 | 常见原因 | 处理方式 |
|---|---|---|
| ITMS-90022 | Info.plist 缺少隐私权限用途描述 | 找到对应 API 并补上NS*UsageDescriptionkey |
| ITMS-90023 | 同上,通常是另一个权限 key 缺失 | 补全所有涉及的用户隐私权限描述,不要有遗漏 |
| Unsupported Architecture | 包内含x86_64或i386模拟器架构 | 检查 Build Settings 的 Architectures 和 Excluded Architectures,重新 Archive |
| Code object is not signed at all | 签名失效或未签名 | 重新选择 Distribution 证书和 App Store 描述文件,再导出 |
| Invalid Code Signing Entitlements | 授权文件与描述文件不匹配 | 重置 signing capability 配置,确认 push、iCloud 等 entitlement 与后台一致 |
| Invalid SDK Version | 使用了 beta Xcode 或旧版本 Xcode | 使用稳定版 Xcode 重新构建 |
| Invalid Large App Icon | 1024 图标尺寸不对或含 alpha 通道 | 导出无透明通道的 1024x1024 PNG |
| Missing required icon | App 图标集中缺少某尺寸图标 | 重新生成完整 AppIcon 集 |
| ITMS-90125 | 包内结构异常,可能是资源文件混入 | 解包检查文件列表,删除临时文件和多余动态库 |
| ITMS-90683 | 缺少 Swift 支持文件或签名不完整 | 不要手动改包,用 Xcode 完整导出 .ipa |
| Invalid Bundle, nested frameworks | 框架目录嵌套错误 | 确认动态库放在Frameworks目录且签名正确 |
| App contains disallowed file | 包内包含不被允许的脚本、日志、资源 | 清理打包脚本和多余文件后重新打包 |
表格不是万能的,很多无效二进制邮件里并没有具体错误码,只有一段模糊的描述。这时候我的经验是:不能猜,要靠日志定位。Transporter 和 App Store Connect 的活动日志是最接近真相的线索。如果你发现错误码和你的实际场景对不上,别硬套,回到第 2 节的三步定位法,按顺序排查。
5.1 同一个错误码,原因可能完全不同
比如 ITMS-90022 在很多文章里都写成“缺少相册权限描述”,但它也可能是缺少定位权限、麦克风权限、通讯录权限。你必须在工程里搜索所有涉及隐私的 API,然后把对应的Info.plistkey 全部匹配一遍,而不是只补某一个。
同样,“Unsupported Architecture” 也不一定就是模拟器架构混入。我见过一台 CI 机器因为本机lipo缓存异常,导致打出来的包虽然显示arm64,但某个 framework 还是包含模拟器切片。这种情况你光看主程序不够,还要逐个检查 app 包里的 framework:
find Payload/MyApp.app -name "*.framework" -type d | while read fw; do binary_name=$(basename "$fw" .framework) lipo -info "$fw/$binary_name" done5.2 Xcode 版本不一致导致的“灵异事件”
如果你多台机器协同打包,最容易遇到的无效二进制原因其实是 Xcode 版本不一致。比如 A 机器用 Xcode 14.3,B 机器用 Xcode 15.4,两台机器导出的 ipa 可能都显示“没问题”,但上传到 App Store Connect 后一个正常,一个异常。苹果的检查会把构建工具链信息也算进去,所以同一工程在不同 Xcode 版本下产物并不等价。
我的建议是:如果团队里有稳定的上架流程,最好统一到同一台“上架专用机器”或同一条 CI 流水线,不要今天这台机器打,明天那台机器打。至少保证 Xcode 版本一致,并且不要混用手动导出和命令行导出的不同签名策略。
5.3 提交前最后 5 分钟检查清单
我每次上传 ipa 前,都会在脑子里过一遍下面的清单。不能说百分百避免问题,但确实帮我挡掉了不少低级错误:
- [ ] Bundle ID 与后台 App ID 完全一致,没有大小写和标点差异。
- [ ] Version 和 Build 都是合法数字,Build 比上一次大。
- [ ] Info.plist 里所有
*UsageDescription都非空。 - [ ] 1024 图标无 alpha 通道,尺寸正确。
- [ ] Release 构建只包含
arm64,没有x86_64。 - [ ] 签名证书是 Apple Distribution,描述文件是 App Store 类型。
- [ ] 用 Xcode 或
xcodebuild导出 App Store 包,导出后没有手工修改过 .app 内容。 - [ ] ipa 包的
Payload目录下只有一个.app。 - [ ] 上传成功后,Transporter 没有 Warning。
- [ ] App Store Connect 状态最终变成可用的构建,而不是 Invalid Binary。
这套清单用多了,会变成肌肉记忆。
6. 几次翻车之后,我的处理顺序和心态
无效二进制这个问题,说起来不算大,但每次出现都会打断发布节奏。我现在的处理顺序基本固定了:先看邮件里有没有错误码,没有就去后台活动页找日志;然后本地解包核对 Info.plist、架构和签名;最后再考虑是不是 Xcode 或打包链路的问题。如果实在查不出来,就老老实实递增 Build 号,重新走一遍 Archive 流程,而不是在同一构建号上反复折腾。
还有一个心态上的建议:别把 Invalid Binary 当成“苹果在故意卡你”。绝大多数情况下,确实是包本身有不符合规范的地方。苹果给的提示虽然不友好,但它本质上是在帮你拦截那些即使上传了也会在审核阶段被拒的问题。与其抱着侥幸心理反复重传,不如用半小时把工程配置完整体检一遍。
最后分享一个小细节:我在自己的项目里把 Build 号拆成了“年+月+日+序列号”的格式,比如24010101,这样每次构建都有唯一标识,即使上传失败,下一个包的 Build 号也天然递增,不会出现覆盖问题。这个习惯帮我在很多次无效二进制的处理里省下了排查成本。如果你也经常被这个问题困扰,可以试试。