我正在尝试为iOS应用制作动态框架。感谢新版本的Xcode(6),我们可以在创建新项目时选择Cocoa Touch Framework,不再需要添加聚合目标,运行脚本等等。构建框架时我没有问题。但是,当我尝试在iOS应用程序中使用它时,我会遇到一些架构问题。
ld: warning: ignoring file /Library/Frameworks/MyFramework.framework/MyFramework, file was built for x86_64 which is not the architecture being linked (arm64): /Library/Frameworks/MyFramework.framework/MyFramework
Undefined symbols for architecture arm64:
"_OBJC_CLASS_$_MyFrameworkWebService", referenced from:
objc-class-ref in AppDelegate.o
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
ld: warning: ignoring file /Library/Frameworks/MyFramework.framework/MyFramework, file was built for x86_64 which is not the architecture being linked (armv7): /Library/Frameworks/MyFramework.framework/MyFramework
Undefined symbols for architecture armv7:
"_OBJC_CLASS_$_MyFrameworkWebService", referenced from:
objc-class-ref in AppDelegate.o
ld: symbol(s) not found for architecture armv7
clang: error: linker command failed with exit code 1 (use -v to see invocation)
我已经尝试更改框架项目和目标的设置(仅限架构和构建有效架构和有效架构)。我为iOS应用程序项目做了同样的事情,但没有任何作用。我认为有些事情我不明白。
例如,当我仅为i386(iOS模拟器)构建框架时,请使用命令行进行检查 " xcrun lipo -info MyFramework",我有一个问题
ld:警告:忽略文件/Library/Frameworks/MyFramework.framework/MyFramework,文件是为x86_64构建的,而不是被链接的架构(i386)......
如果有人可以帮助我获得适用于所有iOS架构(包括模拟器)的框架。
答案 0 :(得分:66)
根据所有回复,由post on raywenderlich.com创建的gist和Chris Conway我提出了this。
执行以下步骤,我能够构建一个Cocoa Touch框架(包括Swift和Objective-C文件),其中包含模拟器和设备的所有体系结构:
答案 1 :(得分:47)
尝试以下步骤来创建包含框架项目和应用项目的工作区。
工作区:
框架项目:
应用项目:
请注意,上面的示例演示了如何构建在模拟器中运行的应用。如果您需要创建在模拟器和设备上运行的通用静态库,那么一般步骤如下:
网上有很多关于它的参考资料,例如here。
为框架创建通用二进制文件:导航到框架Derived Data目录然后 / Build / Products ,以下命令可以帮助您在 Products 目录中创建通用二进制文件:
lipo -create -output "framework-test-01-universal" "Debug-iphonesimulator/framework-test-01.framework/framework-test-01" "Debug-iphoneos/framework-test-01.framework/framework-test-01"
请注意, framework-test-01 是我的框架项目名称。
答案 2 :(得分:13)
在项目的ONLY_ACTIVE_ARCH=NO
中设置Build Settings
。
在您的框架的控制台Products
文件夹中打开(您可以通过开放框架文件夹和cd ..
从那里打开它)
从Products
文件夹中运行 this script 。它在此文件夹中创建fat Framework。 (或按照下面 4.5。中的说明手动完成)
framework_name="${$(basename $(find ./Debug-iphoneos -type d -name '*.framework' -maxdepth 1))%.*}" && \
cp -R Debug-iphoneos/$framework_name.framework ./$framework_name.framework && \
lipo -create -output "$framework_name.framework/$framework_name" "Debug-iphonesimulator/$framework_name.framework/$framework_name" "Debug-iphoneos/$framework_name.framework/$framework_name"
或者:
通过此脚本使用 lipo 组合这两个框架(将YourFrameworkName
替换为您的框架名称)
lipo -create -output "YourFrameworkName" "Debug-iphonesimulator/YourFrameworkName.framework/YourFrameworkName" "Debug-iphoneos/YourFrameworkName.framework/YourFrameworkName"
替换现有框架中的新二进制文件:
cp -R Debug-iphoneos/YourFrameworkName.framework ./YourFrameworkName.framework
mv YourFrameworkName ./YourFrameworkName.framework/YourFrameworkName
./YourFrameworkName.framework
- 是现成的胖二进制文件!您可以将其导入项目! 对于项目,不在xcworkspace
- es:
您也可以尝试使用this gist但似乎它不适用于工作空间中的项目。
答案 3 :(得分:10)
我这样做的方式类似于vladof,但希望有点简单。我将框架作为应用程序项目的子项目。
框架项目
App项目
对于Obj-C应用程序
对于Swift应用程序
通过这种方式,应用程序依赖于框架,因此如果您在框架类中进行更改,您不必更改目标以单独构建框架,它将首先编译框架,然后是应用程序。
答案 4 :(得分:7)
我已经改变了某人的脚本以支持所有Simulator的架构:
UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal
# make sure the output directory exists
mkdir -p "${UNIVERSAL_OUTPUTFOLDER}"
# Step 1. Build Device and Simulator versions
xcodebuild -target "${PROJECT_NAME}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphoneos BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build
xcodebuild -target "${PROJECT_NAME}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphonesimulator VALID_ARCHS="x86_64 i386" BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build
# Step 2. Copy the framework structure to the universal folder
cp -R "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework" "${UNIVERSAL_OUTPUTFOLDER}/"
# Step 3. Create universal binary file using lipo and place the combined executable in the copied framework directory
lipo -create -output "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework/${PROJECT_NAME}"
# Step 4. Convenience step to copy the framework to the project's directory
cp -R "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework" "${PROJECT_DIR}"
# Step 5. Delete temporary build directory in the project's directory
rm -rf "${PROJECT_DIR}/build"
# Step 6. Convenience step to open the project's directory in Finder
open "${PROJECT_DIR}"
答案 5 :(得分:2)
自上述链接之前我所做的旧视频已不再可用。
答案 6 :(得分:1)
vladof共享的方法很少有更多适用于基于swift的框架
答案 7 :(得分:1)
最后,我让它为我工作! 抱歉黄色的大框架,我不知道如何更好地格式化它。
解决方案来自Claudio Romandi,但链接的脚本有一个小问题。我无法对他的帖子发表评论,因为我需要50个声誉,所以我没有别的选择,只能复制他的帖子以获得完整的解决方案..
将以下代码放入其中:
#!/bin/sh
UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal
# make sure the output directory exists mkdir -p "${UNIVERSAL_OUTPUTFOLDER}"
# Step 1. Build Device and Simulator versions xcodebuild -target "${PROJECT_NAME}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION}
-sdk iphoneos BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build xcodebuild -target "${PROJECT_NAME}" -configuration ${CONFIGURATION} -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build
# Step 2. Copy the framework structure (from iphoneos build) to the universal folder cp -R "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework" "${UNIVERSAL_OUTPUTFOLDER}/"
# Step 3. Copy Swift modules (from iphonesimulator build) to the copied framework directory cp -R "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/Modules/${PROJECT_NAME}.swiftmodule/." "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/Modules/${PROJECT_NAME}.swiftmodule"
# Step 4. Create universal binary file using lipo and place the combined executable in the copied framework directory lipo -create
-output "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework/${PROJECT_NAME}"
# Step 5. Convenience step to copy the framework to the project's directory cp -R "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework" "${PROJECT_DIR}"
# Step 6. Convenience step to open the project's directory in Finder open "${PROJECT_DIR}"
在方案选择下拉列表中选择聚合
问题是模拟器目录指向一个不存在的目录,正在改变" Framework"到" $ {PROJECT_NAME}"在2个地方做了诀窍:))
答案 8 :(得分:1)
想在skywinder here提供的lipo脚本答案中添加一些内容。我遵循了这些步骤,但是仍然无法让我的框架在仅设备的模拟器上运行。要解决此问题:
-我进入了框架的debug-iphonesimulator版本,并且在Modules / [FrameworkName] .swiftmodule中,我复制了所有i386和X86文件。
-然后,我进入了新创建的胖版本框架,并导航到该文件夹。我粘贴了i386和X86文件(与已经存在的ARM文件一起),然后将胖框架添加到我的项目中。
Voila,她在模拟器和真实设备上工作!这是Xcode 10 / Swift 4.2 btw
答案 9 :(得分:1)
这个问题是不久前发布的(Xcode 6),但是最近我在Xcode 10上遇到了同样的问题。
所以问题是:构建的框架不支持足够的架构。
如果不知道哪种架构代表什么,则不同的iPhone设备具有不同的架构,下面是完整列表:
因此,如果您在模拟器上使用框架,则该框架需要支持i386或x86_64。如果您在iPhone 6上运行您的应用程序,则该框架需要支持arm64架构。
因此,在大多数情况下,框架需要支持所有上述架构。
现在回到如何解决问题。我们需要为设备和模拟器构建框架。
如何为设备构建:
如何构建模拟器:
如何同时针对设备和模拟器进行构建:
有了设备框架后,您需要将模拟器框架和设备框架与“ lipo”命令结合在一起。 将模拟器框架重命名为[MyFrameworkProject] _sim.framework并将两个框架复制到同一文件夹中。在终端中运行以下命令(确保您位于文件夹中):
lipo -create -output [MyFrameworkProject].framework/[MyFrameworkProject] [MyFrameworkProject].framework/MyFrameworkProject [MyFrameworkProject]_sim.framework/MyFrameworkProject
现在[MyFrameworkProject] .framework是同时支持模拟器和设备的最终产品。
答案 10 :(得分:0)
对不起,我已经让这个话题打开了这么长时间......你们中的一些人已经正确回答了我的问题。当我写这个问题时,我没有发现在一个完整的(也称为胖)框架(准备使用)中有两个切片。一个用于iOS设备,一个用于模拟器。当我发现我使用lipo命令创建一个脚本来融合两个切片并自动获得一个完整的框架。