从Xcode中的动态库中剥离不需要的架构
自从发布iOS 8以来,开发人员已经能够利用动态库的优势进行iOS开发。
对于一般开发,为所有需要的体系结构提供一个动态库是一件很棒的事,这样您就可以在所有设备和iOS Simulator上运行而无需进行任何更改。
在我的项目及其各种扩展中,我使用了Reactive Cocoa,并将它作为预编译的动态库包含在我的项目中,其中包含Simulator 和设备的i386和x86_64slice 。armv7arm64
但是,这种方法有一个缺点-因为它们是在运行时链接的,所以当动态库单独编译到最终运行的应用程序时,就无法确定实际需要哪种架构。因此,Xcode只会在编译时将整个内容复制到您的应用程序包中。除了浪费磁盘空间之外,从理论上讲,这没有真正的缺点。但是实际上,iTunes Connect不喜欢我们添加未使用的二进制切片:
提交AppStore 提示Unsupported Architectures. Your executable contains unsupported architectures ‘[X86_64, i386]’.
解决
那么,我们如何解决这个问题?
-
我们可以改用静态库。但是,在我的项目中有多个目标和扩展,用相同库的副本膨胀我的所有可执行文件似乎很愚蠢。
-
我们可以每次从源代码编译该库,从而生成一个新的动态库,其中仅包含每个构建所需的架构。有两件事让我感到困扰-首先,一直都在重新编译所有不变的代码似乎很浪费,第二是我喜欢保持依赖关系为静态,并且每次都进行新的构建意味着我没有必须再运行稳定的代码,尤其是如果我开始在Xcode Beta中四处乱搞的时候。如果更改编译器导致库中出现奇怪的错误怎么办?这是非常罕见的事情,但是确实发生了,而且我不知道该库的代码库足以调试它。
-
如果我们没有开始的源头,那么,我们有点不走运。
-
我们可以在构建时弄清楚如何处理它,然后再也不必考虑它。听起来更像!
脚本解决
今天,我整理了一些构建时脚本来处理此问题,因此我不必再在意它了。
在我的项目文件夹中:
$ lipo -info Vendor/RAC/ReactiveCocoa.framework/ReactiveCocoa
→ Architectures in the fat file: ReactiveCocoa are:
i386 x86_64 armv7 arm64
按下“ build”后:
$ lipo -info Cascable.app/Frameworks/ReactiveCocoa.framework/ReactiveCocoa
→ Architectures in the fat file: ReactiveCocoa are:
armv7 arm64
事不宜迟,这里是脚本。在构建步骤中添加一个“运行脚本”步骤,将其放置在嵌入框架的步骤之后,将其设置为“使用”,/bin/sh然后输入以下脚本:
APP_PATH="${TARGET_BUILD_DIR}/${WRAPPER_NAME}"
# This script loops through the frameworks embedded in the application and
# removes unused architectures.
find "$APP_PATH" -name '*.framework' -type d | while read -r FRAMEWORK
do
FRAMEWORK_EXECUTABLE_NAME=$(defaults read "$FRAMEWORK/Info.plist" CFBundleExecutable)
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"
done
该脚本将浏览您构建的应用程序的Frameworks文件夹,并确保每个框架中仅存在要构建的体系结构。
好多了!现在,我可以在项目中添加大量动态库,其中包含我将需要的所有体系结构,并且构建过程将处理在任何给定时刻适合哪些体系结构。
参考
https://stackoverflow.com/questions/30547283/submit-to-app-store-issues-unsupported-architecture-x86
http://ikennd.ac/blog/2015/02/stripping-unwanted-architectures-from-dynamic-libraries-in-xcode/