http://www.jianshu.com/p/ef3d5b7e7006
http://www.knowsky.com/884469.html
http://www.jianshu.com/p/6c033c39884a
http://my.oschina.net/u/856930/blog/196484
http://ios.jobbole.com/81583/
https://segmentfault.com/q/1010000002952316
网上有很多解释和写法,这里根据自己的实测做一下综合
Framework常识
苹果平台的链接库除了静态库 .a 和 动态库.dylib 之外,Mac OS/iOS 平台还可以使用 Framework。Framework 实际上是一种打包方式,将库的二进制文件,头文件和有关的资源文件打包到一起,方便管理和分发,这样 Xcode 能够很容易的将其集成到你的工程中去。
在 iOS 8 之前,iOS 平台不支持使用动态 Framework,开发者可以使用的 Framework 只有苹果自家的 UIKit.Framework,Foundation.Framework 等。这种限制可能是出于安全的考虑。换一个角度讲,因为 iOS 应用都是运行在沙盒当中,不同的程序之间不能共享代码,同时动态下载代码又是被苹果明令禁止的,没办法发挥出动态库的优势,实际上动态库也就没有存在的必要了。
由于上面提到的限制,开发者想要在 iOS 平台共享代码,唯一的选择就是打包成静态库 .a 文件,同时附上头文件(例如微信的SDK)。但是这样的打包方式不够方便,使用时也比较麻烦,大家还是希望共享代码都能能像 Framework 一样,直接扔到工程里就可以用。于是人们想出了各种奇技淫巧去让 Xcode Build 出 iOS 可以使用的 Framework,Framework 还有 “伪”(Fake) Framework 和 “真“(Real) Framework 的区别。
iOS 8/Xcode 6 推出之后,iOS 平台添加了动态库的支持。为什么 iOS 8 要添加动态库的支持?唯一的理由大概就是 Extension 的出现。Extension 和 App 是两个分开的可执行文件,同时需要共享代码,这种情况下动态库的支持就是必不可少的了。但是这种动态 Framework 和系统的 UIKit.Framework 还是有很大区别。系统的 Framework 不需要拷贝到目标程序中,我们自己做出来的 Framework 哪怕是动态的,最后也还是要拷贝到 App 中(App 和 Extension 的 Bundle 是共享的),因此苹果又把这种 Framework 称为 Embedded Framework。
系统会在需要的时候将framework载入内存中,多个应用程序可以同时使用同一个framework。这种方法可以使得你的代码易分享,在多个工程中复用,并且可以隐藏实现细节,控制公开的头文件。
苹果平台的静态库和动态库的概念与其他平台的概念不尽相同。
- 静态库:链接时完整地拷贝至可执行文件中,被多次使用就有多份冗余拷贝。
- 动态库:链接时不复制,程序运行时由系统动态加载到内存,供程序调用,系统只加载一次,多个程序共用,节省内存。
总结来说:其实就是加载时机和加载次数的不同。
framework分为真机—Debug(调试)版本、真机—Release(发布)版本、模拟器—Debug版本、模拟器—Release版本;开发中一般都打包Release(发布)版本,将真机和模拟器版本合并,提供外界。(注意:debug和release要和引入framework的工程对应)
在项目开发的过程中,例如两个公司之间业务交流,不可能把源代码都发送给另一个公司,这时候将私密内容打包成framework,别人只能调用接口,而不能知道其中实现的细节。
制作framework
步骤
1,新建工程
选择左边那个framework,右边那个是创建.a静态库的。
2,创建接口代码
在工程中创建类,写一些开放给外部用的接口。
第一个类,做点简单的加法,需要公开的api就写在h里面
//
// Compute.h
// FrameworkTest
//
// Created by yxhe on 16/7/6.
// Copyright © 2016年 yxhe. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface Compute : NSObject
- (NSInteger)addNumber:(NSInteger)a withNumber:(NSInteger)b;
@end
//
// Compute.m
// FrameworkTest
//
// Created by yxhe on 16/7/6.
// Copyright © 2016年 yxhe. All rights reserved.
//
#import "Compute.h"
@implementation Compute
- (NSInteger)addNumber:(NSInteger)a withNumber:(NSInteger)b
{
return a + b;
}
@end
第二个类,打印
//
// Print.h
// FrameworkTest
//
// Created by yxhe on 16/7/6.
// Copyright © 2016年 yxhe. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface Print : NSObject
- (void)printWords:(NSString *)words;
@end
//
// Print.m
// FrameworkTest
//
// Created by yxhe on 16/7/6.
// Copyright © 2016年 yxhe. All rights reserved.
//
#import "Print.h"
@implementation Print
- (void)printWords:(NSString *)words
{
NSLog(@"%@", words);
}
@end
最后在自动生成的导出头文件里把这两个类的h都import进去
//
// FrameworkTest.h
// FrameworkTest
//
// Created by yxhe on 16/7/6.
// Copyright © 2016年 yxhe. All rights reserved.
//
#import <UIKit/UIKit.h>
//! Project version number for FrameworkTest.
FOUNDATION_EXPORT double FrameworkTestVersionNumber;
//! Project version string for FrameworkTest.
FOUNDATION_EXPORT const unsigned char FrameworkTestVersionString[];
// In this header, you should import all the public headers of your framework using statements like #import <FrameworkTest/PublicHeader.h>
#import <FrameworkTest/Compute.h>
#import <FrameworkTest/Print.h>
3,修改buildsettings
选择TARGETS里面
- Linking下面:Dead Code Stripping选No,Mach-O Type选择static或者dynamic都行(在后面有点区分)
- Architectures下增加armv7s,并选中。将Build Active Architecture Only 设置为NO
4,设置Headers
把需要公开调用的头文件一道public里面,需要隐藏的放在private里面。
5,打包framework
- 选择一个模拟器,编译工程(command + B)
- 选择一个真机或者Generic Device(建议),编译工程(command + B)
- 在Finder中找到.framework文件
生成成功后工程目录里的product从红色变成了正常颜色。
会看到分成了 模拟器和真机两个文件夹,此时就可以把这两个.framework分别引入到对应的模拟器或者真机项目使用了。
6,合并framework
通过终端命令将两个framework合为一个模拟器和真机都可使用的framework。
打开控制台输入
lipo -create iphoneos下frameworkTest的路径 simulator下frameworkTest的路径 -output 新的路径,这样就完成了模拟器和真机版本的合并,新路径下的frameworkTest就是你合并后的文件,将这个文件名字改成和你未合并之前的Test一样的名字,放到framework文件夹下,替换掉原来的frameworkTest文件。
例如我的
lipo -create /Users/yxhe/Library/Developer/Xcode/DerivedData/FrameworkTest-gajdcpnghsabghalspugjmolohhd/Build/Products/Debug-iphoneos/FrameworkTest.framework/FrameworkTest /Users/yxhe/Library/Developer/Xcode/DerivedData/FrameworkTest-gajdcpnghsabghalspugjmolohhd/Build/Products/Debug-iphonesimulator/FrameworkTest.framework/FrameworkTest -output /Users/yxhe/Library/Developer/Xcode/DerivedData/FrameworkTest-gajdcpnghsabghalspugjmolohhd/Build/Products/FrameworkTest
在目标文件夹里找到那个FrameworkTest文件,拖到真机.framework文件夹里替换掉原来的,这样,真机.framework就可以当做universal的framework使用了。
tips
- 合并还有另外一种方法,没试成功,是创建Aggregate跑脚本,不会写T_T
- 带有图片资源的需要把图片打包成Bundle文件,和framework一起拷贝到相应的项目中。
- 公开的类中如果引用的private的类,打包以后对外会报错,找不到那个private的类,可以把那个private的.h放到private里面
使用framework
引用系统framework
1)选中项目名称
2)选中TARGETS
3)选中Build Phases
4)在Link Binary With Libraries中添加。
5)点击“+”号,加入所需的系统提供的.framework文件
6)引入头文件,就行了
引用第三方framework
步骤
这里主要使用之前创建的framework测试
1)从Finder里面直接将.framework文件直接拖到工程目录中
2)在Link Binary With Libraries中添加framework
其实一般拖进去之后,这个项系统自动添加了
注意:如果是Dynamic Libray形式的framework,需要添加到Embedded Frameworks
3)在项目中引入头文件即可
测试结果
目录结构
代码的写法
//
// ViewController.m
// FrameWorkUseTest
//
// Created by yxhe on 16/7/6.
// Copyright © 2016年 yxhe. All rights reserved.
//
#import "ViewController.h"
// 引入framework的头文件
#import <FrameworkTest/Compute.h>
#import <FrameworkTest/Print.h>
@interface ViewController ()
@end
@implementation ViewController
- (IBAction)onClick:(id)sender
{
Compute *compute = [[Compute alloc] init];
NSInteger sum = [compute addNumber:7 withNumber:5];
Print *print = [[Print alloc] init];
[print printWords:[NSString stringWithFormat:@"7 + 5 = %ld", (long)sum]];
_numberLabel.text = [NSString stringWithFormat:@"7 + 5 = %ld", (long)sum];
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
在模拟器和iphone6s真机上都成测试成功
源代码
csdn:diy的framwork
github:diy的framwork