背景
实际开发中,遇到公司多个项目用到同一个工具或者同一个业务时,我们就可以把这部分业务或者功能做成一个组件,将内部所需资源和文件打包,所有项目共用;这样一来,开发成组件的这部分业务只需要独立维护就可以了,多个项目只管使用,省时又省力啊
关于组件
iOS中的组件
1、静态库 常见的是 .a
2、动态库常见的是 .dll(windows),.dylib(mac),so(linux)
3、framework(in Apple): Framework 是Cocoa/Cocoa Touch程序中使用的一种资源打包方式,可以将代码文件、头文件、资源文件、说明文档等集中在一起,方便开发者使用。也就是说我们的 framework其实是资源打包的方式,和静态库动态库的本质是没有关系的
关于静态库和动态库的详细描述:
静态库和动态库的区别
静态库: 链接时会被完整的复制到可执行文件中,所以如果两个程序都用了某个静态库,那么每个二进制可执行文件里面其实都含有这份静态库的代码
动态库: 链接时不复制,在程序启动后用dyld加载,然后再决议符号,所以理论上动态库只用存在一份,好多个程序都可以动态链接到这个动态库上面,达到了节省内存(不是磁盘是内存中只有一份动态库),还有另外一个好处,由于动态库并不绑定到可执行程序上,所以我们想升级这个动态库就很容易,windows和linux上面一般插件和模块机制都是这样实现的。
But我们的苹果爸爸在iOS平台上规定不允许存在动态库,并且所有的 IPA 都需要经过苹果爸爸的私钥加密后才能用,基本你用了动态库也会因为签名不对无法加载,(越狱和非 APP store 除外)。于是就把开发者自己开发动态库掐死在幻想中。
直到有一天,苹果爸爸的iOS升级到了8,iOS出现了APP Extension,swift编程语言也诞生了,由于iOS主APP需要和Extension共享代码,Swift语言的机制也只能有动态库,于是苹果爸爸尴尬了,不过这难不倒我们的苹果爸爸,毕竟我是爸爸,规则是我来定,我想怎样就怎样,于是提出了一个概念Embedded Framework,这种动态库允许APP和APP Extension共享代码,但是这份动态库的生命被限定在一个APP进程内。简单点可以理解为被阉割的动态库。
制作动态库framework
我们以制作微信的SDK为例,来说明动态库制作过程
1、新创建一个framework工程
2、将下载好的微信SDK文件拖进工程,这里可以想象如果是自己封装好的工具类,也是同样的道理
3、添加所依赖的系统库,我们制作的是动态库,可以看到Build Settings中,Mach-O Type可以选择所创建的库的类型
4、将需要暴露的头文件header拖到Public中
5、下面这个是关键,在Build Settings中搜索 other link,将Other Linker Flags项添加-Objc,至于为什么:
之所以使用该标志,和Objective-C的一个重要特性:类别(category)有关。根据这里的解释,Unix的标准静态库实现和Objective-C的动态特性之间有一些冲突:Objective-C没有为每个函数(或者方法)定义链接符号,它只为每个类创建链接符号。这样当在一个静态库中使用类别来扩展已有类的时候,链接器不知道如何把类原有的方法和类别中的方法整合起来,就会导致你调用类别中的方法时,出现"selectornotrecognized",也就是找不到方法定义的错误。为了解决这个问题,引入了-ObjC标志,它的作用就是将静态库中所有的和对象相关的文件都加载进来。
6、Edit Scheme
7、选择模拟器Common+B 一次,选择Generic iOS Device再Common+B 一次,可以看到动态库frame制作成功
8、为了不留遗憾,使用时可以模拟器也可以真机,在Build phrase中,New Run Script Phase
if [ "${ACTION}" = "build" ]
then
INSTALL_DIR=${SRCROOT}/Products/${PROJECT_NAME}.framework
DEVICE_DIR=${BUILD_ROOT}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework
SIMULATOR_DIR=${BUILD_ROOT}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework
if [ -d "${INSTALL_DIR}" ]
then
rm -rf "${INSTALL_DIR}"
fi
mkdir -p "${INSTALL_DIR}"
cp -R "${DEVICE_DIR}/" "${INSTALL_DIR}/"
#ditto "${DEVICE_DIR}/Headers" "${INSTALL_DIR}/Headers"
lipo -create "${DEVICE_DIR}/${PROJECT_NAME}" "${SIMULATOR_DIR}/${PROJECT_NAME}" -output "${INSTALL_DIR}/${PROJECT_NAME}"
open "${DEVICE_DIR}"
open "${SRCROOT}/Products"
fi
9、真机和模拟器都Build一遍之后就会在工程目录下生成Products文件夹
使用非系统framework
如果你把某个自己开发的动态库(系统的不算,毕竟苹果是爸爸)放在了Linked Frameworks and Libraries里面,程序一启动就会报Reason: Image Not Found,你只能把它放在Embeded Binaries里面才能正常使用。
在Embedded Binaries一栏也加一次就好了