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

jw789520 7年前
   <p>如果我们有些功能要给别人用,但是又不想公开代码实现,比如高德地图、第三方登录分享等等,这时候我们就要打包成库了。库分静态库和动态库两种:</p>    <p>静态库:以 .a 和 .framework 为文件后缀名。</p>    <p>动态库:以 .tbd (之前叫 .dylib ) 和 .framework 为文件后缀名。</p>    <h3><strong>静态库与动态库的区别</strong></h3>    <p>静态库:链接时会被完整的复制到可执行文件中,被多次使用就有多份拷贝。</p>    <p>动态库:链接时不复制,程序运行时由系统动态加载到内存,系统只加载一次,多个程序共用(如系统的 UIKit.framework 等),节省内存。</p>    <p>但是苹果不让使用自己的动态库,否则审核就无法通过。</p>    <p>我们先来看一下iOS设备有哪些架构,因为下面要用到:</p>    <p>模拟器:</p>    <p>iPhone4s-iPnone5:i386</p>    <p>iPhone5s-iPhone7 Plus:x86_64</p>    <p>真机:</p>    <p>iPhone3gs-iPhone4s:armv7</p>    <p>iPhone5-iPhone5c:armv7s</p>    <p>iPhone5s-iPhone6s:Plus:arm64</p>    <p>支持armv7的静态库可以在armv7s上正常运行。</p>    <h3><strong>.a静态库的制作</strong></h3>    <p>1、先创建一个新的Xcode工程Test,需要选择下面这个模板:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/8840785d1fbec1cbbdd1deb87191044a.png"></p>    <p style="text-align:center">选择模板</p>    <p>创建完成后是这个样子的:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/56087572c09da69796d5ef671803b51b.png"></p>    <p style="text-align:center">创建工程</p>    <p>2、我们把默认生成的Test.h和Test.m删掉,重新创建一个类PrintString,在这个类里面添加一个单纯打印字符串的简单方法:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/e3b45d6d25b02b934e6b9ea10ae59c6a.png"></p>    <p style="text-align:center">PrintString.h</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/7282e3f42adaf0adc481e6edb6f33a79.png"></p>    <p style="text-align:center">PrintString.m</p>    <p>3、选择添加公开头文件</p>    <p>为了让使用者知道有哪些方法可以用,我们需要公开头文件,这里我们公开PrintString.h:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/914660e5988739b9b95134d9748c1038.gif"></p>    <p style="text-align:center">选择添加公开头文件</p>    <p>4、修改配置</p>    <p>我们需要把 Build Active Architecture Only 修改为NO,否则生成的静态库就只支持当前选择设备的架构。</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/685d801082c19fd6632d8d5e5f10fb77.gif"></p>    <p style="text-align:center">修改配置</p>    <p>5、然后编译</p>    <p>我们分别选择 Generic iOS Device 和 任意一个模拟器 各编译一次,编译完后,我们会看到工程中Products文件夹下的libTest.a由红色变成了黑色,然后 show in finder ,看看生成的文件:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/2bd4e1a020ee3d217999efb895f900bd.gif"></p>    <p style="text-align:center">Untitled.gif</p>    <p>我们看到它为真机和模拟器都生成了.a静态库。里面都包含我们选择公开的头文件。</p>    <p>我们来看看静态库支持的框架:命令为 lipo -info 静态库名字</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/315e436fcae1b83117fd6b0f018b2414.gif"></p>    <p style="text-align:center">查看静态库支持的框架</p>    <p>我们看到, Debug-iphoneos 里面的静态库支持的架构有 armv7 和 arm64 所以它只能用于真机,在模拟器上会报错。 Debug-iphonesimulator 里面的静态库支持的架构有 i386 和 x86_64 ,所以它只能用于模拟器,在真机上会报错。</p>    <p>如果想要让模拟器和真机通用一个静态库,我们可以使用终端命令来实现。命令格式: lipo -create 第一个.a文件的绝对路径 第二个.a文件的绝对路径 -output 最终的.a文件路径 :</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/09220e5ef6e8346c9ffc41b02b1e351f.gif"></p>    <p style="text-align:center">生成通用静态库</p>    <p>我们看到生成了一个新的 libTest.a 文件。这个静态库就支持所有模拟器和所有真机了。然后我们创建一个文件夹,把.a和头文件都放进去,我们最终需要使用的就是这个文件夹:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/247be2c54fe80a97ae0fc2b3a5912098.gif"></p>    <p style="text-align:center">新建文件夹</p>    <p>注意:为了开发方便,我们可以使用生成的通用静态库,但是最终上线的使用我们可以只导入真机的,这样工程的体积也会小一些。</p>    <h3><strong>使用生成的.a静态库</strong></h3>    <p>新建一个工程,将上面的通用静态库拖进去,导入头文件,就可以使用里面的方法了。经过试验,我们生成的静态库在真机上和模拟器上都能成功打印字符串:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/0ed7690b185a7d9ddbb853ea23945afd.png"></p>    <p style="text-align:center">Paste_Image.png</p>    <p>.frameworke静态库的制作</p>    <p>1、先创建一个新的Xcode工程LibTest,需要选择下面这个模板:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/8b3bd1afbf076c65cea930bcbf89927f.png"></p>    <p style="text-align:center">选择模板</p>    <p>创建完成后是这个样子的:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/888b2ebab3a495afff72e8ece289be1f.png"></p>    <p style="text-align:center">创建完成</p>    <p>创建完成后我们可以看到,工程本身自带一个 LibTest.h 文件和一个 Info.plist 文件。</p>    <p>2、我们创建一个类 PrintString ,添加一个单纯打印字符串的简单方法:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/90b87c49ba753c92f32a79ba842aa356.png"></p>    <p style="text-align:center">PrintString.h</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/fb34c645b841d27b111609c091ccea24.png"></p>    <p style="text-align:center">PrintString</p>    <p>3、选择添加公开头文件</p>    <p>为了让使用者知道有哪些方法可以用,我们需要公开头文件,我们需要在 并且将 Target->Build Phases->Headers 中的 Projec t中要暴露的头文件拖拽到 Pulic 里面,这里我们公开 PrintString.h :</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/beba11169c25f8f8dfb52a051077f119.gif"></p>    <p style="text-align:center">选择添加公开头文件</p>    <p>注意:暴露出来的头文件中import的其他类也得添加到public中暴露出来。如果不想将import的类暴露出来,那么在头文件中用@class 然后在对应的.m文件中再import。</p>    <p>4、设置支持所有架构(和.a制作一样)</p>    <p>5、修改生成的 Mach-O 格式,因为动态库也可以是以framework形式存在,所以需要设置,否则默认打出来的是动态库。将 target->BuildSetting->Mach-o Type 设为 Static Library (默认为 Dynamic Library ):</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/270efbb624f1b32a74ce0e69138c6599.png"></p>    <p style="text-align:center">修改生成的Mach-O格式</p>    <p>6、编译</p>    <p>我们分别选择 Generic iOS Device 和 任意一个模拟器 各编译一次,编译完后,我们会看到工程中Products文件夹下的LibTest.framework由红色变成了黑色,然后 show in finder ,看看生成的文件:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/dea2e0c4c7133efea579b89cccd11708.gif"></p>    <p style="text-align:center">编译</p>    <p>我们看到它为真机和模拟器都生成了LibTest.framework静态库。</p>    <p>我们来查看静态库支持的框架:与上面不同,命令为 lipo -info framework下的二进制文件名字</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/3d8f4558e835eeb2890152db66d5408a.gif"></p>    <p style="text-align:center">查看静态库支持的框架</p>    <p>如果想要让模拟器和真机通用一个静态库,我们可以使用终端命令来实现。合并的命令与上面不同的是:framework静态库合并的不是framework,而是framework下的二进制文件,命令为:</p>    <p>lipo -create 第一个framework下二进制文件的绝对路径 第二个framework下二进制文件的绝对路径 -output 最终的二进制文件路径 :</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/95398cd7a11c7a52aa74f29922060629.gif"></p>    <p style="text-align:center">合并二进制文件</p>    <p>然后将任何一个framework中的二进制文件替换成合并后的二进制文件,然后把framework添加到要使用的项目中即可使用。</p>    <h3><strong>使用生成的.framework静态库</strong></h3>    <p>新建一个工程,将静态库拖进去,导入头文件,就可以使用里面的方法了。经过试验,我们生成的静态库在真机上和模拟器上都能成功打印字符串:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/b24b3970193fe14bdc4dbdd1e4e2493d.png"></p>    <p style="text-align:center">Paste_Image.png</p>    <p>注意:</p>    <p>如果静态库中有category类,则在使用静态库的项目配置中 Other Linker Flags 需要添加参数 -ObjC 或者 -all_load 。</p>    <p>如果创建的framework类中使用了 .tbd ,则需要在实际项目中导入 .tbd 动态库。</p>    <h3><strong>运行调试静态库</strong></h3>    <p>如果你是开发静态库的人,你会发现上面的方法只是制作静态库,并没有办法运行看效果和调试bug,这时候我们可以这样:</p>    <p>1、新建一个专门用来开发静态库的正常工程Test:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/fda8e5716f8b715a793d7ba8211c5f51.png"></p>    <p style="text-align:center">新建工程</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/79632de1f2e3390794eeab22ba53eaf9.png"></p>    <p style="text-align:center">建好的工程</p>    <p>2、添加一个静态库的target</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/b4769960fcf3966625e5a4497d8c417e.gif"></p>    <p style="text-align:center">添加一个静态库的target</p>    <p>我们看到它生成了几样东西:</p>    <p>一个framework的target:在这里面修改静态库的配置们,例如支持的架构、要暴露的头文件们和Mach-O的配置。</p>    <p>一个LibTest文件夹:静态库里面的类们都放在这里面。</p>    <p>product文件夹下面的LibTest.framework:在这里show in finder找到编译后生成的静态库。</p>    <p>3、开发调试代码</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/9d8f1b0a230359f79cb5f951968cef5a.gif"></p>    <p style="text-align:center">开发调试代码</p>    <p>我们看到程序可以正常运行,并可以在动态库里面蹲点运行。方便我们调试。</p>    <p>4、确保代码没问题后,选择对应的target编译生成。</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/6716059fa4d3268cced6e05d10360591.gif"></p>    <p style="text-align:center">编译生成</p>    <p>5、后面的过程就与上面一样了。</p>    <p> </p>    <p>来自:http://ios.jobbole.com/90470/</p>    <p> </p>