问题描述
正常通过Produre - Archive
打包,并在Xcode
的Window -Organizer - Distribute App
提交App Store
审核报错误。
Bitcode
是一种中间表示形式,在 Xcode
中打包提交到 App Store
审核时,如果出现包含 Bitcode
的报错,这通常意味着您的应用没有正确包含 Bitcode
。Bitcode
是苹果的一项要求,它允许苹果在 App Store
中对您的应用进行进一步的优化。
当提交应用到 App Store
时出现与 Bitcode
相关的问题,您需要手动移除 framework
中的 Bitcode
。
解决方法
在 Xcode 中禁用 Bitcode:
-
打开你的 Xcode 项目; -
选择你的项目在 Project Navigator 中; -
选择你的目标应用; -
选择“Build Settings”标签; -
搜索“Enable Bitcode”并将其设置为“No”; -
清理并重建你的项目(使用快捷键 Shift + Command + K 进行清理,然后使用 Command + B 进行重建)。
由于 Xcode16 不再支持 Bitcode,所以我们无法在项目中找到这个设置。
使用Xcode 15
打包构建上传
由于最近刚换了电脑,自己的 Intel 破笔记本上还是用的是
Mac OS 13.7.2
,Xcode 15.2
,而且 Apple 已经停止了对这个机型的更新。公司一直有台
Mac Mini (Apple M1 + 8GB + 256GB)
着实丐中丐了,实在是提不起兴趣,但是确实没办法,自己的电脑面临着淘汰,最新的系统无法更新,Xcode
可能需要最新的版本才能构建提交。
可以尝试使用旧版Xcode 15
打包并构建,我这里并没有进行尝试,同事说这个错误在他的电脑上打包是一直都存在,通过我电脑打包构建的项目是没有问题的。
但还是建议通过各种方法做最新的兼容。
使用命令行工具,手动更改Bitcode
假设您有一个名为 NIMSDK.framework
的 framework
,并且它位于 /path/to/~/NIMSDK.framework
路径,那么您可以按照以下方式处理:
通过
cd
命令进入到NIMSDK.framework
的路径。
如果是通过pod install
获取的SDK
,则进入pods
文件夹。执行以下命令检查
framework
是否包含bitcode
,返回0
即为不包含。
otool -l NIMSDK | grep __LLVM | wc -l
- 如果检测结果不是
0
,则继续执行以下命令移除NIMSDK.framework
的Bitcode
。
xcrun bitcode_strip -r NIMSDK -o NIMSDK
一定要注意是.framework
路径下的同名文件
一定要注意是.framework
路径下的同名文件
一定要注意是.framework
路径下的同名文件
重要的事情说三遍。
使用shell
脚本,批量处理
如果你的某一个路径下有很多需要移除的bitcode
库,编写一个如下的脚本,下面使用网易云信的NERtcSDK
举例。
代码示例如下:
#!/bin/sh
proj_path=$(pwd)
if [ -f NELivePlayerFramework.framework/NELivePlayerFramework ]; then
echo "remove bitcode for NELivePlayerFramework.framework"
xcrun bitcode_strip -r $proj_path/NELivePlayerFramework.framework/NELivePlayerFramework -o $proj_path/NELivePlayerFramework.framework/NELivePlayerFramework
otool -l $proj_path/NELivePlayerFramework.framework/NELivePlayerFramework | grep __LLVM
fi
if [ -f NELPGslb.framework/NELPGslb ]; then
echo "remove bitcode for NELPGslb.framework"
xcrun bitcode_strip -r $proj_path/NELPGslb.framework/NELPGslb -o $proj_path/NELPGslb.framework/NELPGslb
otool -l $proj_path/NELPGslb.framework/NELPGslb | grep __LLVM
fi
exit
最后保存为 remove_nertc_bitcode.sh
- 打开终端,通过
cd
命令进入到Pods/NERtcSDK/NERTC/NERtcSDK
目录下; - 拷贝
remove_nertc_bitcode.sh
脚本到frameworks
所在路径; - 执行以下命令:
sh remove_nertc_bitcode.sh
您可以下载 remove_nertc_bitcode.sh 脚本,批量去除引入了网易云信音视频产品 SDK 系列的 iOS 项目中的 Bitcode。或者参考它写出适用自己项目的脚本。
使用CocoaPods
的post_install
钩子
也是我正在使用的一种方式,相比较上面的方法来说,非常懒人,如果再次遇到报错的库,可以直接在podfile
文件中,添加 Framework
路径,然后重新pod install
。
post_install do |installer|
bitcode_strip_path = 'xcrun --find bitcode_strip'.chop!
def strip_bitcode_from_framework(bitcode_strip_path, framework_relative_path)
framework_path = File.join(Dir.pwd, framework_relative_path)
command = "#{bitcode_strip_path} #{framework_path} -r -o #{framework_path}"
puts "Stripping bitcode: #{command}"
system(command)
end
# 列出需要剥离BitCode的frameworks路径
framework_paths = [
"Pods/LibraryA/LibraryA/dynamic/LibraryA.xcframework/ios-arm64_armv7/LibraryA.framework/LibraryA",
"Pods/LibraryB/LibraryB.xcframework/ios-arm64_armv7/LibraryB.framework/LibraryB"
]
framework_paths.each do |framework_relative_path|
strip_bitcode_from_framework(bitcode_strip_path, framework_relative_path)
end
end
亦或者是添加config.build_settings['ENABLE_BITCODE'] = 'NO'
来实现每次pod install
都会去安装无bitcode
的库,但是如果某一个的库中使用的是xcframework
,则需要对xcframework
中不同的架构路径下的framework
进行移除bitcode
操作。
下面是我基于上面的 post_install
代码做的调整,添加了对framework_paths
路径检查、bitcode
检查。
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '13.0'
config.build_settings['ENABLE_BITCODE'] = 'NO'
end
end
# 剥离pod库中的Bitcode
bitcode_strip_path = `xcrun --find bitcode_strip`.chop!
def strip_bitcode_from_framework(bitcode_strip_path, framework_relative_path)
framework_path = File.join(Dir.pwd, framework_relative_path)
command = "#{bitcode_strip_path} #{framework_path} -r -o #{framework_path}"
puts "Stripping bitcode: #{command}\n\n"
system(command)
end
# 检查是否存在bitcode
def has_bitcode(framework_relative_path)
framework_path = File.join(Dir.pwd, framework_relative_path)
# 检查是否存在 bitcode
command = "otool -l #{framework_path} | grep __LLVM | wc -l"
result = `#{command}`.strip.to_i
# 如果结果不为 0,则认为存在 bitcode
result != 0
end
# 列出需要剥离Bitcode的xcframeworks路径
framework_paths = [
"Pods/LibraryA/LibraryA/dynamic/LibraryA.xcframework/ios-arm64_armv7/LibraryA.framework/LibraryA",
"Pods/LibraryB/LibraryB.xcframework/ios-arm64_armv7/LibraryB.framework/LibraryB"
]
framework_paths.each do |framework_relative_path|
if File.exist?(framework_relative_path)
if has_bitcode(framework_relative_path)
strip_bitcode_from_framework(bitcode_strip_path, framework_relative_path)
else
filename = File.basename(framework_relative_path)
puts "Framework #{filename} does not contain bitcode."
end
else
puts "Framework path does not exist: #{framework_path}"
end
end
end
这两种方法可以实现互补,也可以找到全部的路径添加到framework_paths
来全部实现,实际需要操作的framework
可能会很多。
温馨提示
建议在重新pod install
前,执行
pod cache clean --all
优化更新
- 更新时间:2025 年 03 月 03 日
由于大部分的
Bitcode
都是通过remove_nertc_bitcode.sh 脚本处理了,这次更改为在framework_globs
中实现,不再依赖于这个脚本执行。
# 自动发现需要处理的 framework 路径
framework_globs = [
# xcframework下的全部路径
'Pods/LibraryA/*.xcframework/**/*.framework',
# 可以指定xcframework路径下的指定路径
'Pods/LibraryA/Library_Example_A.xcframework/**/Library_Example_A.framework',
'Pods/LibraryB/Library_Example_B.xcframework/**/Library_Example_B.framework',
# 全部路径下的
'Pods/LibraryC/**/*.framework',
# 亦可单独指定
'Pods/LibraryD/**/LibraryD.framework',
]
# 列出需要剥离Bitcode的framework和xcframeworks路径
framework_paths = framework_globs.flat_map { |g| Dir.glob(g) }.map do |path|
framework_name = File.basename(path, '.*')
"#{path}/#{framework_name}"
end
- 将旧
framework_paths
替换为新framework_paths
; -
bitcode
处理流程未改变,优化了可能
需要手动添加的路径长度。
参考资料
融云干货丨由于 xcode16 不支持 framework 开启 bitcode,移除 framework 中的 bitcode
xcode16 提交审核报 bitcode 错错误-Asset validation failed (90482) Invalid Executable
App Store 审核应用时出现包含 bitcode 的报错
怎么删除 NERtc SDK Frameworks 的 Bitcode
Xcode 提交 App Store 审核时出现包含 bitcode 的报错
Xcode does not contain bitcode
Xcode14 正式版编译报错‘ does not contain bitcode.解决方案
[iOS] Upload Symbols Failed on Xcode 16 #46853