Xcode 12.3: 为 iOS 模拟器构建,但是链接和嵌入式框架是为 iOS + iOS 模拟器构建的

我有一个使用链接和嵌入式自定义框架的应用程序。在 Xcode 12.2之前,这个应用程序都是为 iOS 设备和模拟器构建的。然而,从 Xcode 12.3开始,我得到了以下错误:

构建 iOS 模拟器,但是链接和嵌入式框架‘ My.Framework’是为 iOS + iOS 模拟器构建的。

这个框架是为设备和模拟器构建的(正如错误实际上所说的) ,并且使用 lipo进行了合并,因此它应该能够在任何地方运行而不会出现问题。

我是不是漏掉了什么? Xcode 12.3有相关的改动吗?

106313 次浏览

我有一个包含通用二进制的框架,其中包含 x86_64arm64,我在框架构建时将它们与 lipo合并,并使用自定义脚本。我在 Xcode 12.3中遇到了同样的问题,现在已经创建了一个解决方案。希望这个问题能够在 Xcode 很快得到解决,但是在那之前,一个快速的解决方案是瘦化架构并使用你所需要的框架。

请参阅 我在这里的答案是关于如何开始生成.xc 框架,这是框架作者的长期解决方案

例如,让我们假设我在一个终端工作目录中,我的通用框架 some_framework.framework就在那里。如果我想在实际的物理设备上运行,我会执行以下命令:

lipo -thin arm64 some_framework.framework/some_framework -output some_framework

使用上面的命令,可以提取 arm64二进制文件。然后,用新生成的仅 arm64二进制文件替换当前的 some_framework.framework/some_framework

mv some_framework some_framework.framework

如果您有一个只从 Objective-C 源构建的通用框架,那么您的工作就完成了。但是如果您也有 Swift 代码,那么您需要更新 some_framework.framework/Modules/some_framework.swiftmodule,以便它不包含任何对非 arm64的体系结构的引用。

除了需要 x86_64之外,在模拟器上运行时可以遵循类似的过程。目前我正在维护我的框架的两个版本,直到这个问题得到解决。每当我在模拟器和设备之间切换时,我只需切换出项目中的框架。

你必须排除设备架构,而建设为模拟器,而建设为设备,你必须排除模拟器的架构。

为此,导航到项目的 Build Settings-> Excluded Architectures-> 选择配置(Debug/Release/etc. .)。.)- > 点击 +-> Any iOS Simulator SDK-> 添加 arm64arm64earmv7

类似地,将 x86_64i386添加到 Any iOS SDK

enter image description here

PS: 您可以通过运行 file <path_to_framework_binary>lipo -info <path_to_framework_binary>检查框架中的所有架构。

前任

除了 Misahenry 的回答之外,您还可以使用此解决方案在项目中自动处理这个问题。

  1. 将不能在 Xcode 12.3中工作的 Universal 框架设置为 Do not embed(在 将军框架、库和嵌入式内容中)

  2. 在“构建阶段”中添加这个“新的运行脚本阶段”:

    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

我担心这实际上是正确的错误,框架不应该同时包含 iOS 和 iOS 模拟器代码。苹果试图强迫我们为此使用 XCFramework。他们从 Xcode 11开始,只是加强了限制。

解决这个问题的唯一正确方法是将框架重新构建为 XCFramework,这很容易做到:

xcrun xcodebuild -create-xcframework \
-framework /path/to/ios.framework \
-framework /path/to/sim.framework \
-output combined.xcframework

您可以从一个组合 .framework开始。制作框架的两个副本,并使用 lipo从与另一个 SDK 关联的二进制文件中删除片。

它是基于苹果 给你的原始答案。

我的特殊情况是我使用 罗马得到了这个错误,它产生了这些框架(一个可能的解决方案是 给你)。而且,在 迦太基那边上也有很多挣扎。