修复 App Store 上传报 ITMS-90426 Invalid Swift Support

SwiftSupport 目录缺失时,App Store Connect 会以 ITMS-90426 Invalid Swift Support 拒绝你的 IPA。最快修复方案,外加六类根因、诊断命令和干净重建流程。

本地归档通过校验,点了上传到 App Store Connect,进度条跑完,几分钟后收到邮件:“ITMS-90426: Invalid Swift Support — The SwiftSupport folder is missing. Rebuild your app using the current public (GM) versions of Xcode and resubmit it.” 重新归档再传又是同样错误。Frameworks 目录看起来没问题,工程能编、Xcode 也说归档有效。

TL;DR(先给最快的修复): 这个错误的意思是 SwiftSupport 目录没有被打进你的 .ipa。最常见的原因(且远高于其他)是 IPA 用了错误的分发方式导出。Ad Hoc、Development、Enterprise 导出默认会剥掉 Swift 运行时库,只有 App Store Connect 分发导出才会包含 SwiftSupport 把现有的 .xcarchive 通过 Xcode → Window → Organizer → Distribute App → App Store Connect 重新导出一次(或在 fastlane 里设 export_method: "app-store"),然后重新上传。如果你本来就用的是 App Store 导出,那问题出在某个打包方式不对的第三方 framework —— 对照下面的表格逐项排查。

你属于哪一种情况

你能自查的现象最可能的原因跳转
你用 Ad Hoc / Development / Enterprise 导出,或 fastlane export_method 不是 app-store错误的导出方式剥掉了 Swift 库原因 0
某个 vendor 的 .framework/.xcframework 显示一个旧的 DTXcode用更旧的 Swift 工具链编的原因 1
framework 的 .swiftmodule 旁边没有 .swiftinterface没开 library evolution 编译原因 2
对某个 framework 跑 lipo -info 列出了 x86_64/i386模拟器切片混进了设备归档原因 3
framework 出现在 Link Binary 里但不在 Embed Frameworks 里手动拷贝而非 Embed & Sign原因 4
归档机和上传机的 xcode-select -p 不一致Xcode 版本不匹配原因 5
find 显示多个嵌套的 SwiftSupport/.swiftmodule冲突的 Swift 内嵌负载原因 6

截至 2026 年 6 月,Apple 要求每个 iOS 上传包都用 Xcode 26 / iOS 26 SDK 或更新版本 构建(自 2026 年 4 月 28 日起强制执行)。拒信里的 “current public (GM) Xcode” 现在指的是 Xcode 26.x,不是 beta,也不是 Xcode 16/17。用 xcodebuild -version 确认;SDK 要用 xcodebuild -showsdks 确认报的是 iOS 26。

常见原因

0. 错误的导出方式(最常见)

这是要第一个排除的,也是绝大多数 ITMS-90426 报告最终被解决的原因。导出为 Ad HocDevelopmentEnterprise 的 IPA,其 Swift 运行时支持文件被剥掉了 —— SwiftSupport 目录只会在 App Store Connect 分发导出时被组装出来。二进制完全一样,外层包装布局不一样。

如何识别:解压 IPA 找这个目录:unzip -l YourApp.ipa | grep -i SwiftSupport。如果什么都没打印,说明 SwiftSupport 目录缺失,你用了错误的导出方式。在 fastlane 里,确认 gym/build_app 用的是 export_method: "app-store",而不是 "ad-hoc""development"

第三方 framework 类原因

按概率排序。

1. 嵌入的 framework 是用别的 Swift 版本编译的

你引入了一个 vendor 的二进制分发 .xcframework.framework,它是用更旧的 Swift 工具链编出来的。App Store Connect 把 framework 的 SwiftSupport metadata 和当前 GM Xcode 对比,发现不一致就拒。

如何识别otool -L YourApp.app/YourApp 看二进制依赖的 Swift 库路径;framework 是基于更旧 Xcode 的 libswiftCore.dylib 编的。看 Frameworks/<Framework>.framework/Info.plist 里的 DTXcode 字段是否比你当前 Xcode 老。

2. framework 没用 BUILD_LIBRARY_FOR_DISTRIBUTION 编译

一个 Swift framework 想跨 Xcode 版本安全分发,必须打开 BUILD_LIBRARY_FOR_DISTRIBUTION = YES。没这个标志 ABI 不稳定,归档的 SwiftSupport 目录无法对齐。

如何识别:看 vendor 的 framework —— 如果 .swiftmodule 旁边没有 .swiftinterface 文件,就说明这个 framework 不是按 distribution 编的。

3. Pod / SPM 把 x86_64 模拟器切片带进了设备归档

.xcframework 缺失,或 .framework 编成了包含模拟器切片的 fat Mach-O 时,App Store 上传步骤会因 SwiftSupport 里有模拟器架构而拒。

如何识别lipo -info YourApp.app/Frameworks/<Framework>.framework/<Framework> 看到 arm64 之外还有 x86_64i386。App Store 二进制只能包含设备切片。

4. 手动拷贝了动态 framework 而不是用 Embed Frameworks

如果你把 .framework 拖进项目时没在 Frameworks, Libraries, and Embedded Content 里勾 Embed & Sign,Xcode 不会跑 Run Script: Strip Invalid Architectures 阶段,SwiftSupport 也无法正确组装。

如何识别:打开 Build Phases → Embed Frameworks。如果你的 framework 不在这里,但出现在 Link Binary With Libraries 里,就是这个原因。

5. 上传用的 Xcode 和归档用的不是同一个

上传步骤用调用方 Xcode 的工具来组装 SwiftSupport。如果 CI 机器还是 Xcode 16 active,而开发机是用 Xcode 26 归档的,上传步骤会取错 Swift support 文件。自 2026 年 4 月 28 日起,低于 Xcode 26 的还会直接因 SDK 过旧被拒,所以一个过期的 CI 镜像现在更容易失败。

如何识别:上传机器的 xcode-select -p 与归档机器不同,或任一机器上 xcodebuild -version 低于 26。

6. framework 自带了过时的 swiftsupport 子目录

某些旧 framework 在自身内部还带了一份 SwiftSupport 目录。App Store Connect 去重时可能选错版本。

如何识别find YourApp.app/Frameworks -name "SwiftSupport" -o -name "*.swiftmodule" 在嵌套 framework 里列出多处 module。

开始之前

  • 把拒信里那串 ITMS-90xxx 错误号记下 —— 不同号对应不同修复路径。
  • 把失败的 .xcarchive 拷贝到 ~/Desktop/ArchiveDebug.xcarchive,方便后续多次取样。
  • 找出问题 framework;拒信有时点名,有时只说 “SwiftSupport”。

需要收集的信息

  • ls -la YourApp.xcarchive/Products/Applications/YourApp.app/Frameworks/ 的输出。
  • 每个 framework 二进制的 lipo -info 输出。
  • 每个 framework 二进制的 otool -L <bin> | grep -i swift 输出。
  • 归档机的 Xcode 版本:xcodebuild -version
  • 每个 framework Info.plist 中的 DTXcodeDTSDKBuild 值。
  • PodfilePackage.resolved 中的依赖声明。

修复步骤

步骤 1:定位有问题的 framework

把归档里每个 framework 都查一遍:

cd YourApp.xcarchive/Products/Applications/YourApp.app/Frameworks
for fw in *.framework; do
  echo "=== $fw ==="
  lipo -info "$fw/$(basename $fw .framework)"
  /usr/libexec/PlistBuddy -c "Print :DTXcode" "$fw/Info.plist" 2>/dev/null
  ls "$fw/Modules/$(basename $fw .framework).swiftmodule/" 2>/dev/null
done

留意:有模拟器架构、缺 .swiftinterfaceDTXcode 显著早于归档 Xcode。

步骤 2:把 fat framework 换成 XCFramework

vendor 的 framework 含模拟器切片时,要么向 vendor 索要 .xcframework,要么自己转:

# Extract device-only slice
lipo -extract arm64 \
  Path/To/Old.framework/Old \
  -o Path/To/Old.framework/Old-device

mv Path/To/Old.framework/Old-device Path/To/Old.framework/Old

# Or build an XCFramework from device + sim archives
xcodebuild -create-xcframework \
  -framework Path/To/Device.framework \
  -framework Path/To/Simulator.framework \
  -output Path/To/Combined.xcframework

工程里把引用换成 .xcframework,Xcode 会按 build 自动选对的切片。

步骤 3:自研 Swift framework 开启 library evolution 重新构建

framework target 的 Build Settings:

BUILD_LIBRARY_FOR_DISTRIBUTION = YES
SWIFT_INSTALL_OBJC_HEADER = YES
SKIP_INSTALL = NO

然后 archive 这个 target:

xcodebuild archive \
  -scheme MyFramework \
  -destination "generic/platform=iOS" \
  -archivePath ./build/iOS.xcarchive \
  SKIP_INSTALL=NO \
  BUILD_LIBRARY_FOR_DISTRIBUTION=YES

模拟器用 -destination "generic/platform=iOS Simulator" 同样跑一遍,再用 xcodebuild -create-xcframework 合并。

步骤 4:App target 中每个 framework 都设为 Embed and Sign

App target → General → Frameworks, Libraries, and Embedded Content。所有动态 framework 都应该是 Embed & Sign。静态库则是 Do Not Embed。如果某个应当是动态的 framework 标了 Do Not Embed,改过来。

步骤 5:让所有机器和 CI 用同一个 Xcode 版本

CI 配置里 pin 住 Xcode 26(当前最低版本):

xcode_version: "26.0"

开发机:sudo xcode-select -s /Applications/Xcode_26.0.app/Contents/Developer。归档步骤和上传步骤的 Xcode 不一致时,SwiftSupport 剥离过程会取错源;低于 26 的版本自 2026 年 4 月 28 日起也会因 App Store SDK 最低要求而被拒。

步骤 6:清理 DerivedData,从零重建

缓存的 Swift module 会让 SwiftSupport payload 长期带病:

rm -rf ~/Library/Developer/Xcode/DerivedData/*
rm -rf ~/Library/Caches/org.swift.swiftpm
xcodebuild clean -workspace YourApp.xcworkspace -scheme YourApp

然后干净状态下重新归档。跳过这一步是”工程改了还在传旧 framework”最常见的原因。

步骤 7:用对的工具上传

最稳的方式是用 Xcode Organizer(Window → Organizer → Archives → Distribute App → App Store Connect),因为它会重新跑一遍组装 SwiftSupport 的 App Store 导出。如果你要脚本化,xcrun altool --upload-app 仍然能用于 App Store 上传,且必须从归档时同一个 Xcode 调用:

xcrun altool --upload-app -f YourApp.ipa -t ios \
  --apiKey "$ASC_KEY_ID" --apiIssuer "$ASC_ISSUER_ID"

注意:altool 只是在**公证(notarization)**上被废弃(自 2023 年 11 月 1 日起公证服务不再接受它)—— App Store 上传仍走它,而 Apple 现在更推荐用独立的 Transporter 应用或 App Store Connect API key,而非旧的 -u/-p 密码方式。看上传日志,SwiftSupport 处理步骤会打印它处理了哪些 framework。

验证

  • 新归档的 Frameworks/ 里二进制只剩 arm64
  • 每个 Swift framework 的 module 目录里 .swiftinterface.swiftmodule 都有。
  • App Store Connect 上传完成不再报 ITMS-90426 / 90427。
  • 处理后的 build 在 TestFlight 中 5-30 分钟内出现。
  • Xcode → Window → Organizer → Validate App 不再有 Swift support 警告。

长期预防

  • 二进制依赖都用 .xcframework;fat framework 已废弃,未来会一直踩坑。
  • 向 vendor 索要按 distribution 模式构建的 framework;不给的话,能从源码构建就从源码来。
  • CI 与每台开发机都 pin 住 Xcode 版本,通过 .xcode-version 文件或类似 nvm 的工具切换。
  • 加一段上传前脚本,对归档里每个 framework 跑 lipo -info,发现模拟器切片直接 fail。
  • 记录每个 vendor framework 是用哪个 Swift / Xcode 编的;Xcode 大版本升级时重新编一次。下游卡处理的现象参考TestFlight Build 卡在处理中
  • 不要直接把 .framework 拖进工程;用 Swift Package Manager 或 CocoaPods,它们能正确处理 embed 步骤。

常见坑

  • “改完 Xcode 设置”之后重新上传同一个 .ipa —— 没重新归档的话 IPA 完全没变。
  • 同一个 framework 同时引入静态版和动态版;App Store 看到重复符号会拒。
  • 在 App target 上设了 BUILD_LIBRARY_FOR_DISTRIBUTION = YES,而不是 Framework target。
  • CocoaPods 通过 use_frameworks! 决定静态/动态;切换需要 deintegrate + 重新装。
  • 用 beta Xcode 的 Mac 提交,但归档是用 GM Xcode 做的 —— Apple Beta Xcode 归档不接受生产提交。
  • 以为 xcrun altool 总匹配当前 Xcode —— 决定它走哪个的是 xcode-select 设置。

FAQ

Q:我的 App 一个第三方 framework 都没有,为什么还缺 SwiftSupport?

那几乎肯定是原因 0:.ipa 用了非 App Store 的方式导出。fastlane、Expo/EAS、Unity、Qt 这类工具经常默认走 Ad Hoc 或 Development 导出,会剥掉 SwiftSupport。跑 unzip -l YourApp.ipa | grep -i SwiftSupport —— 如果什么都没打印,就把同一个 .xcarchive 通过 Organizer → Distribute App → App Store Connect 重新导出,或者把构建工具的导出方式设成 app-store。这不需要重新编译代码。

Q:vendor 说他们的 framework 支持 App Store,为什么苹果拒?

最常见情况是 framework 是用 BUILD_LIBRARY_FOR_DISTRIBUTION = NO 编的,或者发的是含模拟器切片的 fat framework。要求 vendor 用最新 GM Xcode 重新构建一份 .xcframework。如果对方不配合,要么自己从源码编、要么放弃这个依赖。

Q:Bitcode 在这里有用吗?

Xcode 14 起 Bitcode 已废弃 —— 在 Build Settings 里关掉(ENABLE_BITCODE = NO)。现代 Xcode 上开着它没好处只有风险,还会以诡异方式触发 Swift support 错误。

Q:我用的是 Swift Package Manager,还会遇到这个吗?

会,如果 SPM 包用 .binaryTarget(name:url:) 引用了一个有问题的 XCFramework。去 ~/Library/Developer/Xcode/DerivedData/<proj>/SourcePackages/artifacts/ 里检查这个二进制。

Q:苹果说要用 GM Xcode 重建,可我就是 GM 啊?

先确认你的工具链确实达到了当前下限:xcodebuild -version 必须报 Xcode 26 或更新(自 2026 年 4 月 28 日起的最低要求)。如果你的 App 没问题,再去看每个 vendor framework Info.plist 里的 DTXcodeDTSDKBuild。哪一个是更旧 Xcode 编的,苹果拒的就是它;你要重建的是那个 framework,不是你的 App。

Q:能直接手动删掉 framework 的 SwiftSupport 目录吗?

不能。Xcode 在 export 归档时会重新生成 SwiftSupport,手动改会被覆盖。正确做法是修 framework 的 build settings。

相关阅读

标签: #排查 #ios #xcode #swift #archive