Fork me on GitHub

Framework和Library的制作流程和注意事项

FrameworkVSLibrary

 静态库、动态库和Framework的区别?

所谓库就是二进制文件,加上头文件和相关的资源文件就可以提供给别人使用了。

  • 静态库:(静态链接库,也叫.a)在编译时会将库copy一份到目标程序中,编译完成之后,目标程序不依赖外部的库,也可以运行,但是缺点就是会使应用程序变大。
  • 动态库:(.dylib)编译时只存储指向动态库的引用。可以多个程序指向这个库,在运行时才加载,不会使体积变大,但是运行时加载会损耗部分性能,并且依赖外部的环境,如果库不存在或者版本不正确则无法运行
  • Framework:实际上是一种打包方式,将库的二进制文件,头文件和有关的资源文件打包到一起,方便管理和分发。

 Framework制作流程

未完待续

 Library的制作流程

未完待续

 Framework和Library的嵌套使用

我们接下来讨论以下几种情况

  • StaticFramework中嵌套StaticFramework
  • StaticFramework中嵌套使用StaticLibrary
  • StaticLibrary中嵌套StaticLibrary
  • DynamicFramework中嵌套使用StaticLibrary
  • DynamicFramework中嵌套使用StaticFramework
  • DynamicFramework中嵌套使用DynamicFramework


 StaticFramework中嵌套StaticFramework

  • 创建一个叫做StaticFrameworkOne的Framework的静态库(Static Library),并且内部创建一个StaticFrameworkOneTest的类,并声明staticFrameworkOneTestMethod方法,内部实现如下:
1
2
3
4
5
6
7
8
9
10
#import "StaticFrameworkOneTest.h"

@implementation StaticFrameworkOneTest

- (void)staticFrameworkOneTestMehtod
{
NSLog(@"%s",__func__);
}

@end
  • 同样我们在用同样的方法创建一个名为StaticFrameworkTwo的Framework静态库(Static Library),并创建一个StaticFrameworkTwoTest类,声明一个StaticFrameworkTwoTestMethod方法,并在StaticFrameworkTwoTest内部引用了StaticFrameworkOne,并且调用了StaticFrameworkOneTestMethod方法,内部实现如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#import "StaticFrameworkTwoTest.h"
#import <StaticFrameworkOne/StaticFrameworkOneTest.h>

@implementation StaticFrameworkTwoTest

- (void)staticFrameworkTwoTestMehtod
{
NSLog(@"%s",__func__);

StaticFrameworkOneTest *one = [[StaticFrameworkOneTest alloc] init];
[one staticFrameworkOneTestMehtod];

}

@end
  • 将编译生成好的StaticFrameworkTwo Framework导入项目中,并调用其staticFrameworkTwoTestMethod方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#import "ViewController.h"
#import <StaticFrameworkTwo/StaticFrameworkTwo.h>

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
[super viewDidLoad];

StaticFrameworkTwoTest *two = [[StaticFrameworkTwoTest alloc] init];
[two staticFrameworkTwoTestMehtod];

}

@end

  当我们command + B 编译的时候发现报错了,提示

  • 我们在Demo工程加入StaticFrameworkOneFramework,再次run工程不再报错,并输出
1
2
2019-05-27 17:23:11.860204+0800 FrameWork制作[8562:334159] -[StaticFrameworkTwoTest staticFrameworkTwoTestMehtod]
2019-05-27 17:23:11.860304+0800 FrameWork制作[8562:334159] -[StaticFrameworkOneTest staticFrameworkOneTestMehtod]

  总结:StaticFramework中嵌套使用其他StaticFramework,不会包含内部嵌套的StaticFramwework,只能link其内部的StaticFramework

  使用场景:自己的Framework中包含了其他业务也使用的库,为避免最终工程符号冲突或者避免工程多个库文件,采取这种嵌套方式比较合适

 StaticFramework中嵌套StaticLibrary

  • 创建一个叫做StaticLibraryOne的StaticLibrary,并声明方法staticLibraryOneMethod,内部实现如下:
1
2
3
4
5
6
7
8
9
10
#import "StaticLibraryOne.h"

@implementation StaticLibraryOne

- (void)staticLibraryOneMethod
{
NSLog(@"%s",__func__);
}

@end
  • 将编译好的libStaticLibraryOne.a加入StaticFrameworkOne中,并调用其方法,StaticFrameworkOneTest内部实现如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#import "StaticFrameworkOneTest.h"
#import "StaticLibraryOne.h"

@implementation StaticFrameworkOneTest

- (void)staticFrameworkOneTestMethod
{
NSLog(@"%s",__func__);

StaticLibraryOne *libraryOne = [[StaticLibraryOne alloc] init];
[libraryOne staticLibraryOneMethod];
}

@end
  • 编译StaticFrameworkOne,并将其framework加入测试工程中,并调用其方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#import "ViewController.h"
#import <StaticFrameworkOne/StaticFrameworkOne.h>

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
[super viewDidLoad];

StaticFrameworkOneTest *one = [[StaticFrameworkOneTest alloc] init];
[one staticFrameworkOneTestMethod];
}


@end
  • 运行测试主工程,输入如下:
1
2
2019-05-27 20:08:44.157571+0800 Framework测试主工程[11412:542791] -[StaticFrameworkOneTest staticFrameworkOneTestMethod]
2019-05-27 20:08:44.157677+0800 Framework测试主工程[11412:542791] -[StaticLibraryOne staticLibraryOneMethod]

  总结: StaticFramework中嵌套使用StaticLibrary,会将StaticLibrary中的内容全部link到Framework中,外部使用StaticFramwork时,无需在单独link内部staticLibrary

  使用场景: 对外提供一个完成的模块时,使用这种嵌套的方式,但是需要注意,内部嵌套使用StaticLibrary时,最好做了类名方法名全部变量等名称的修改,避免冲突

 StaticLibrary中嵌套StaticLibrary

  • 创建一个StaticLibraryOne的静态库StaticLibrary,并实现其方法:

1
2
3
4
5
6
7
8
9
10
#import "StaticLibraryOne.h"

@implementation StaticLibraryOne

- (void)staticLibraryOneTestMethod
{
NSLog(@"%s",__func__);
}

@end
  • 创建一个StaticLibraryTwo的静态库StaticLibrary,并导入StaticLibraryOne,实现其方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#import "StaticLibraryTwo.h"
#import "StaticLibraryOne.h"

@implementation StaticLibraryTwo

- (void)staticLibraryTwoTestMethod
{
NSLog(@"%s",__func__);

StaticLibraryOne *one = [[StaticLibraryOne alloc] init];
[one staticLibraryOneTestMethod];
}

@end
  • 编译StaticLibraryTwo,并将其导入测试工程,并调用其方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#import "ViewController.h"
#import "StaticLibraryTwo.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
[super viewDidLoad];

StaticLibraryTwo *two = [[StaticLibraryTwo alloc] init];
[two staticLibraryTwoTestMethod];
}
@end
  • 运行测试主工程,输入如下:
1
2
2019-05-27 20:35:26.567364+0800 Framework测试主工程[11743:577093] -[StaticLibraryTwo staticLibraryTwoTestMethod]
2019-05-27 20:35:26.567472+0800 Framework测试主工程[11743:577093] -[StaticLibraryOne staticLibraryOneTestMethod]

  总结:StaticLibrary的嵌套使用,会link所有内容,但是要注意修改类名,避免冲突

 StaticLibrary中嵌套StaticFramework

  • 将StaticFrameworkOne加入到StaticLibraryOne并调用其方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#import "StaticLibraryOne.h"
#import <StaticFrameworkOne/StaticFrameworkOne.h>

@implementation StaticLibraryOne

- (void)staticLibraryOneTest
{
NSLog(@"%s",__func__);

StaticFrameworkOneTest *one = [[StaticFrameworkOneTest alloc] init];
[one staticFrameworkOneTestMethod];
}

@end
  • 编译StaticLibraryOne,并将其导入测试工程中,并调用其方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#import "ViewController.h"
#import "StaticLibraryOne.h"


@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
[super viewDidLoad];

StaticLibraryOne *one = [[StaticLibraryOne alloc] init];
[one staticLibraryOneTest];
}


@end
  • 运行测试工程,发现其报错


  • 将StaticFramework加入测试工程中,运行测试工程,输出如下:
1
2
2019-05-27 20:54:42.634333+0800 Framework测试主工程[12028:602066] -[StaticLibraryOne staticLibraryOneTest]
2019-05-27 20:54:42.634494+0800 Framework测试主工程[12028:602066] -[StaticFrameworkOneTest staticFrameworkOneTestMethod]

  总结:StaticLibrary嵌套使用staticFramework,不会将staticFramework的内容link进来,外部使用还需要link

 DynamicFramework中嵌套StaticLibrary

  • 创建叫DynamicFrameworkOne的DynamicFramework, 添加StaticLibraryOne,并实现方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#import "DynamicFrameworkOneTest.h"
#import "StaticLibraryOne.h"

@implementation DynamicFrameworkOneTest

- (void)dynamicFrameworkOneTest
{
NSLog(@"%s",__func__);

StaticLibraryOne *one = [[StaticLibraryOne alloc] init];
[one staticLibraryOneTestMethod];
}

@end
  • 编译DynamicFrameworkOne, 并将其添加到demo工程调用其方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#import "ViewController.h"
#import <DynamicFrameworkOne/DynamicFrameworkOne.h>

@interface ViewController ()
@end

@implementation ViewController

- (void)viewDidLoad {
[super viewDidLoad];

DynamicFrameworkOneTest *one = [[DynamicFrameworkOneTest alloc] init];
[one dynamicFrameworkOneTest];
}
@end
  • 运行测试工程,输出如下:
1
2
2019-05-27 21:26:06.248994+0800 Framework测试主工程[12571:646020] -[DynamicFrameworkOneTest dynamicFrameworkOneTest]
2019-05-27 21:26:06.249154+0800 Framework测试主工程[12571:646020] -[StaticLibraryOne staticLibraryOneTestMethod]

  总结:dynamicFramework中嵌套使用StaticLibrary,会将StaticLibrary中的内容也link到DynamicFramework内部

  注意:测试工程导入DynamicFramework时报错,提示如下:

  解决办法:

 DynamicFramework中嵌套StaticFramework

  • DynamicFrameworkOne中导入StaticFramework,并调用其方法,内部如实现如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#import "DynamicFrameworkOneTest.h"
#import <StaticFrameworkOne/StaticFrameworkOne.h>

@implementation DynamicFrameworkOneTest


- (void)dynamicFrameworkOneTestMethod
{
NSLog(@"%s",__func__);

StaticFrameworkOneTest *one = [[StaticFrameworkOneTest alloc] init];
[one staticFrameworkOneTestMethod];
}

@end
  • 编译DynamicFramework并将其导入到测试主工程:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#import "ViewController.h"
#import <DynamicFrameworkOne/DynamicFrameworkOne.h>

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
[super viewDidLoad];

DynamicFrameworkOneTest *one = [[DynamicFrameworkOneTest alloc] init];
[one dynamicFrameworkOneTestMethod];
}

@end
  • 运行测试主工程,输出如下:
1
2
2019-05-27 21:43:59.495934+0800 Framework测试主工程[12852:669931] -[DynamicFrameworkOneTest dynamicFrameworkOneTestMethod]
2019-05-27 21:43:59.496059+0800 Framework测试主工程[12852:669931] -[StaticFrameworkOneTest staticFrameworkOneTestMethod]

  总结: DynamicFramework中嵌套使用StaticFramework时,会将StaticFramework中的内容也link到DynamicFramwork内部

 DynamicFramework中嵌套DynamicFramework

  • DynamicFrameworkTwo中导入 DynamicFrameworkOne,并调用其方法,内部实现如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#import "DynamicFrameworkTwoTest.h"
#import <DynamicFrameworkOne/DynamicFrameworkOne.h>

@implementation DynamicFrameworkTwoTest

- (void)dynamicFrameworkTwoTestMethod
{
NSLog(@"%s",__func__);

DynamicFrameworkOneTest *one = [[DynamicFrameworkOneTest alloc] init];
[one dynamicFrameworkOneTestMethod];
}

@end
  • 编译DynamicFramework并导入测试工程中,调用其方法,内部实现如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#import "ViewController.h"
#import <DynamicFrameworkTwo/DynamicFrameworkTwo.h>


@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
[super viewDidLoad];

DynamicFrameworkTwoTest *two = [[DynamicFrameworkTwoTest alloc] init];
[two dynamicFrameworkTwoTestMethod];
}


@end
  • 运行测试工程,发现报错
  • 解决方案:将DynamicFrameworkOne导入工程,运行结果如下
1
2
2019-05-27 21:58:46.241110+0800 Framework测试主工程[13102:688871] -[DynamicFrameworkTwoTest dynamicFrameworkTwoTestMethod]
2019-05-27 21:58:46.241230+0800 Framework测试主工程[13102:688871] -[DynamicFrameworkOneTest dynamicFrameworkOneTestMethod]

  总结: DynamicFramework中嵌套使用DynamicFramework时,外部使用DynamicFramework时还需要link内部使用的DynamicFramework,具体查看其内部是否有对应的内部DynamicFramework文件

 Podfile中#useframework!和useframework!的使用

  • 不使用use_frameworks! -> static libraries 方式 -> 生成.a文件
1
2
在Podfile中如不加use_frameworks!,cocoapods会生成相应的 .a文件(静态链接库),
Link Binary With Libraries: libPods-**.a 包含了其他用pod导入有第三方库的.a文件
  • use_frameworks! -> dynamic frameworks 方式 -> 生成.framework文件
1
2
使用了use_frameworks!,cocoapods会生成对应的frameworks文件(包含了头文件,二进制文件,资源文件等等)
Link Binary With Libraries:Pods_xxx.framework包含了其它用pod导入的第三方框架的.framework文件

使用场景

  • Swift项目cocoapods 默认 use_frameworks!
  • OC项目cocoapods 默认 #use_frameworks!

用cocoapods导入OC框架到swift项目:

  • #use_frameworks! 必须创建头文件,在头文件里面 #import "AFNetworking.h"
  • use_frameworks! 如果有头文件,在头文件里面 #import "AFNetworking/AFNetworking.h",其它swift文件中用到不需要再import;如果没有头文件,则在每个需要用到的swift文件里import AFNetworking

用cocoapods导入swift框架到swift项目:

  • 必须use_frameworks!
  • 不需要头文件,在需要用到框架的swift文件里 import Alamofire

用cocoapods导入OC框架到OC项目:

  • #use_frameworks! 在需要用到的文件里 #import “AFNetworking.h”;也可以通过pch文件,用法类似swift中的头文件。
  • use_frameworks! 与上述类似,用法上没有区别。