App打包-001-静态库(.a和.framework)和动态库的区别与制作,以及使用
引言
在开发中.framework静态库还是比较常见的,我们可以把一些不愿意让别人见到的代码,用静态库的方式把它隐藏起来,只留下.h文件显示方法供编程人员使用。而.a文件出了静态库本身外,还需要引入.h文件,而.framework就不需要如此,由于.framework的方便性所以一般情况下我们见到的较多。
库
库从本质上来说是一种可执行代码的二进制格式,可以被载入内存中执行。库分静态库和动态库两种。
静态库:以.a
和 .framework
为文件后缀名。
动态库:以.tbd
(之前叫.dylib
) 和 .framework
为文件后缀名。
静态库可以做什么:
1.定义基础的数据类
2.定义视图类
3.定义视图控制器类
静态库与动态库的区别
静态库和动态库是相对编译期和运行期的:
动态库:运行时获取
静态库:只读一次,编译时获取
//注意:苹果禁止一切未开源的代码在APP中使用,也就是说上传APP的时候,要将代码告知给苹果,审核通过之后才能上传使用,若苹果发现上传的APP中包含静态库或者动态库则会拒绝上架。
001-静态库.a 创建
1.新建工程
比如我们的工程名叫HKLibTest,那么我们创建的.a 静态库最好就是前面加个Lib,如:LibHKLibTest.a
新建工程 (选中xcode,按commond + shift + N)
此时工程目录是这个样子,.a文件还没有被创建,因此是红色的
你可以把图中 HKLibTest.h
和.m
换成你自己要生成库的文件(可以是多个),在这里我就不换了,就用这两个文件,我们在.h
文件中添加一个方法+sayHello
,并在.m
中实现它
#import "HKLibTest.h" @implementation HKLibTest + (void)sayHello { NSLog(@".a静态库:Hello, World ~"); } @end
2.添加Headers
按照下图顺序进行操作
Build Phases ->添加 -> New Run Script Phase
选中所有的.h文件,在点击Add
/* 这里需要注意的是暴露出来的头文件中import的其他类也得添加到public中暴露出来。 如果不想将import的类暴露出来,那么在头文件中用@class 然后在对应的.m文件中再import。 总之 1. 你再外面用到的类,一定要暴露出来; 2. 你暴露出来的类,头文件中导入的类也一定是暴露出来的 3. 如果提示导入头文件报错,找不到文件,找不到谁暴露谁就对了 */
3. 进行打包前的一些配置
设置编译模式,打开xcode菜单Product -> Scheme -> Edit Scheme,改成release模式,如下图
编译机器的选择,如下图,一定要选择NO。(如果选择yes,生成部分机型,选择NO则适配所有机型)
4. 接下来,我们进行打包
操作简述: Command + B
1. 在真机情况下编译 (Generic iOS Device),并记录下.a
文件的绝对路径
2. 在模拟机情况下编译(随便吧,我用的是iPhone8Plus),并记录下.a
文件绝对路径
3. 用命令行合并1、2部记录的文件,到新的.a
文件,名字最好取开始我们取的名字吧,命令行:lipo -create 真机静态库路径空格模拟器静态库路径 -output 最终文件路径(桌面)
4. 把你要暴露的.h
文件和你已经生成的.a
文件搞到一个文件夹里,这个文件夹就可以直接拖到工程里用啦
//真机静态库路径 /Users/MengYu/Library/Developer/Xcode/DerivedData/HKLibTest-cqiexexehimllgdmfaxigfagpzet/Build/Products/Release-iphoneos/libHKLibTest.a //模拟器静态库路径 /Users/MengYu/Library/Developer/Xcode/DerivedData/HKLibTest-cqiexexehimllgdmfaxigfagpzet/Build/Products/Release-iphonesimulator/libHKLibTest.a
合成:
//$lipo -create /Users/MengYu/Desktop/真机静态库/libHKLibTest.a /Users/MengYu/Desktop/模拟器静态库/libHKLibTest.a -output /Users/MengYu/Desktop/LibHKLibTest.a
在桌面就可以看到合成之后的.a文件了
把我们刚合成的.a文件和想暴露的.h文件,弄到一个文件夹下
静态库创建完成~
导入HKDemo工程中:
#import "ViewController.h" #import "HKLibTest.h" @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. [HKLibTest sayHello]; }
补充:
查看.a文件/.Framework是否正确:lipo -info
$lipo -info 真机模式下的.a文件路径
/Users/MengYu/Desktop/真机静态库/libHKLibTest.a is architecture: arm64 【真机】
//真机 armv7 arm64
$lipo -info 模拟器下的.a文件路径
/Users/MengYu/Desktop/模拟器静态库/libHKLibTest.a is architecture: x86_64 【模拟器】
//模拟器 i386 x86_64
.FrameWork :
模拟器:
//$lipo -info /Users/MengYu/Desktop/HKFrameWork.framework/HKFrameWork Architectures in the fat file: /Users/MengYu/Desktop/HKFrameWork.framework/HKFrameWork are: i386 x86_64
真机:
//$lipo -info /Users/MengYu/Desktop/HKFrameWork.framework/HKFrameWork Architectures in the fat file: /Users/MengYu/Desktop/HKFrameWork.framework/HKFrameWork are: armv7 armv7s i386 x86_64 arm64
/* 1.category是我们实际开发项目中经常用到的,把category打成静态库是没有问题的,但是在用这个静态库的工程中,调用category中的方法时会有找不到该方法的运行时错误(selector not recognized),解决办法是:在使用静态库的工程中配置other linker flags的值为-ObjC。 2.如果一个静态库很复杂,需要暴露的.h比较多的话,就可以在静态库的内部创建一个.h文件(一般这个.h文件的名字和静态库的名字相同),然后把所有需要暴露出来的.h文件都集中放在这个.h文件中,而那些原本需要暴露的.h都不需要再暴露了,只需要把.h暴露出来就可以了。 */
002-静态库.Framework创建
1.新建工程
这里我使用的是Xcode9,选择Cocoa Touch Framework,然后点next。
2、创建功能类或者拖入已有的功能类,并实现功能类的功能
3、更改Xcode项目配置
1> Architectures 修改 BuildingSettings 添加 armv7s
Build Active Architecture Only 设置为NO
2> Mach-O Type 设置为 Static Library
3> 添加Headers 同.a 静态库 (Build Phrases)
4>然后需要在HKFrameworkTest.h(必须是公开的,否则无法引用)中将你所有要公开的.h引入。
4、开始打包Framework
1>选择真机,点击Generic iOS Device Command + B 编译 ,获取真机Framework路径;
2>选择模拟器,点击iPhone8Plus Command + B 编译 ,获取模拟器Framework路径;
3>合成Framwork
lipo -create 真机版本路径 模拟器版本路径 -output 合并后的文件路径/名称
1.合并操作很容易出现问题,当提示这个错误时:
//error: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/lipo: can't move temporary file: /Users/xiong/Desktop/demo to file: /Users/xiong/Desktop/demo.lipo (Is a directory)
解决方法:
此错误一般是在合并后的路径没有加上合并后生成的文件名字,加上就行。
2.正确:
lipo -create /Users/MengYu/Library/Developer/Xcode/DerivedData/HKFrameWork-hfsogjyrorjfqchkyodzhhgyfwgs/Build/Products/Release-iphoneos/HKFrameWork.framework/HKFrameWork /Users/MengYu/Library/Developer/Xcode/DerivedData/HKFrameWork-hfsogjyrorjfqchkyodzhhgyfwgs/Build/Products/Release-iphonesimulator/HKFrameWork.framework/HKFrameWork -output /Users/MengYu/Library/Developer/Xcode/DerivedData/HKFrameWork-hfsogjyrorjfqchkyodzhhgyfwgs/Build/Products/HKFrameWork
如图所示:
5、将此Framework导入HKDemo工程中:
Command +B 编译一下,即可使用我们定义好的 kSCREENWIDTH
终端版:
//补充
/* lipo -info [文件名称] :显示静态库文件的架构类型 iphone用lipo合并模拟器库和真机库,发布一个通用的静态库 lipo -create [文件名称1,文件名称2,.......,文件名称n] -output [生成的文件名称] //静态库中是不能包含资源文件的!!!(图片,xib,音频等) 需要资源文件的时候,生成file.bundle。 */
一、什么是库? 库是共享程序代码的方式,一般分为静态库和动态库。 二、静态库与动态库的区别? 静态库:链接时完整地拷贝至可执行文件中,被多次使用就有多份冗余拷贝。 动态库:链接时不复制,程序运行时由系统动态加载到内存,供程序调用,系统只加载一次,多个程序共用,节省内存。 三、iOS里静态库形式? .a和.framework 四、iOS里动态库形式? .dylib和.framework 五、framework为什么既是静态库又是动态库? 系统的.framework是动态库,我们自己建立的.framework是静态库。 六、a与.framework有什么区别? .a是一个纯二进制文件,.framework中除了有二进制文件之外还有资源文件。 .a文件不能直接使用,至少要有.h文件配合,.framework文件可以直接使用。 .a + .h + sourceFile = .framework。 建议用.framework. 七、为什么要使用静态库? 方便共享代码,便于合理使用。 实现iOS程序的模块化。可以把固定的业务模块化成静态库。 和别人分享你的代码库,但不想让别人看到你代码的实现。 开发第三方sdk的需要。 八、制作静态库时的几点注意: 1 注意理解:无论是.a静态库还.framework静态库,我们需要的都是二进制文件+.h+其它资源文件的形式,不同的是,.a本身就是二进制文件,需要我们自己配上.h和其它文件才能使用,而.framework本身已经包含了.h和其它文件,可以直接使用。 2 图片资源的处理:两种静态库,一般都是把图片文件单独的放在一个.bundle文件中,一般.bundle的名字和.a或.framework的名字相同。.bundle文件很好弄,新建一个文件夹,把它改名为.bundle就可以了,右键,显示包内容可以向其中添加图片资源。 3 category是我们实际开发项目中经常用到的,把category打成静态库是没有问题的,但是在用这个静态库的工程中,调用category中的方法时会有找不到该方法的运行时错误(selector not recognized),解决办法是:在使用静态库的工程中配置other linker flags的值为-ObjC。 4 如果一个静态库很复杂,需要暴露的.h比较多的话,就可以在静态库的内部创建一个.h文件(一般这个.h文件的名字和静态库的名字相同),然后把所有需要暴露出来的.h文件都集中放在这个.h文件中,而那些原本需要暴露的.h都不需要再暴露了,只需要把.h暴露出来就可以了。
常见问题:
1.iOS导入动态库提示Reason:image not found
https://www.jianshu.com/p/bed94ddacfa8
2.ios自定义Framework 报错 Could not build module
https://blog.csdn.net/fushi007/article/details/79420675