为了提高项目中代码的复用,通常会把耦合度低的模块解耦出来做成Pod库放在私有仓库上,很多To B的业务,需要制作SDK给第三方使用,这时候需要提供静态framework给第三方。
静态库生成
模块说明书PodSpec
我们把podspec文件上传给cocoapod的master上,当别人配置好CocoaPods就会把我们的podspec.json下载到/.cocoapods/repos/master/下,用户要使用AFNetworking查找本地/.cocoapods/repos/master/ 找到这个AFNetworking.podspec.json文件根据内容下载配置。
podspec文件就是充当了一个我们源代码模块的说明书,告诉开发者我们模块名称,我们用途,可以在哪下载源代码 ,需要如何配置。
podspec创建
pod 还提供了一个一条龙服务的命令:pod lib create 会帮我们创建一个跟项目名称相同podspec文件 测试project 工程 测试框架。
1 | pod lib create XXXX |
podspec常用属性说明
1 |
|
模块说明书的验证
1 | pod spec lint test.podspec |
可以设置 –allow-warnings来忽略警告,通过–verbose查看错误具体信息
模块说明书注意
一个tag对应一个版本 都会包含一个podspec 文件
仓库Repo
存放说明书的地方就是仓库
创建自己cocoapod仓库的命令就是
1 | //REPO_NAME 仓库名称 |
推送podspec需要添加仓库名称和 podspec文件地址
1 | pod repo push RooboSpecs xxxxxx.podspec |
编译SDK静态库
如果需要隐藏源代码,可以把pod库编译成静态库的方式。
可以通过安装cocoapod的编译插件配合我们的cocoapod 文件来编译我们静态库文件 安装cocoapods-packager
1 | sudo gem install cocoapods-packager |
- 编译库文件
1 | //pod package NAME [SOURCE] |
- Pod Package命令含义
1 | //强制覆盖之前已经生成过的二进制库 |
注意:
使用–library编译出的.a静态库文件,pod package插件有问题的,根部不会生成头文件。所以只能编译framwork的库文件
静态库制作遇到的坑
运行时便无法找到对应的selector?
编译/链接过程
编译器在编译的过程中首先会将 .c/.cc/.cpp/.m/.mm 的源文件编译成后缀为 .o 的对象文件 ,源文件与对象文件是一一对应的,对象文件中包含了符号、代码以及数据,对象文件是不能被系统加载并使用的。当在编译生成静态库时,这些所有的对象文件,都会被封装到 .a(archive) 文件,可以理解为一个归档文件,也就是我们平常使用的静态库。
当需要生产二进制文件或是动态库时,编译器会对静态库 .a(archive) 文件进行处理;编译器将获取静态库中所有的符号表,并检查哪些符号被引用,只有被引用的对象文件才会被链接器真正的加载并处理。例如在静态库中有 10 个对象文件,但被引用到只有 2 个,则链接器只加载被引用的 2 个对象文件,未被使用到的 8 个对象文件则会被忽略。
在 C/C++ 语言中,这种机制可以很好的工作,因为 C/C++ 语言会尽可能的在编译期去做这些事。在 Objective-C 语言中非常依赖运行时特性,Category 就是基于运行时实现,但它并不会像类或者函数一样被创建链接符号,编译器在检查符号表时便不能检查到 Category 对应的符号表,从而 Category 的对象文件就不能被正常的加载,在运行时便无法找到对应的 selector 。
解决方案
- Other Linker Flags 添加
-all_load 告诉编译器 对于所有静态库中的所有对象文件,不管里面的符号有没有被用到,全部都载入,这种方法可以解决问题,但是会产生比较大的二进制文件
-force_load 并指定路径,-force_load $(BUILT_PRODUCTS_DIR)/<library_name.a> 这种方法和 -all_load 类似,不同的是它只载入指定的静态库
-ObjC 如果在静态库的对象文件中发现了 Objective-C 代码,就把它载入,Category 中肯定会存在 Objective-C 代码。
- 在 Category 的源文件里添加 Fake symbol,并确保以某种方法在编译时引用了该 Fake symbol,这会使得 Fake symbol 对象文件被加载时它里面 Category 代码也会被载入。该方法可以控制哪些 Category 可以被正常加载,同时也不需要添加编译参数做特殊处理。