iOS 静态库.framework的制作

一、概念:

1)、什么是库?

库是共享程序代码的方式,一般分为静态库和动态库。

2)、静态库与动态库的区别?

静态库:链接时完整地拷贝至可执行文件中,被多次使用就有多份冗余拷贝。

动态库:链接时不复制,程序运行时由系统动态加载到内存,供程序调用,系统只加载一次,多个程序共用,节省内存。

3)、iOS里静态库形式?

.a和.framework

4)、iOS里动态库形式?

.dylib和.framework

5)、framework为什么既是静态库又是动态库?

系统的.framework是动态库,我们自己建立的.framework是静态库。

6)、a与.framework有什么区别?

.a是一个纯二进制文件,.framework中除了有二进制文件之外还有资源文件。

.a文件不能直接使用,至少要有.h文件配合,.framework文件可以直接使用。

.a + .h + sourceFile = .framework。

建议用.framework.

7)、为什么要使用静态库?

方便共享代码,便于合理使用。

实现iOS程序的模块化。可以把固定的业务模块化成静态库。

和别人分享你的代码库,但不想让别人看到你代码的实现。

开发第三方sdk的需要。

8)、制作静态库时的几点注意:

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暴露出来就可以了。

二、目标

本文将基于Xcode9制作一个framework,并简单使用

三、步骤

1、打开Xcode,新建工程。

不要选择“Application”,选择“Framework & Library”中的“Cocoa Touch Framework”,然后Next。

2、创建功能类。

这里我创建一个继承自NSObject的TestMethod类

3、实现功能。

在新创建的类里面声明方法并实现。这里我写一个sayHello的方法,以便后面测试使用。

//
//  TestMethod.h
//  testFramework
//
//  Created by 毕杰涛 on 2018/7/20.
//  Copyright © 2018年 fanneng. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface TestMethod : NSObject

/**
 Framework测试方法
 */
- (void)printContent;
@end
//
//  TestMethod.m
//  testFramework
//
//  Created by 毕杰涛 on 2018/7/20.
//  Copyright © 2018年 fanneng. All rights reserved.
//

#import "TestMethod.h"

@implementation TestMethod
- (void)printContent {
    NSLog(@"行号=%d 函数名=%s",__LINE__,__func__);
}
@end

4、更改参数

在TARGETS下选中工程,在Build Settings下更改几个参数。

5、增加armv7s

  在Architectures下增加armv7s,并选中。将Build Active Architecture Only 设置为NO。

6、设置Headers

将你要公开的头文件拖至Public下,要隐藏的放在Private或者Project下,当然,隐藏的头文件就无法再被引用。

然后需要在testFramework.h(必须是公开的,否则无法引用)中将你所有要公开的.h引入。

7、设置支持bitcode 

  在Other c flags下增加-fembed-bitcode

8、打包Framework

1)选中模拟器,编译程序,单独出模拟器的

2)选中测试机,编译程序,单独出真机的

3)在finder中找到framework文件

4)将两个framework合为一个模拟器和真机都可使用的framework。

嵌入脚本。选中target,然后选中右侧的Build Phases,点击左下方加号,选择New Run Script Phase,在Run Script 添加下面的脚本

脚本内容,直接复制

if [ "${ACTION}" = "build" ]
then
INSTALL_DIR=${SRCROOT}/Products/${PROJECT_NAME}.framework
DEVICE_DIR=${BUILD_ROOT}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework
SIMULATOR_DIR=${BUILD_ROOT}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework
if [ -d "${INSTALL_DIR}" ]
then
rm -rf "${INSTALL_DIR}"
fi
mkdir -p "${INSTALL_DIR}"
cp -R "${DEVICE_DIR}/" "${INSTALL_DIR}/"
#ditto "${DEVICE_DIR}/Headers" "${INSTALL_DIR}/Headers"
lipo -create "${DEVICE_DIR}/${PROJECT_NAME}" "${SIMULATOR_DIR}/${PROJECT_NAME}" -output "${INSTALL_DIR}/${PROJECT_NAME}"
#open "${DEVICE_DIR}"
open "${SRCROOT}/Products"
fi

通过第一种方法中“把真机和模拟器的frameworkTest合并成一个”的过程和上边的脚本语言比较,我们可以发现其实两者异路同归,两个方法里面同时用到了“lipo -create  xxx”和“-output xxx”,不同的地方是第一种方法需要我们自己真机和模拟器分别变异一遍,而且需要我们把framework的路径拖进去,相比而言第二种方法比较简单。

9、监测Framework支持的平台

1)终端输入 lipo -info 路径/名字 ,分别监测模拟器,真机及合并的

需要先跑模拟器,再跑合并的,否则报错

bijietaodeMacBook-Pro:desktop bijietao$ lipo -info /Users/bijietao/Desktop/testFramework.framework/testFramework

Architectures in the fat file: /Users/bijietao/Desktop/testFramework.framework/testFramework are: i386 x86_64 
bijietaodeMacBook-Pro:desktop bijietao$ lipo -info /Users/bijietao/Desktop/testFramework.framework/testFramework

Architectures in the fat file: /Users/bijietao/Desktop/testFramework.framework/testFramework are: armv7 armv7s i386 x86_64 arm64 
bijietaodeMacBook-Pro:desktop bijietao$ lipo -info /Users/bijietao/Desktop/testFramework.framework/testFramework

Architectures in the fat file: /Users/bijietao/Desktop/testFramework.framework/testFramework are: armv7 armv7s i386 x86_64 arm64 

10、监测代码引用

最后就是用我们的Framework了,倒入另一个Xcode中,我们打开这个framework看看,发现只有Headers,里面有两个.h,其中一个是我们之前添加的testFrameworkh文件,另一个就是我们的TestMethod.h 。

四、总结

1、.h文件的外漏一定要保证是自己的想要外漏的。不想外漏的就别外漏了。

2、开始打包的时候,一定要在选中模拟器和选中真机上边分别编译一次, 我觉得之前在家里没有真机的时候编译的好像不对。

3、在终端上边合并的时候可能是error并生成一个.lipo文件,不要怕,大胆修改成同名的不挂后缀的同名文件。

4、调用的时候分清楚是类方法还是实例方法,方便调用。

5、在制作framework或者lib的时候,如果使用了category,则使用改FMWK的程序运行时会crash,此时需要在该工程中 other linker flags添加两个参数 -ObjC -all_load。(这点没有亲测)

6、带有图片资源的需要把图片打包成Bundle文件,和framework一起拷贝到相应的项目中。

7、公开的类中如果引用的private的类,打包以后对外会报错,找不到那个private的类,可以把那个private的.h放到(也没亲测)

8、namespace 冲突。静态库用了某第三方库,项目也用了同样的第三方库,在编译的时候就会有 duplicate symbol 错误,因为有两份同样的第三方库。解决办法就是把用到的第三方库加上自定义前缀,包括类名、delegate 协议、常量名,尤其需要注意 Category 的方法名要修改。

9、封装静态库的时候应尽量避免引入重量级第三方库,多自己进行封装

10、一个静态库要有自己独有的前缀,所有类名、常量等都要加同样的前缀。

11、真机+模拟器支持。(和第2条意思一样)Xcode 默认只会用当前环境(真机或模拟器)生成静态库,这样的 SDK 不方便其他项目开发时调试。解决办法就是通过脚本生成一份通用库,build_universal_library.sh,via SO.

12、文档。静态库的方便是使用者直接拿你提供的方法来用,无需关注具体实现;不方便在于看不到实现,出现问题无法排查,因此需要把 SDK 的版本、更新历史、使用、FAQ 等写成文档,方便使用,也显得 SDK 比较正式规范。

13、图片等资源文件用 bundle 方式打包。一个简单制作 bundle 的方法:新建文件夹,重命名为 YourSDK.bundle,然后 Show Package Contents 打开,加入图片。使用图片的时候需要指明 bundle: [UIImage imageNamed:@"YourSDK.bundle/img.png"]。也可以用 Target 方式制作 bundle,比如 iOS Library With Resourceshttp://www.galloway.me.uk/tutorials/ios-library-with-resources/.

14、如果 SDK 有用到 Category,注意项目设置 Other Linker Flags 添加 -ObjC。(后边介绍了-ObjC的作用)

15、常用参数介绍:

-ObjC:加了这个参数后,链接器就会把静态库中所有的Objective-C类和分类都加载到最后的可执行文件中

-all_load:会让链接器把所有找到的目标文件都加载到可执行文件中,但是千万不要随便使用这个参数!假如你使用了不止一个静态库文件,然后又使用了这个参数,那么你很有可能会遇到ld: duplicate symbol错误,因为不同的库文件里面可能会有相同的目标文件,所以建议在遇到-ObjC失效的情况下使用-force_load参数。

-force_load:所做的事情跟-all_load其实是一样的,但是-force_load需要指定要进行全部加载的库文件的路径,这样的话,你就只是完全加载了一个库文件,不影响其余库文件的按需加载

猜你喜欢

转载自blog.csdn.net/TechAlleyBoy/article/details/81284635
今日推荐