最近更新了一回工程中的第三方库,发现AFNetworking和环信在传统导入Framework时,一运行就crash。控制台打印日志显示:
dyld: Library not loaded: @rpath/AFNetworking.framework/AFNetworking Referenced from: /var/containers/Bundle/Application/66CDB081-574E-4B56-A2ED-DF78FB15526E/xxx.app/xxx Reason: image not found
为什么先前没有碰到呢?Google之,发现AFNetworking新版本虽然形式依旧为Framework,但本质却改为动态库了。至于为什么要改为动态库,参照另一篇文章讲解。
好了,知道了问题就要解决。从Xcode6开始就提供了两种导入Framework的方式,一种是很早就有的Linked Frameworks and Libraries,静态库导入,跟代码一起编译进二进制文件;另一种是Xcode6,也就是iOS8开始提供的Embedded Binaries嵌入动态库的形式。动态库嵌入后输出的.app包,Framework结构如下:
接下来,在整个开发过程中,都不再碰到Framework引发的问题。可就在提交App Store时,Xcode报了这个错:
ERROR ITMS-90087: "Unsupported Architecture. Your executable contains unsupported architecture '[x86_64, i386]'."
按字面意思理解,是包里含有不支持的架构。x86_64和i386是模拟器架构,的确是在发布时不需要的。可是Framework是打好的包,如何去除是个问题。
于是继续Google之,在stackoverflow上有人碰到了一样的问题,原文的正确答案里给出了一段编译脚本可解决问题,脚本最初来自于一位老外技术博客里的原创解决方案。对于这种写脚本解决问题的老外,我能说两个字,牛逼!脚本如下,按需自取:
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
大意就是,读取目标app目录,取到Framework目录,遍历之,取出Framework,对其瘦身。
脚本添加后,可以指定在Archive时才使用,以免影响模拟器运行。