开篇扯淡:
什么情况下需要用到静态库呢?
1、例如我们常用的第三方SDK(微信、支付宝、高德地图、友盟等等),像要将自己公司的核心技术共享出来使用,但是又不想让开发者看到源码实现,需要采用闭源的方式,就需要使用静态库进行打包提供给外部使用;
2、例如项目中的一些模块及组件,想要使用闭源模式抽取给到其他项目组使用,也需要使用静态库打包;
3、自己项目中的可以抽取封装的一些较大的模块或组件,封装好后需求基本不会有太大改动,可以封装成静态库进行二进制集成到项目中使用,减少代码编译时间。
介绍
iOS有两种库:静态库和动态库,所谓库就是程序代码的集合,是共享程序代码的一种方式。
静态库分为.a和.framework,动态库分为.dylib和.framework。
其区别在于:链接静态库的时候,静态库会被完整地复制到可执行文件中,被多次使用就会被多次复制;而链接动态库的时候,动态库不会被复制,程序运行的时候,系统会将库动态加载到内存中,供程序调用,且只加载一次,多个程序共用,节省内存空间。
注意:
iOS平台 在 iOS8 之前,苹果不允许第三方框架使用动态方式加载,从 iOS8 开始允许开发者有条件地创建和使用动态框架,这种框架叫做 Cocoa Touch Framework。
虽然同样是动态框架,但是和系统 framework 不同,app 中使用 Cocoa Touch Framework 制作的动态库 在打包和提交 app 时会被放到 app main bundle 的根目录 中,运行在沙盒里,而不是系统中。
也就是说,不同的 app 就算使用了同样的 framework,但还是会有多份的框架被分别签名,打包和加载。不过 iOS8 上开放了 App Extension 功能,可以为一个应用创建插件,这样主app和插件之间共享动态库还是可行的。
苹果系统专属的framework 是共享的(如UIKit), 但是我们自己使用 Cocoa Touch Framework 制作的动态库是放到 app bundle 中,运行在沙盒中的。
下面开始创建静态库工程
创建静态库可以选择Cocoa Touch Framework和Cocoa Touch Static Library,分别就是所谓的.framework和.a库,顺带说一下两种库之间的区别吧:
.a是纯二进制文件,例如项目中含有.c和.cpp的类文件,就需要使用.a库;
.framework中除了二进制文件,还有资源文件bundle(包括图片资源、xib、storyboard等等);
.a文件不能直接使用,至少要有.h文件配合,.framework文件可以直接使用;
.framework = .a + .h + sourceFile,所以.framework使用的范围更广,一般情况下都是使用.framework库;
这里我们使用.framework库,也就是选择Cocoa Touch Framework创建项目:
创建好之后就是这个样子接下来需要做一些静态库配置的修改:
1、在Build Settings -> Linking中,找到Mach-O Type,将其设置为Static Library;
2、在Build Settings -> Architectures中找到Build Active Architecture Only,将其设置为NO(Debug和Release都设为NO);
当Debug和Release属性设置为YES时,是为了debug的时候编译速度更快,它只编译当前的architecture版本;
而当设置为NO时,会编译所有的版本;
编译出的版本是向下兼容的,比如你设置值为YES,用iPhone4编译出来的是armv7版本的,iphone5也可以运行,但是armv6的设备就不能运行。
因此如果我们是做组件库的,无论是Debug还是Release,都应该适配不同的设备;
把代码拖入工程中,并编译通过;
配置需要公开的头文件;
在Build Phases找到Headers,展开后发现显示Public、Private、Project三个目录,默认文件都是在Project下,将需要公开的的头文件从Project中拖拽到Public目录下。
接下来就开始进行编译打包过程了
- 设置当前运行为Release环境,选中顶部菜单栏Product -> Scheme -> Edit Scheme,Run下设置Build Configuration为Release;
- 分别选中模拟器和真机(Generic iOS Device)进行编译;
- 两个都编译成功后,通过Products目录下的framework,右击Show in Finder,找到两个framework对应的目录(Release-iphoneos、Release-iphonesimulator);
- 将Release-iphoneos目录下的framework拷贝出来;(当前我拷贝在xxx/xxx/Framework目录下)
- 打开终端,使用“lipo -create 路径1 路径2 -output 目标路径”命令进行framework合并。
路径1:xxx/xxx/Release-iphoneos/xxx.framework/xxx
(例如:xxx/xxx/Release-iphoneos/SGUtils.framework/SGUtils)
路径2:xxx/xxx/Release-iphonesimulator/xxx.framework/xxx
(例如:xxx/xxx/Release-iphonesimulator/SGUtils.framework/SGUtils)
目标路径:xxx/xxx/xxx.framework/xxx
(例如:xxx/xxx/Framework/SGUtils.framework/SGUtils)
- 合并完成,“目标路径”就是合并后的framework。
接下来就是framework的发布了
podspec文件中需要配置framework路径,例如:
s.vendored_frameworks = 'xxx/xxx/SGUtils.framework'
私有库的发布请看iOS组件化实现
发布开源库其实也可以按照私有库发布的流程,将仓库开发成开源项目,最后发布的时候,使用以下命令进行发布。
pod trunk push --allow-warnings
发布成功后,就可以通过终端命令pod search进行搜索查看到开源库了。
例如:
pod search IJKMediaFramework
-> IJKMediaFramework (0.1.3)
ijkplayer framework.
pod 'IJKMediaFramework', '~> 0.1.3'
- Homepage: https://gitee.com/renzifeng/IJKMediaFramework
- Source: https://gitee.com/renzifeng/IJKMediaFramework.git
- Versions: 0.1.3, 0.1.2, 0.1.1, 0.1.0 [master repo]