我有一个应用程序,使用了一个链接和嵌入的自定义框架。在Xcode 12.2之前,该应用程序可以正确地构建iOS设备和模拟器版本。但是从Xcode 12.3开始,我遇到了以下错误:
构建iOS模拟器版本时,链接并嵌入的框架'My.framework'是为iOS + iOS模拟器版本构建的。
框架已经为设备和模拟器版本构建好(正如错误信息所说),并且使用了lipo
进行了合并,因此它应该能够在任何地方运行而不会出现问题。
这里有什么我忽略的东西吗? Xcode 12.3有相关的更改吗?
我有一个应用程序,使用了一个链接和嵌入的自定义框架。在Xcode 12.2之前,该应用程序可以正确地构建iOS设备和模拟器版本。但是从Xcode 12.3开始,我遇到了以下错误:
构建iOS模拟器版本时,链接并嵌入的框架'My.framework'是为iOS + iOS模拟器版本构建的。
框架已经为设备和模拟器版本构建好(正如错误信息所说),并且使用了lipo
进行了合并,因此它应该能够在任何地方运行而不会出现问题。
这里有什么我忽略的东西吗? Xcode 12.3有相关的更改吗?
xcrun xcodebuild -create-xcframework \
-framework /path/to/ios.framework \
-framework /path/to/sim.framework \
-output combined.xcframework
.framework
开始。复制框架两次,并使用lipo
从与不同SDK相关联的二进制文件中删除切片。PS:您可以通过运行file <path_to_framework_binary>
或lipo -info <path_to_framework_binary>
来检查框架中存在的所有体系结构。
例如:file /Users/srikanth.kv/MyProject/MyLibrary.framework/MyLibrary
我有一个框架,其中包含 x86_64
和 arm64
的通用二进制文件,我使用自定义脚本通过 lipo
合并二进制文件。我在 Xcode 12.3 中遇到了同样的问题,并已经创建了一个解决方法。希望这个问题可以很快得到修复,但在修复之前,一种快速解决方法是减少体系结构并使用所需的框架。
请参见我在这里的答案,了解如何开始生成 .xcframeworks,这是框架作者的长期解决方案
例如,假设我在终端中处于工作目录,在那里我的通用框架some_framework.framework
存在。如果我想在实际的物理设备上运行,我执行以下命令:
lipo -thin arm64 some_framework.framework/some_framework -output some_framework
使用上述命令,您提取arm64
二进制文件。然后,将当前的some_framework.framework/some_framework
替换为新生成的arm64
二进制文件。mv some_framework some_framework.framework
如果你的通用框架只由Objective-C源代码构建,那么你的工作就完成了。但是如果你还有Swift代码,那么你需要更新some_framework.framework/Modules/some_framework.swiftmodule
,以便它不包含任何对不是arm64
体系结构的引用。
在模拟器上运行时,你需要使用x86_64
,你将按照类似的过程进行操作。目前我维护两个版本的框架,直到这个问题被解决。每当我在模拟器和设备之间切换时,我只需切换项目中使用的框架即可。
除了mistahenry的回答外,您还可以使用此解决方法在项目中自动处理。
将不适用于Xcode 12.3的通用框架设置为不嵌入
(在常规→框架、库和嵌入内容中)
在“构建阶段”中添加这个“新运行脚本阶段”:
FRAMEWORK_APP_PATH="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
# 1. Copying FRAMEWORK to FRAMEWORK_APP_PATH
find "$SRCROOT" -name '*.framework' -type d | while read -r FRAMEWORK
do
if [[ $FRAMEWORK == *"MY_WONDERFUL_UNIVERSAL_FRAMEWORK.framework" ]]
then
echo "Copying $FRAMEWORK into $FRAMEWORK_APP_PATH"
cp -r $FRAMEWORK "$FRAMEWORK_APP_PATH"
fi
done
# 2. Loops through the frameworks embedded in the application and removes unused architectures.
find "$FRAMEWORK_APP_PATH" -name '*.framework' -type d | while read -r FRAMEWORK
do
if [[ $FRAMEWORK == *"MY_WONDERFUL_UNIVERSAL_FRAMEWORK.framework" ]]
then
echo "Strip invalid archs on: $FRAMEWORK"
FRAMEWORK_EXECUTABLE_NAME=$(/usr/libexec/PlistBuddy -c "Print CFBundleExecutable" "$FRAMEWORK/Info.plist")
FRAMEWORK_EXECUTABLE_PATH="$FRAMEWORK/$FRAMEWORK_EXECUTABLE_NAME"
echo "Executable is $FRAMEWORK_EXECUTABLE_PATH"
EXTRACTED_ARCHS=()
for ARCH in $ARCHS
do
echo "Extracting $ARCH from $FRAMEWORK_EXECUTABLE_NAME"
lipo -extract "$ARCH" "$FRAMEWORK_EXECUTABLE_PATH" -o "$FRAMEWORK_EXECUTABLE_PATH-$ARCH"
EXTRACTED_ARCHS+=("$FRAMEWORK_EXECUTABLE_PATH-$ARCH")
done
echo "Merging extracted architectures: ${ARCHS}"
lipo -o "$FRAMEWORK_EXECUTABLE_PATH-merged" -create "${EXTRACTED_ARCHS[@]}"
rm "${EXTRACTED_ARCHS[@]}"
echo "Replacing original executable with thinned version"
rm "$FRAMEWORK_EXECUTABLE_PATH"
mv "$FRAMEWORK_EXECUTABLE_PATH-merged" "$FRAMEWORK_EXECUTABLE_PATH"
codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements $FRAMEWORK_EXECUTABLE_PATH
else
echo "Ignored strip on: $FRAMEWORK"
fi
done
MY_WONDERFUL_UNIVERSAL_FRAMEWORK
替换为你的框架名称,并确保它位于 SRCROOT
目录下。