天天看点

Xcode 6制作动态及静态通用Framework(解决不支持 armv7s arm64 armv7)

有没有写SDK或者要将一些常用的工具类做成Framework的经历? 你或许自己写脚本完成了这项工作,相信也有很多的人使用 iOS-Universal-Framework ,随着Xcode 6的发布,相信小伙伴们已经都知道了,Xcode 6支持做Framework了. 同时iOS-Universal-Framework开发者也宣布不在继续维持此项目的开发,建议开发者使用Xcode 6制作,目前网上也有很多制作iOS Framework的资料,但大多都不够详细,接下来本文会详情介绍一下在Xcode 6下制作iOS Framework.

关于静态库和动态库的概念,网上资料很多,这里不做叙述,只讲解制作过程。

创建iOS动态库

新建工程并选择默认Target为Cocoa Touch Framework, 如图:

Xcode 6制作动态及静态通用Framework(解决不支持 armv7s arm64 armv7)

做编码工作,在这里我简单的写了一个Utils的类,并写了一个log方法

Xcode 6制作动态及静态通用Framework(解决不支持 armv7s arm64 armv7)

设置开放的头文件:Framework中有些类可能是一些私有的辅助工具,不需要使用者看到,在这里只需要把开放出去的类放到Public下, 如图

Xcode 6制作动态及静态通用Framework(解决不支持 armv7s arm64 armv7)

这样生成的Framework的Headers目录下也只能看到Public的头文件

Xcode 6制作动态及静态通用Framework(解决不支持 armv7s arm64 armv7)

编码完成之后,直接Run就能成功生成Framework文件了,选择 xCode->Window->Organizer->Projects->Your Project, 打开工程的Derived Data目录,这样就能找到生成的Framework文件了,如图

Xcode 6制作动态及静态通用Framework(解决不支持 armv7s arm64 armv7)
Xcode 6制作动态及静态通用Framework(解决不支持 armv7s arm64 armv7)

新建测试工程,使用生成的Framework

将Framework文件导入到测试工程,调用Framework中的代码

MyUtils *utils = [MyUtils new]; 
[utils log:@"didFinishLaunchingWithOptions"];
           

运行报错(Reason: Image Not Found)

Xcode 6制作动态及静态通用Framework(解决不支持 armv7s arm64 armv7)

为什么会这样的?因为我们做的是动态库,在使用的时候需要额外加一个步骤,要把Framework同时添加到‘Embedded Binaries’中

Xcode 6制作动态及静态通用Framework(解决不支持 armv7s arm64 armv7)

注意: 在XCode 6之前是没有这个选项的(我没发现),所以理论上XCode 5及之前的版本无法使用Xcode 6下生成的Framework动态库。

到这里,假定你整个过程都是使用的模拟器做的,那看上去会很顺利。这时候尝试将测试工程部署到真机上,问题来了

ld: warning: ignoring file /work/ios/MyFrameworkTest/MyFrameworkTest/MyFramework.framework/MyFramework, file was built for x86_64 which is not the architecture being linked (armv7): /work/ios/MyFrameworkTest/MyFrameworkTest/MyFramework.framework/MyFramework

Undefined symbols for architecture armv7:

  "_OBJC_CLASS_$_MyUtils", 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)

为什么会这样?错误提示已经很明显了,因为我们制作动态库的时候,选的设备是模拟器,如果选真机的话,那生成的库也只能在真机上使用,那我们该怎样制作一个通用的动态库呢? 简单的方法是分别生成模拟器和真机上运行的库,然后在合并,这个方法,在每次生成动态库的时候,过程都会很繁琐,下面我们用一个脚本来自动完成它。

制作通用动态库

新建Aggregate Target

Xcode 6制作动态及静态通用Framework(解决不支持 armv7s arm64 armv7)

添加script到新建的Target

Xcode 6制作动态及静态通用Framework(解决不支持 armv7s arm64 armv7)
# Sets the target folders and the final framework product.
# 如果工程名称和Framework的Target名称不一样的话,要自定义FMKNAME
# 例如: FMK_NAME = "MyFramework"
FMK_NAME=${PROJECT_NAME}
# Install dir will be the final output to the framework.
# The following line create it in the root folder of the current project.
INSTALL_DIR=${SRCROOT}/Products/${FMK_NAME}.framework
# Working dir will be deleted after the framework creation.
WRK_DIR=build
DEVICE_DIR=${WRK_DIR}/Release-iphoneos/${FMK_NAME}.framework
SIMULATOR_DIR=${WRK_DIR}/Release-iphonesimulator/${FMK_NAME}.framework
# -configuration ${CONFIGURATION}
# Clean and Building both architectures.
xcodebuild -configuration "Release" -target "${FMK_NAME}" -sdk iphoneos clean build
xcodebuild -configuration "Release" -target "${FMK_NAME}" -sdk iphonesimulator clean build
# Cleaning the oldest.
if [ -d "${INSTALL_DIR}" ]
then
rm -rf "${INSTALL_DIR}"
fi
mkdir -p "${INSTALL_DIR}"
cp -R "${DEVICE_DIR}/" "${INSTALL_DIR}/"
# Uses the Lipo Tool to merge both binary files (i386 + armv6/armv7) into one Universal final product.
lipo -create "${DEVICE_DIR}/${FMK_NAME}" "${SIMULATOR_DIR}/${FMK_NAME}" -output "${INSTALL_DIR}/${FMK_NAME}"
rm -r "${WRK_DIR}"
open "${INSTALL_DIR}"
           

选中新建的Target,Run, 如果没有异常的话,会自动弹出生成的Framework文件

Xcode 6制作动态及静态通用Framework(解决不支持 armv7s arm64 armv7)

这样生成的动态库就能同时支持模拟器和真机了。

Xcode 6下制作通用静态库

上面我们也提到了,这样生成的动态库恐怕很难在Xcode 5上使用,那我们为什么非要用动态库呢,一般情况下不是用静态库就好了吗? So Easy!只需要修改一个参数即可生成静态库了。

Xcode 6制作动态及静态通用Framework(解决不支持 armv7s arm64 armv7)

使用静态库的话,就可以把Framework从‘Embedded Binaries’中删除了. 亲测在Xcode 5下可用。把新生成的库导入到测试工程,试试在模拟器和真机上运行,一切OK.

不巧,如果你用的真机是iPhone5 C, 那悲剧又要发成了,生成的Framework竟然不支持armv7s,不知是Xcode 6的bug,还是因为苹果认为使用armv7s的设备太少,可以不支持了.Xcode 新建工程,默认的Architectures竟然不包含armv7s.

Xcode 6制作动态及静态通用Framework(解决不支持 armv7s arm64 armv7)

想要生成的库支持armv7s,把armv7s添加到Architectures中,重新生成Framework即可

Xcode 6制作动态及静态通用Framework(解决不支持 armv7s arm64 armv7)

判断一个Framework支持哪些架构

我们该怎么验证生成的Framework支持哪些平台呢,总不能一个个测试吧?当然不用.下面的命令是加上armv7s前后生成的framework的对比

Yearsdembp:Products Years$ lipo -info ./MyFramework.framework/MyFramework 
Architectures in the fat file: ./MyFramework.framework/MyFramework are: i386 x86_64 armv7 arm64 
Yearsdembp:Products Years$ lipo -info ./MyFramework.framework/MyFramework 
Architectures in the fat file: ./MyFramework.framework/MyFramework are: armv7 armv7s i386 x86_64 arm64