组件化模块(四): 静态库的封装

当我们看好多第三方的插件的时候,会发现好多.a/.framework的静态库,之所以这些大厂这么做,其实是为了方便在集成完毕之后,快速的编译,最重要的是看不到自己的源码,并且保护我们的代码。并且在MRC阶段的代码,如果想要在ARC下使用,那么确实需要进行ARC兼容,但是我们进行编译之后,并不需要考虑这些问题,直接引用这个编译好的静态库就行,并不需要兼容ARC,确实好处多多。

首先讲解如何创建.a的二进制文件

1.创建一个静态库工程

创建静态库

2.由于不同的模拟器以及真机对应着不同的架构,

模拟器:4-5:i386   5s-iphoneX:x86-64

真机:3gs-4s: armv7(兼容7s)   5-5c: armv7s   5s-iphoneX:arm64

为了适配所有的CPU架构我们设置如下,Build Active Architecture Only  YES表示只编译某些比较主流的架构,所以要想都进行编译,我们需要对所有的都编译

注意如果你用的是比较新的xcode版本,比如xcode10,那么由于并没有自带比较老的模拟器,比如4/4s等,那么生成出来的静态库架构并不会包含i386或者armv7,如果想兼容4/4s等比较久的机型,需要下载老的模拟器版本

设置允许的架构类型

3.查看生成的.a文件架构架构

在终端中cd 到.a文件的父文件

输入命令 lipo  -info  静态库名称.a

输出当前所有支持的架构

架构类型

4.暴露.h 文件

暴露.h

5.默认生成的.a文件模拟器和真机是分开的,所以需要合成同时支持真机和模拟器的.a

lipo -create 模拟器中.a文件地址 真机中.a文件地址 -output  新的文件名.a

合成

6.生成realease版本的静态库(上面生成的是debug版本)

静态库

然后在项目中切换真机/模拟器,command+B,就会在.a文件的根目录发现release/debug、真机/模拟器版本信息

所有的.a文件

当我们应用.a文件的时候,只需要将import  .h文件进来就可以直接使用静态库文件里的方法了。

接下来我们用framework来生成静态库

.a文件是一个纯二进制文件,.frameWork中除了有二进制文件还有其他的资源文件;.a文件必须有.h文件配合使用,frameWork文件可以直接使用;framework静态库就类似一个文件夹,所有的子类文件都要放到framework中,包括可执行文件frameWork和.h以及资源文件。可以这么总结.a+.h+sourceFile(资源文件)=framework,所以相比.a文件来说,framework更加易于管理,所以本人更倾向与生成framework静态库

同样在新建工程中选择

生成

2.项目中添加一个工具类Tool,当Command+B编译之后,在framework中发现只有frameWork.h的头文件,并没有我们想要的Tool.h,所以我们需要对Tool.h暴露,将暴露到外界的.h文件放到public目录下,如果不用frameWork.h主头文件,可以将其删除

暴露.h

3.检查可执行文件支持的CPU架构

注意cd到.frameWork,然后检查目录下frameWork可执行文件中的架构,发现是x86_64,由于当前是在模拟器上进行的编译,所以我们需要兼容所有的模拟器/真机类型.

支持的种类

修改当前active Architecture Only的类型为No,表示所有的模拟器/真机架构都需要编译

编译架构

接下来我们需要在XCode中选择设备处设置为Generic ios Device,编译后的结构可以在项目中的Products->Framework.framework包中找到编译之后的结构,包含真机和模拟器两部分.

选择设备


4.适配所有的CPU架构(和上边生成.a文件一样)

5.生成release版本的.framework静态库,而不是debug版本的静态库注意:当前5到7步是生成了动态库,可以直接看7步中的原因,进行相应的步骤调整。这样写是为了更好的记录遇到的问题

6.合成适配模拟器和真机的静态库

注意合成的是静态库目录下的可执行文件(frameWork)的合并。

将地址拖过来就行

lipo -create 模拟器中可执行文件地址 真机中可执行文件地址 -output  新的文件名.framework

将生成的frameWork,替换掉之前release版本里的可执行文件,那么这个frameWork就可以用了。

7.修改frameWork(刚生成的时候其实为动态库)为静态库

查看文件


引用framWork

防止崩溃的发生,我们需要将frameWork动态库引用进Embedded Binaries

所以,当我们生成frameWork的时候就应该生成静态库。所以在生成frameWork工程中,

修改framework类型为静态库

将Dynamic Library修改为 Static Library。所以上边的第5到第7个步骤中我们需要重新进行生成。(删除工程中Library Framework和 Embedded Binaries 中的动态库文件)重新导入工程进行测试,发现不将framework引入Embedded Binaries,也是可以正常运行的,那么现在生成的是静态库了。

记录一些问题:

(1).图片资源的导入问题?(framework和.a图片的导入方式是一样的)

拿生成.a静态库举例,添加资源文件,将图片放入Tool.h同级目录下,编译,会发现我们编译后的包中,并没有我们的资源图片,我们需要将图片文件添加到BuildPhases->CopyFiles中+进来,才会放到我们编译后的文件中,包括三部分.a+.h+资源图片,那么这个时候会出现一个问题:

将我们编译好的.a+.h+资源文件作为一个静态库放入我们的主项目中,如果我们的主项目中已经有一个同名图片,然后对主项目进行编译后,发现包中只有一个同名的图片.

为了解决这个问题,我们将图片放到一个文件夹中,将这个文件夹放到和.a/.h同级目录下,当我们在主工程引用这个静态库的时候,需要将这个文件夹拖入主工程,但是我们用两个选择Create Group/Create folder references,由于我们将静态库导入到主工程,其实包括资源文件/.h/.a都已经编译好了,所以并不需要主工程对当前的资源文件做出引用,应该选择Create folder references,这样会将资源文件/.a/.h都加入到主工程的同级目录下,否则会发现资源文件不见了.

但是如果选择了Create Group,那么就会出问题,所以我们将资源文件放到bundle中进行存放(),bundle中的资源并不会因为这两个选项选错了就会把资源文件位置放错,一直会放到同级目录下.

(2).如果用户导入的头文件过多怎么办?

我们自己先建立一个主头文件,我们将所有的头文件都导入到主头文件中,我们直接import主头文件就行

(3).静态库如何测试?

.a文件如果交给主工程测试无法定位问题所在

所以定义一个复合工程,进行单元测试,在Targets中点击+号,选择Framework & Library 中的CocoaTouch Framework,新建一个Framework工程

添加Testframe复合工程

比如我们想要在A业务模块中调试代码,那么我们将A业务模块代码放到主工程中,调用我们想要编译成静态库的代码B,将B(以Tool类为例)

添加到Testframework中

在复合工程FrameworkTests中引入我们的静态库类,然后再主工程中调用Tool.h类进行测试,如果没问题,那么在Targets点中我们的复合工程Testframework,配置生成静态库的某些项,编译完之后,再Products中查找Testframework并查看包的内容,生成合并的release静态库.

(4).当我们将组建进行二进制化之后,那么导入方式将会改变,例如#import 'Tool.h'  #import <Framework/Tool.h>,如何避免多地方的改动?

我们可以将.h文件剥离出来,独立于framework之外,引用的时候直接调用#import 'Tool.h',实现的时候还是在framework中进行实现

(5).如何将生成的所有的架构文件删除某个架构,该如何操作?比如我们不需要支持i386

第一种:那么我们分别对其他的架构生成静态库,然后将静态库合并

第二种:直接在生成的静态库中移除某一个架构, cd到当前静态库的上一级,命令     

 lipo -remove i386 文件地址.a  -output  生成的名字.a

如果只要某一个架构的文件 比如arm64:

lipo -thin arm64 文件地址.a -output 生成名.a


接下来我们将framework放到远端仓库

以之前创建的一个WKDownLoad私有库为例首先创建一个Framework 项目WKDownloadLb,将WKDownLoad中的代码放到WKDownloadLb中,并暂时删除自带的WKDownloadLb.h文件,Xcode配置相应的生成framework的某些项,mach-o-Type/Build Active Architecture Only/run->release

生成的framwork项目

接下来,为了能够方便的查找我们生成framework位置,需要对xcode进行配置File->Project Settings

Project Settings
具体存放位置

将framework存放到相对于workspace的同级目录下的products文件下,开始进行编译,然后将framework进行合并,合并完之后,我们可以将WKDownloadLb.framework放到Products中,把iphoneos/iphonesimulator删掉

编译后的路径

接下来将原来的WKDownLoad中的podspec文件拷贝一份放到我们的WKDownloadLb项目中,用于进行pod时的查找,并修改podspec,包括库的名称/homepage/source/,在初始化coding.net一个项目的时候,不要设置git.ignore,将coding.net中的homepage/source分别放到podspec对应位置

为了外界不用改动引入我们.h文件的方式,我们做一层兼容,在framework外把所有的.h文件都加进来(真实情况是将所有.h文件都加都一个文件中,只引用某一个文件就行),在根目录下创建一个文件夹,把所有的.h文件都拷贝一份放到这里.

.h的header文件夹

修改source_files/s.vendored_frameworks,其中vendored_frameworks其实是指明我们framework的地址专门存在的,由于已经将framework放到了products中,所以地址更短了;source_files是除了framework之外的而外信息,就是我们的暴露header

framework/header设置

修改完之后,按照

git add .

git status

git commit -m '标记'

git remote

git remote add origin 地址

git push origin master

git tag -a 'tag值' -m '打标签'

git push --tags

pod lib lint   

(1)第一种错误

pod lib lint 第一种错误

发现好多小伙伴报这种错误,

解决方案:

pod repo push 私有spec xxxxxx.podspec --allow-warnings --skip-import-validationpod spec lint xxxxxx.podspec --skip-import-validation

参考地址

这个问题困扰了我很久,终于解决了,感谢小伙伴的贡献啊.

(2)第二种错误

pod lib lint 第二种错误

是由于tag没提交远端或者podspec中tag不一致导致的.


最终方案

我们现在远程仓库有一个原生代码组件和一个静态库组件,那么我们这样有一个弊端,需要改两个组件库才能将两个库中代码修改完毕,并且需要进行pod文件名称的修改,很不方便

能不能合并到一个里边那?答案是肯定滴

再原来pod lib create 创建的私有库demo中创建一个framework的复合工程

复合工程

将framework复合工程中的部分中引入对原来类的引用,注意只是引用,并不拷贝,这样就能保证修改的是一份代码.

引用

生成的framework复合工程部分,引用完之后代码结构

代码结构

为了生成静态库,需要在复合项目的build Setting工程目录下修改相应的配置,release/mach-o/build avtive/修改暴露外界的.h到Public中等,然后编译生成静态framework库,合并真机和模拟器的可执行文件,放到原来组件的Classes的同级目录下

products同级目录下

 接下来,修改podspec文件,并设置静态库暴露在外的头文件以及framework静态库

设置原来组件的podspec

修改暴露的source_files为暴露classes中的.h,添加引用的framework地址,这样就算设置完毕了.

接下来我们将修改后的组件上传到原来未二进制化时的私有库中

进行上传...

在其他地方调用本组件,会发现已经二进制化了😆,搞定

最终将上传到私有库的framework进行pod install,但是报了一个错误

pod install

发现是由于在pod file中打开了use_frameworks!,注掉就行

我们可以发现:这样并不需要添加一个新的pod依赖,并且通过pod update --no-repo-update就可以更新我们的远端私有库,又节省了远端私有库的资源

最后兼容源码和静态库两种类型

pod 中是可以设置环境变量的,比如 xxx pod install,xxx就是我们的环境变量

安装的时候 IS_SOURCE=1 pod install,就会把原生代码加进来了

兼容原生和二进制

注意的地方:

1.如果我们生成的是.a的静态库,并不是framework静态库,那么需要将s.vendored_framework换成s.vendored_libraries就行了

2.如果原来是framework,再IS_SOURCE=1 pod install到原生,那么会发现安装进来的私有库.m文件找不到了,这时需要先将之前的缓存清掉 pod cache clean --all,再将pods文件夹全部删除,这个时候再执行IS_SOURCE=1 pod install

3.如果我们的私有库都用这个环境变量控制,就能起到统一管理私有库源码或者二进制文件导入,但是这个时候有一个问题,如何只设置某一个为原生代码?其他都为二进制

可以给每一个私有库单独设置一个变量,表示当前私有库需要设置二进制 - WKDownload

单独设置为原生

执行WKDownload=1 pod install ,这样,私有库中的所有代码都设置为二进制形式,除了WKDownload为原生

4.私有库中有依赖,那么怎么处理

不应该包含依赖的xxx.a/framework文件

并且比如包含很多subspec,那么我们需要将所有的都放到一个framework中

快速生成framework

最后,为了方便,我们很多时候可以利用cocoapods-packager来快速完成framework打包,但是必须注意,我们需要将原来的源码已经用上传到托管平台,并且已加了tag。

1.安装package

安装

2.根据生成静态库

静态库生成

3.查看支持的类型

支持的类型

4.把不需要的类型删除

删除

根据路径下的库中的podspec文件,生成相对应的framework,并且支持所有的机型,个人比较倾向于这个工具。

包含subspec的静态库的封装

如果有framework里有依赖,那么我们不能用自动化的cocoapods packager打包framework框架里.

组合项目里创建target framework来进行静态库的封装,打包完之后其实是不包含我们的第三方依赖的,

我们的复合项目中想要用第三方的框架中的代码,那么需要将我们创建的target放入pod中,根据pod 文件的修改

pod 文件添加framework类

修改podspec  去掉之前色subspec,将所有的代码看成一个整体

修改podspec 文件里添加source_files/vendored_frameworks

去掉  库名称.dependency      '依赖库名称'

然后按照framwork的封装进行提交到私有库



欢迎关注我的公众号,专注iOS开发、大前端开发、跨平台技术分享。

iOS开发之家
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,835评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,598评论 1 295
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,569评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,159评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,533评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,710评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,923评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,674评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,421评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,622评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,115评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,428评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,114评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,097评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,875评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,753评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,649评论 2 271

推荐阅读更多精彩内容