CocoaPods组件化——OC/Swift动静态库混用
缘起
一个swift库,charts
。
项目本身是通过 cocoapods
进行组件化管理的。
在没有集成 charts
之前,一切都是那么的美好,天是晴的,雨是停的。
直到有一天,因为业务需要图表功能,经一番调研之后,选择了 charts
集成到工程之中。
然后噩梦就开始了。
直接集成跑项目会直接报上百个错,因为 charts
是用swift写的,错误简要如下:
|
|
当时没想太多(这就是过于依赖搜索了,连分析都没直接去搜),搜的如何的oc项目通过 pod 集成swift代码。
大概翻了几篇的意思是swift只能动态库打包,需要 pod 管理的库改成动态库,其实这都是老黄历了,都是 pod1.5 之前的方案,不过我当时还是无脑跟着这么做了。
其实在这时候里胜利只差一步,结果绕了一个大弯子。如果不想看我废话这么多的,可以直接转到结局去看。
use_frameworks!
在 Podfile
中加入 use_frameworks!
,就可以让 pod 管理的库都改成动态库。
加上之后,重新 pod install
一下。
然后项目一跑,果然不报错了,哎呦,牛逼,这就解决了。
心里美滋滋的,现在回头来看,还是太年轻了,直接把库都弄成动态库,后面还有成吨的依赖问题在等着我。。
就如下面的标题: 动静态库 pod 内部依赖静态lib,静态framewor,动态framework,都是坑!
动态库 Pod 中嵌入静态 lib
先说一下最先遇到的就是动态库 Pod 中嵌入静态lib。
vendored_library属性对应依赖的.a,然后依赖系统库在library,frameworks里加上。
最后就是.h,如果你不想暴露的话public_header_files里加完就不用管了,如果想要暴露给别人调用,只能source_files里再加一遍.h。
不想在source_files里再写一遍的也可以建个.h引用一遍所有.a的头文件,最后source_files写你自己的.h,但这只是保证我到处可以通过引用自己的头文件实现方法调用,并不能单个引用对应.a的头文件。
动态库 Pod 嵌入静态 Framework
对静态的Framework封装的时候可以说是最简单的了,vendored_frameworks加上去基本就万事大吉了,至于依赖啥系统库什么的跟上面一样。
动态库 Pod 嵌入动态 Framework
对于动态的Framework封装,是最恶心的,就算不用 pod 也是很麻烦的。
不用 pod 你要手动把这SDK拖到Embedded Binaries位置头文件才能引用,这个是苹果现在引用动态Framework的方法。
下面讲一下 pod 怎么搞,如果单纯framework做 pod,首先public_header_files要指定xxx.framework/Headers/{.h}不然头文件找不到。
其次source_files里看具体编译情况决定加不加xxx.framework/Headers/{.h},然后就是比较普通的地方vendored_frameworks指定好就完事了。
source_files这个加了的时候还有一个前提就是Framework内引用全是"“不能<>,所以大部分情况source_files不加。
另一种混合使用感觉这才是最常见的。
这时候不要指定Framework的public_header_files,写一个自己的头文件引用类,把想公开可以调用的写在在头文件引用类里如:#import <xxx.framework/xxx.h>
,间接把xxx.h暴露出来。
静态库 Pod 资源文件的调用
静态库其实还好,跟 pod 有关的resourced都在相应的 pod库名.bundle
之中。
只需要用下面方法,就可以取出bundle,然海找相应的资源。
|
|
动态库 Pod 资源文件的调用
每错,新坑出来了,动态 pod 中的静态framework,所依赖的资源图片找不到了。
打开ipa一看,路径全变了,pod 建动态库的时候的bundle都在相应的Framework里了。
大概路径就是:xxx.ipa/Frameworks/xxxpod.framework/xxxpod.bundle
真坑。。
所以获取bundle的方法改成下面的了。
|
|
关于动静之争
关于动态库和静态库的优劣网上一堆一堆的文章在说,这里就不废话了。
不过我个人倾向是用静态库的,事少,而且启动速度一些,说白了就是空间换时间。
安卓的art技术也是在空间换时间。
这年头空间哪有时间贵啊,手机容量再小,连这点都没有的那也不是我们的有效客户了。
结局
故事的答案是,我一开始以为swift不能打成静态库,所以导致的报错,其实并不是的。
当时报这个错是 Undefined symbols
错误,在后来把报错一搜,找到了 stackoverflow
上一个帖子。
大概意思就是这个OC的项目不知道要编译Swift的代码才报错,只需要在主工程中,建一个空的swift文件并自动建一个bridge,然后就可以了。
没错,智慧就是这么简单,而我绕了好大的一个弯。
彩蛋1:Xcode9swift静态库的支持
一开始查的结果其实就是过时的,早在Xcode9,swift就支持打成静态库了,所以不用非要弄成动态库。
彩蛋2: pod1.5 use_modular_headers!
随着支持swift静态库,pod1.5也更新的对应的功能,如果swift的 pod 依赖于某个OC的 pod,需要为该OC版 pod 启用modular headers
,所以多了 use_modular_headers!
来全局开启,不过开启之后,之前一些不严谨的依赖,可能会报错,需要具体情况具体分析了,网上相关的文章也很多,就不在这里一一赘述了。而且我也不建议这种跨语言的交叉依赖,比如我的项目主要是OC,依赖的swift版 pod,就是纯swift写的。
再来点废话
虽然是过去式了,但是之前用 use_frameworks!
的时候,发现会给每一个 pod 创建一个 umbrella.h
文件,而这个文件里会有 pod 里所有的.h,当然这个是可以通过 podspec 中的属性控制的。如果 pod 里有 cpp 之类的文件,各种引用问题就很烦人了,还得一点一点改。
这是去年建新项目的时候一点心路历程,只是大概记个印象了,有的细节也不是很清楚了,等后面再遇到或者想起来了,再补充把。
引用:
https://stackoverflow.com/questions/52536380why-linker-link-static-libraries-with-errors-ios https://cloud.tencent.com/developer/news/252403 https://www.jianshu.com/p/10ed66dae403 https://blog.csdn.net/ios8988/article/details/84111011 https://www.jianshu.com/p/544df88b6a1e https://www.jianshu.com/p/be9c848d050f https://www.jianshu.com/p/4be1ef1dc3ff https://www.jianshu.com/p/dfe9a1e1db7f https://www.jianshu.com/p/913df8cc1f18 https://www.jianshu.com/p/35db14a4931c https://zhuanlan.zhihu.com/p/50571342