使用 Xcode 6 ,我们可以创建自己的动态Cocoa Frameworks
。
因为:
模拟器仍然使用32-bit
库
从2015年6月1日开始,提交到App Store的应用更新必须包含64位支持,并使用iOS 8 SDK(developer.apple.com)构建
我们必须使胖库在设备和模拟器上运行项目。即支持框架中的32位和64位。
但我没有找到任何手册,如何导出通用胖框架以便将来与其他项目集成(并与某人共享此库)。
在ONLY_ACTIVE_ARCH=NO
Build Settings
将支持armv7 armv7s arm64 i386 x86_64
添加到Architectures
(肯定)
但最终我仍然遇到在设备和模拟器上同时使用此框架运行项目的问题。
如果我从Debug-iphoneos
文件夹中获取框架 - 它可以在设备上运行
并在模拟器上获取错误:ld: symbol(s) not found for architecture i386
xcrun lipo -info CoreActionSheetPicker
胖文件中的架构:CoreActionSheetPicker是:armv7 armv7s arm64
如果我从Debug-iphonesimulator
文件夹中获取框架 - 它适用于模拟器。我在设备上遇到错误:ld: symbol(s) not found for architecture arm64
xcrun lipo -info CoreActionSheetPicker
胖文件中的架构:CoreActionSheetPicker是:i386 x86_64
此答案与Xcode 6 iOS Creating a Cocoa Touch Framework - Architectures issues有关,但并非重复。
我发现了这种情况的“肮脏黑客”。查看我的answer below。 如果有人知道更方便的方式 - 请告诉我!
答案 0 :(得分:78)
这个答案的实际情况是:2015年7月。事情很可能会发生变化。
TLDR;
目前Xcode没有自动导出通用胖框架的工具,因此开发人员必须使用lipo
工具的手动使用。同样根据this radar提交给AppStore开发人员之前,框架的消费者也必须使用lipo
从框架中剥离模拟器切片。
更长的答案如下
我在这个主题上做了类似的研究(答案底部的链接)。
我没有找到任何关于分发的官方文档,因此我的研究基于对Apple Developer Forums,Carthage和Realm项目的探索以及我自己的xcodebuild
,lipo
,{{1}的实验工具。
这是来自Apple Developer论坛帖子Exporting app with embedded framework的长引用(带有一点标记):
从框架项目中导出框架的正确方法是什么?
目前唯一的方法就是你所做的:
- 为模拟器和iOS设备构建目标。
导航到该项目的Xcode的DerivedData文件夹,并将两个二进制文件组合成一个单独的框架。但是,在Xcode中构建框架目标时,请确保将目标设置“仅构建活动体系结构”调整为“否”。这将允许Xcode为多种binarty类型(arm64,armv7等)构建目标。这就是为什么它可以从Xcode运行而不是作为一个独立的二进制文件。
此外,您还需要确保将方案设置为发布版本并构建针对发布的框架目标。 如果仍然遇到库未加载错误,请检查框架中的代码片。
- 使用
codesign
并检查结果。
lipo -info MyFramworkBinary
结果为
lipo -info MyFrameworkBinary
- 现代通用框架将包含4个切片,但可能包含更多:
i386 x86_64 armv7 arm64
如果您没有看到至少这4,那可能是因为Build Active Architecture设置。
这描述了与@skywinder在答案中所做的完全相同的过程。
这是Carthage uses lipo和Realm uses lipo。
的方式重要细节
雷达:Xcode 6.1.1 & 6.2: iOS frameworks containing simulator slices can't be submitted to the App Store以及围绕Realm#1163和Carthage#188进行的长时间讨论,结束于特殊的解决方法:
在提交到AppStore之前必须从模拟器切片中删除iOS框架二进制文件
Carthage有特殊代码:CopyFrameworks和相应的文档:
此脚本适用于由通用二进制文件触发的App Store submission bug。
Realm有特殊脚本:strip-frameworks.sh和相应的文档:
归档通用二进制文件时,需要执行此步骤App Store submission bug。
还有好文章:Stripping Unwanted Architectures From Dynamic Libraries In Xcode。
我自己使用了Realm的i386 x86_64 armv7 arm64
,它完美地为我工作而没有任何修改,当然任何人都可以从头开始写一个。
我建议阅读的主题链接,因为它包含此问题的另一个方面:代码签名 - Creating iOS/OSX Frameworks: is it necessary to codesign them before distributing to other developers?
答案 1 :(得分:56)
这不是那么明确的解决方案,但我找到了唯一的方法:
在ONLY_ACTIVE_ARCH=NO
Build Settings
在您的框架的控制台Products
文件夹中打开(您可以通过开放框架文件夹和cd ..
从那里打开它)
Products
文件夹中运行 this 脚本。它在此文件夹中创建fat Framework。 (或按照下面 3.4。中所述的那样手动完成)或者:
通过此脚本使用 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
答案 2 :(得分:10)
Run Script Phase
以自动复制所需的预编译框架正在运行的架构
echo "Copying frameworks for architecture: $CURRENT_ARCH"
if [ "${CURRENT_ARCH}" = "x86_64" ] || [ "${CURRENT_ARCH}" = "i386" ]; then
cp -af "${SRCROOT}/Frameworks/Simulator/." "${SRCROOT}/Frameworks/Active"
else
cp -af "${SRCROOT}/Frameworks/Device/." "${SRCROOT}/Frameworks/Active"
fi
这样我就没有使用lipo
来创建一个胖框架,而不是Realm的strip-frameworks.sh
来提交到App Store时删除不必要的切片。
答案 3 :(得分:2)
基本上为此我找到了非常好的解决方案。你只需要遵循这些简单的步骤。
lipo -create'device / MyFramework.framework / MyFramework' 'simulator / MyFramework.framework / MyFramework'-output 'MyFramework.framework / MyFramework'
就是这样。在这里,我们合并MyFramework.framework中存在的MyFramework二进制文件的模拟器和设备版本。我们获得了一个通用框架,可以为所有架构构建,包括模拟器和设备。
答案 4 :(得分:2)
我只想通过@odm更新this great answer。从Xcode 10开始,CURRENT_ARCH
变量不再反映构建体系结构。所以我改为更改脚本来检查平台:
echo "Copying frameworks for platform: $PLATFORM_NAME"
rm -R "${SRCROOT}/Frameworks/Active"
if [ "${PLATFORM_NAME}" = "iphonesimulator" ]; then
cp -af "${SRCROOT}/Frameworks/Simulator/." "${SRCROOT}/Frameworks/Active"
else
cp -af "${SRCROOT}/Frameworks/Device/." "${SRCROOT}/Frameworks/Active"
fi
我还添加了一行以在复制之前清除目标目录,因为我注意到否则子目录中的其他文件不会被覆盖。
答案 5 :(得分:1)
我的答案涵盖以下几点:
制作适用于模拟器和设备的框架
如何导出“胖”Cocoa Touch Framework(适用于模拟器和设备)?
架构的未定义符号x86_64
ld:找不到架构x86_64
步骤1:首先使用Simulator目标构建框架
步骤2:模拟器构建过程成功后,现在为您的框架构建设备目标选择或通用iOS设备选择
步骤3:现在选择您的框架目标,并在“Build Phases”下选择“Add Run Script”并复制以下脚本代码)
Step4:最后,再次构建,您的框架已准备好兼容模拟器和设备。乌拉!!!!
[注意:我们必须在最终步骤4之前准备好两个兼容框架(模拟器和设备架构兼容,如果没有,请正确执行上述步骤1和2)
参见参考图片:
将以下代码放入shell区域:
#!/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 (if it exists) to the copied framework directory
SIMULATOR_SWIFT_MODULES_DIR="${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/Modules/${PROJECT_NAME}.swiftmodule/."
if [ -d "${SIMULATOR_SWIFT_MODULES_DIR}" ]; then
cp -R "${SIMULATOR_SWIFT_MODULES_DIR}" "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/Modules/${PROJECT_NAME}.swiftmodule"
fi
# 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 "${BUILD_DIR}/${CONFIGURATION}-universal"