У меня есть приложение, использующее связанный и встроенный пользовательский фреймворк. Приложение было правильно создано для устройств iOS и симуляторов до Xcode 12.2. Однако, начиная с Xcode 12.3, я получаю следующую ошибку:

Сборка для iOS Simulator, но связанный и встроенный фреймворк My.framework был создан для iOS + iOS Simulator.

Фреймворк создан как для устройств, так и для симуляторов (как на самом деле говорит ошибка) и объединен с использованием lipo, поэтому он должен работать везде без проблем.

Я что-то упустил? Есть ли какие-либо соответствующие изменения в Xcode 12.3?

spassas

Ответов: 4

Ответы (4)

Боюсь, что это на самом деле правильная ошибка, и фреймворк не должен содержать код iOS и iOS Simulator одновременно. Apple пытается заставить нас использовать для этой цели XCFrameworks. Запустили в XCode 11 и просто ужесточили ограничения.

Единственный правильный способ решить эту проблему - перестроить фреймворк как XCFramework. Что легко сделать:

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

Вы можете начать с объединенного .framework, сделать две копии каркаса и использовать lipo для удаления фрагментов из двоичного файла, связанных с другим SDK.

На основе оригинального ответа Apple здесь.

Мой частный случай: я получаю эту ошибку, используя Rome, который производит эти фреймворки (возможное решение здесь). Кроме того, много борьбы происходит на стороне Карфагена.

Надеюсь, что это поможет;)

У меня есть фреймворк с универсальным двоичным кодом, который содержит x86_64 и arm64, которые я объединяю с lipo с настраиваемым скриптом во время сборки фреймворка. Я столкнулся с той же проблемой для XCode 12.3 и пока создал обходной путь. Надеюсь, это быстро исправится в XCode, но до тех пор одно быстрое исправление будет заключаться в уменьшении архитектуры и использовании необходимой инфраструктуры. РЕДАКТИРОВАТЬ: см. мой ответ здесь о том, как начать создавать .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, ваша работа сделана. Но если у вас тоже есть быстрый код, вам нужно будет обновить some_framework.framework / Modules / some_framework.swiftmodule, чтобы он не содержал ссылок на архитектуры, отличные от arm64.

Вы должны выполнить аналогичный процесс для запуска на симуляторе, за исключением того, что вам потребуется x86_64. В настоящее время я поддерживаю две версии своего фреймворка, пока это не будет исправлено. Всякий раз, когда я переключаюсь между симулятором и устройством, я просто переключаю, какой фреймворк находится в моем проекте.

Вы должны исключить архитектуры устройства при построении для симулятора, а при создании для устройства вы должны исключить архитектуры симулятора.

Для этого перейдите к Настройки сборки вашего проекта -> Исключенные архитектуры -> Выберите конфигурацию (Debug / Release / Etc ...) -> Tap + - > Любой SDK симулятора iOS -> Добавить arm64, arm64e, armv7

Аналогичным образом добавьте x86_64, i386 к Any iOS SDK.

enter image description here

PS: Вы можете проверить все архитектуры, присутствующие в вашей структуре, запустив file или lipo -info .

Пример.файл /Users/srikanth.kv/MyProject/MyLibrary.framework/MyLibrary

In addition to @mistahenry answer you can handle this automatically in yout project with this workaround.

  1. Установите универсальную платформу, которая не работает в XCode 12.3, на Не встраивать (в разделе «Общие»> «Фреймворки, библиотеки и встроенное содержимое»)
  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

2022 WebDevInsider