美文网首页IOS知识积累iOS ReviewiOS知识库
iOS中的静态库与动态库,区别、制作和使用

iOS中的静态库与动态库,区别、制作和使用

作者: iOS_小松哥 | 来源:发表于2016-11-07 15:33 被阅读9782次

如果我们有些功能要给别人用,但是又不想公开代码实现,比如高德地图、第三方登录分享等等,这时候我们就要打包成库了。库分静态库和动态库两种:

静态库:以.a.framework为文件后缀名。
动态库:以.tbd(之前叫.dylib) 和 .framework 为文件后缀名。

静态库与动态库的区别

静态库:链接时会被完整的复制到可执行文件中,被多次使用就有多份拷贝。
动态库:链接时不复制,程序运行时由系统动态加载到内存,系统只加载一次,多个程序共用(如系统的UIKit.framework等),节省内存。

但是苹果不让使用自己的动态库,否则审核就无法通过。

我们先来看一下iOS设备有哪些架构,因为下面要用到:

模拟器:
iPhone4s-iPnone5:i386
iPhone5s-iPhone7 Plus:x86_64

真机:
iPhone3gs-iPhone4s:armv7
iPhone5-iPhone5c:armv7s
iPhone5s-iPhone7 Plus:arm64

支持armv7的静态库可以在armv7s上正常运行。

.a静态库的制作

1、先创建一个新的Xcode工程Test,需要选择下面这个模板:


选择模板

创建完成后是这个样子的:


创建工程

2、我们把默认生成的Test.h和Test.m删掉,重新创建一个类PrintString,在这个类里面添加一个单纯打印字符串的简单方法:


PrintString.h
PrintString.m

3、选择添加公开头文件
为了让使用者知道有哪些方法可以用,我们需要公开头文件,这里我们公开PrintString.h:


选择添加公开头文件

4、修改配置
我们需要把Build Active Architecture Only修改为NO,否则生成的静态库就只支持当前选择设备的架构。

修改配置

5、然后编译
我们分别选择Generic iOS Device任意一个模拟器各编译一次,编译完后,我们会看到工程中Products文件夹下的libTest.a由红色变成了黑色,然后show in finder,看看生成的文件:

Untitled.gif

我们看到它为真机和模拟器都生成了.a静态库。里面都包含我们选择公开的头文件。

我们来看看静态库支持的框架:命令为lipo -info 静态库名字

查看静态库支持的框架

我们看到,Debug-iphoneos里面的静态库支持的架构有armv7arm64所以它只能用于真机,在模拟器上会报错。Debug-iphonesimulator里面的静态库支持的架构有i386x86_64,所以它只能用于模拟器,在真机上会报错。

如果想要让模拟器和真机通用一个静态库,我们可以使用终端命令来实现。命令格式:lipo -create 第一个.a文件的绝对路径 第二个.a文件的绝对路径 -output 最终的.a文件路径:

生成通用静态库

我们看到生成了一个新的libTest.a文件。这个静态库就支持所有模拟器和所有真机了。然后我们创建一个文件夹,把.a和头文件都放进去,我们最终需要使用的就是这个文件夹:

新建文件夹

注意:为了开发方便,我们可以使用生成的通用静态库,但是最终上线的使用我们可以只导入真机的,这样工程的体积也会小一些。

使用生成的.a静态库

新建一个工程,将上面的通用静态库拖进去,导入头文件,就可以使用里面的方法了。经过试验,我们生成的静态库在真机上和模拟器上都能成功打印字符串:


Paste_Image.png
.frameworke静态库的制作

1、先创建一个新的Xcode工程LibTest,需要选择下面这个模板:


选择模板

创建完成后是这个样子的:


创建完成

创建完成后我们可以看到,工程本身自带一个LibTest.h文件和一个Info.plist文件。

2、我们创建一个类PrintString,添加一个单纯打印字符串的简单方法:

PrintString.h
PrintString

3、选择添加公开头文件
为了让使用者知道有哪些方法可以用,我们需要公开头文件,我们需要在 并且将Target->Build Phases->Headers中的Project中要暴露的头文件拖拽到Pulic里面,这里我们公开PrintString.h

选择添加公开头文件

注意:暴露出来的头文件中import的其他类也得添加到public中暴露出来。如果不想将import的类暴露出来,那么在头文件中用@class 然后在对应的.m文件中再import。

4、设置支持所有架构(和.a制作一样)
5、修改生成的Mach-O格式,因为动态库也可以是以framework形式存在,所以需要设置,否则默认打出来的是动态库。将target->BuildSetting->Mach-o Type 设为Static Library(默认为Dynamic Library):

修改生成的Mach-O格式

6、编译
我们分别选择Generic iOS Device任意一个模拟器各编译一次,编译完后,我们会看到工程中Products文件夹下的LibTest.framework由红色变成了黑色,然后show in finder,看看生成的文件:

编译

我们看到它为真机和模拟器都生成了LibTest.framework静态库。

我们来查看静态库支持的框架:与上面不同,命令为lipo -info framework下的二进制文件名字

查看静态库支持的框架

如果想要让模拟器和真机通用一个静态库,我们可以使用终端命令来实现。合并的命令与上面不同的是:framework静态库合并的不是framework,而是framework下的二进制文件,命令为:
lipo -create 第一个framework下二进制文件的绝对路径 第二个framework下二进制文件的绝对路径 -output 最终的二进制文件路径

合并二进制文件

然后将任何一个framework中的二进制文件替换成合并后的二进制文件,然后把framework添加到要使用的项目中即可使用。

使用生成的.framework静态库

新建一个工程,将静态库拖进去,导入头文件,就可以使用里面的方法了。经过试验,我们生成的静态库在真机上和模拟器上都能成功打印字符串:


Paste_Image.png

注意:
如果静态库中有category类,则在使用静态库的项目配置中Other Linker Flags需要添加参数-ObjC或者-all_load
如果创建的framework类中使用了.tbd,则需要在实际项目中导入.tbd动态库。

运行调试静态库

如果你是开发静态库的人,你会发现上面的方法只是制作静态库,并没有办法运行看效果和调试bug,这时候我们可以这样:
1、新建一个专门用来开发静态库的正常工程Test:


新建工程
建好的工程

2、添加一个静态库的target


添加一个静态库的target

我们看到它生成了几样东西:

一个framework的target:在这里面修改静态库的配置们,例如支持的架构、要暴露的头文件们和Mach-O的配置。
一个LibTest文件夹:静态库里面的类们都放在这里面。
product文件夹下面的LibTest.framework:在这里show in finder找到编译后生成的静态库。

3、开发调试代码


开发调试代码

我们看到程序可以正常运行,并可以在动态库里面蹲点运行。方便我们调试。

4、确保代码没问题后,选择对应的target编译生成。


编译生成

5、后面的过程就与上面一样了。

欢迎关注 和我的专题:iOS技术交流,查看更多好文章。

相关文章

网友评论

  • fc4d591c2216:每一篇文章都认真看了,很赞!
  • JoeTong:动态库装进ipa中 ios11闪退,有崩溃日志在 /var/mobile/Library/Logs/CrashReporter/WeChat-2018-06-30-111151.ips
    但是因为是非越狱看不到,请问下你有啥看法么
  • farawei:动态库的使用,有没有实现过:当需要的时候,通过网络下载到本地,再加载运行?就像插件
  • biny_ios:作者知道h5如何供别的APP调用吗。也能打包到静态库里面吗?如果这个H5里面调用的有别的静态库,还能再打包吗
  • 61de52728bec:你好 demo 可以发给我一份吗 非常感谢 QQ 674483879
  • Ko_Neko:如果导入的是动态库 也是用 #import吗?
  • 从小玩到大的青梅竹马:这个也好棒

    Mark
  • xiongcy:大神,我在用动态库引入动态库的时候有几十个警告,求帮忙
  • 87e5d66ef01c:楼主真屌,超级有用感谢!
    iOS_小松哥:@当我的发型更加翘啊 是缘是情是童真还是意外
  • 亦珩:松哥为什么没有动态库呀?
    chenyu1520:5、修改生成的Mach-O格式,因为动态库也可以是以framework形式存在,所以需要设置,否则默认打出来的是动态库。将target->BuildSetting->Mach-o Type 设为Static Library(默认为Dynamic Library):

    这里不是写的很清楚吗。其实在你项目传到 App Store 后,这个库并不能任意的修改,上传前已经做了签名,和静态库没有区别。但是比起.a 文件的好处是,可以使用这种方式做组件化。
  • b12bb14a0916:动态库的讲解呢?楼主
  • 小怡情ifelse:写的很清晰易懂 学习了
  • bec0fcc16d89:真心不错!
    iOS_小松哥:@给未来加油 :sunglasses:
  • 蜜锋将有小肚腩:松哥威武
    iOS_小松哥:@爱吹水的蜜蜂 是缘是情是童真还是意外
  • 浪流儿:又学到新知识了
    iOS_小松哥:@浪流儿 是缘是情是童真还是意外
  • hello_kity:学习了
    iOS_小松哥:@hello_kity 嘿嘿
  • GavinKang:大神,写的很详细,有空把图片和XIB打包进静态库就更好了
  • 小草先生:你好,我创建了个项目 直接把xcodeproj拖进 项目里面来 运行报错 Found an unexpected Mach-O header code:0x72613c21 sdk和demo Mach-O Type 都是 Static Library
  • R0b1n_L33:思路清晰 方案实用 :heart:
    iOS_小松哥:@ljysdfz 谢谢支持
  • f7139db11dcd:能不能加你qq ?
    iOS_小松哥:@HZW_sister 加群244122891 里面就有我
  • 贝壳小岛Official:苹果不让使用自己封装的动态库??没有吧。
    冰三尺:但是Swift不支持静态库, 只能使用动态库呀
    不留名的黄子嘉:@ChinaKingKong 现在是可以了 但是自己的动态库只能打包签名有效 和静态库没什么区别..
  • 谁是我我我:可以呀,小伙
    我是nil:@iOS_小松哥 有泪有罪有付出还有忍耐:joy:
    谁是我我我:@iOS_小松哥 哈哈:smile:
    iOS_小松哥:@谁是我我我 是缘是情是童真还是意外
  • BrightFuture:松哥,想请教个问题,多工程联编采用的是关联多个静态库实现,那么如果有业务需求需要在子工程中引入主工程的内容该怎么配置呢?

本文标题:iOS中的静态库与动态库,区别、制作和使用

本文链接:https://www.haomeiwen.com/subject/mqfiuttx.html