解决 Xcode 上传应用时“hermes.framework 包含 bitcode”错误
问题描述
在使用 Xcode 16 构建并上传应用到 TestFlight 时,遇到以下验证错误:Asset validation failed, NSLocalizedRecoverySuggestion=Invalid Executable. The executable 'hermes.framework/hermes' contains bitcode
尽管构建和归档过程成功完成,但上传失败导致无法分发到 TestFlight。
问题根源
此问题通常发生在以下环境:
- Xcode 16 或更高版本
- iOS 18 开发环境
- 项目使用了 Hermes JavaScript 引擎(React Native 项目常见)
主要原因是某些框架(特别是 hermes.framework
) 包含 bitcode,但 Xcode 16+ 对 bitcode 处理更为严格。
bash
# 典型错误日志
<IDEDistributionContext: 0x7f9ef32a6d50; ...>
2024-09-25 10:05:15 +0000 [MT] Upload for archive had issues:
(
"Asset validation failed",
"Invalid Executable. The executable 'hermes.framework/hermes' contains bitcode"
)
解决方案
✅ 推荐方案:在 Podfile 中添加自动 strip 脚本
- 修改
Podfile
文件
在文件末尾end
之前添加以下函数(若无post_install
块则需创建):
ruby
post_install do |installer|
# 自动检测并移除 bitcode 的函数
def strip_bitcode_from_frameworks
puts "Checking frameworks for Bitcode..."
# 搜索 Pods 中所有 .framework 文件
frameworks = Dir.glob("Pods/**/*.framework")
frameworks.each do |framework|
binary = File.join(framework, File.basename(framework, ".framework"))
if File.exist?(binary)
# 检测是否包含 bitcode
contains_bitcode = `otool -l "#{binary}" | grep __LLVM`
next unless contains_bitcode && !contains_bitcode.empty?
puts "#{binary} 包含 bitcode,正在移除..."
stripped = "#{binary}_stripped"
# 执行 bitcode 移除
success = system("xcrun bitcode_strip \"#{binary}\" -r -o \"#{stripped}\"")
# 替换原始文件
if success && File.exist?(stripped)
FileUtils.mv(stripped, binary, force: true)
puts "✅ 成功移除 #{binary} 中的 bitcode"
else
puts "❌ 移除 #{binary} 的 bitcode 失败"
end
end
end
puts "🧹 Bitcode 清除完成"
end
# 调用函数
strip_bitcode_from_frameworks
end
- 执行后续操作
bash
# 1. 更新依赖
pod install
# 2. 清理构建缓存
rm -rf ~/Library/Developer/Xcode/DerivedData
# 3. 重新编译归档
xcodebuild clean archive -workspace YourProject.xcworkspace -scheme YourScheme
- 验证修复效果
重新上传到 App Store Connect,确认错误已消失。
⚙️ 替代方案:手动指定框架路径
如果只需处理已知框架(如 Hermes):
ruby
post_install do |installer|
bitcode_strip_path = `xcrun --find bitcode_strip`.chomp
# 定义处理函数
def strip_bitcode(bitcode_strip_path, path)
full_path = File.join(Dir.pwd, path)
if File.exist?(full_path)
system("#{bitcode_strip_path} #{full_path} -r -o #{full_path}")
puts "已处理: #{full_path}"
end
end
# 指定需要处理的路径
[
"Pods/hermes-engine/destroot/Library/Frameworks/macosx/hermes.framework/hermes",
"Pods/hermes-engine/destroot/Library/Frameworks/universal/hermes.xcframework/ios-arm64/hermes.framework/hermes",
# 添加其他路径(如有需要)
].each { |path| strip_bitcode(bitcode_strip_path, path) }
end
注意事项
- RN 版本兼容性
- React Native < 0.72 可能需要额外配置
- 确保
hermes_enabled
正确设置:
ruby
use_react_native!(
:hermes_enabled => true, # 检查此处配置
...
)
- 权限问题 首次运行脚本可能需授权:
bash
sudo chmod +x your_script.sh
- Bitcode 设置 在 Xcode 中确认项目设置:
- Target → Build Settings → Enable Bitcode → NO
⚠️ 重要提示
此解决方案适用于 Xcode 16+ 和 macOS Sonoma/Ventura。
升级 React Native 到兼容版本 0.73+ 可预防此问题再次发生。
验证步骤
- 检查二进制是否仍含 bitcode
bash
otool -l YOUR_APP.app/Frameworks/hermes.framework/hermes | grep __LLVM
- 若无输出则表示 bitcode 已成功移除
遵循以上步骤,即可解决 TestFlight 上传时的 bitcode 验证错误。