iOS 打Framework

作者: 一亩三分甜 | 来源:发表于2019-06-16 21:08 被阅读0次

六月潮湿天气的日数比五月多,比四月也多。周四晚踢足球,深圳多雨,中午电闪雷鸣雨不停,有人建议取消场地,我想雨后终究会见到彩虹,不一会,雨停。

项目需求提供framework,记录下过程。

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

二、静态库和动态库的区别?
静态库:链接时完整地拷贝至可执行文件中,被多次使用就有多分拷贝冗余拷贝。
动态库:链接不复制,程序运行时由系统动态加载到内存,供程序调用,系统只加载一次,多个程序共用,节省内存。

三、iOS里静态库形式?
.a和.framework

四、iOS里动态库形式?
.dylib和.framework

五、framework为么可以既是静态库有事动态库?
系统的.framework是动态库,我们自己建立的.framework是静态库。

六、.a与.framework有什么区别?
.a是一个纯二进制文件,.framework中除了有二进制文件之外还有资源文件。
.a文件不能直接使用,至少要有.h文件配合,.framework文件可以直接使用。
.a + .h + sourceFile = .framework。
建议用.framework。

七、为什么要使用静态库?
方便共享代码,便于合理使用。
实现iOS程序的模块化。可以把固定的业务模块化成静态库。和别人分享你的代码库,但不想让别人看到你代码的实现。开发第三方sdk的需要。

提供给接入方使用的是文件,一般是一个.framework和一个同名的.bundle文件。

1、嵌入包含.bundle的framework到接入方的embeded binaries里面,刚开始想着是否能只提供一个.framework文件,bundle包含在里面。可是可以,只是需要将打出来的.framework导入到embeded binaries中。但是接入此.framework后,打包会报错。

VaRZnA.png

点击show logs,did not contain a "archived-expanded-entitlements.xcent" resource
解决办法:一个static的libraryxxx.framework被添加在Embedded Binaries里面了,从Embedded Binaries移除framework,添加在Link Frameworks and Libraries里面。
只能作罢,只有动态库能放到embeded binaries中,Xcode也能制作动态库,只是不能上传AppStore。
通过嵌入embeded binaries里面打出来的,最后形成.app文件右键显示包内容之后和可以看到一个Frameworks的文件夹。里面有嵌入embeded binaries的所有framework。


Snip20190615_1.png
  • 新建一个workspace,添加两个project:CVideoProject,CVideoDemoProject。在CVideoProject中添加一个target:CVideoBundle。相当于总共有三个target,方便调试。

1.新建静态库:static framework。

Snip20190616_2.png
2.修改配置信息
  • 每次build时不是只生成支持一种设备的framework


    Snip20190616_3.png
  • 添加framework支持所有类型设备。


    Snip20190616_4.png
arm64:iPhone6s | iphone6s plus|iPhone6| iPhone6 plus|iPhone5S | iPad Air| iPad mini2(iPad mini with Retina Display)
armv7s:iPhone5|iPhone5C|iPad4(iPad with Retina Display)
armv7:iPhone4|iPhone4S|iPad|iPad2|iPad3(The New iPad)|iPad mini|iPod Touch 3G|iPod Touch4
i386是针对intel通用微处理器32位处理器
x86_64是针对x86架构的64位处理器
模拟器32位处理器测试需要i386架构,
模拟器64位处理器测试需要x86_64架构,
真机32位处理器需要armv7,或者armv7s架构,
真机64位处理器需要arm64架构。

  • 需要暴露给接入方使用的头文件移到public路径中。


    Snip20190616_5.png
    Snip20190616_8.png

3.在framework中新建bundle。

Snip20190616_9.png
Snip20190616_10.png
  • 导入用到的资源文件


    Snip20190616_14.png
  • 修改bundle文件的参数配置


    Snip20190616_15.png
    Snip20190616_16.png
    Snip20190616_18.png
    Snip20190616_20.png
  • 编译bundle target生成bundle。


    Snip20190616_23.png
    Snip20190616_24.png
    Snip20190616_25.png
  • 编译framework发现framework中包含bundle。


    Snip20190616_26.png

1、将bundle放入到framework中,打出来的framework中包含bundle,此时代码里面引入图片的路径有变。在workspace的Demo中的embeded binaries引入framework。

0.gif
  • 通过打开CVideoDemo.app显示包内容发现如果嵌入到embeded binaries中的framework都放在一个frameworks文件夹路径下。而CVideo.bundle就在Frameworks/CVideo.framework路径下,图片的路径据此找到。


    1.gif
-(void)setupBackNaviBar
{
    self.navigationItem.leftBarButtonItem = nil;
    self.backView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 100, 44)];
    CVideoAddAreaButton *backButton=[CVideoAddAreaButton buttonWithType:UIButtonTypeCustom];
    backButton.shouldExpandClickArea = YES;
    [backButton setFrame:CGRectMake(0, 0, 44, 44)];
    [backButton setImage:[CVideoBundle CVideoImageWithName:@"icon_back"] forState:UIControlStateNormal];
    [backButton addTarget:self action:@selector(onNaviBack) forControlEvents:UIControlEventTouchUpInside];
    [self.backView addSubview:backButton];
    
    self.closeButton=[CVideoAddAreaButton buttonWithType:UIButtonTypeCustom];
    self.closeButton.shouldExpandClickArea = NO;
    [self.closeButton setFrame:CGRectMake(32, 0, 44, 44)];
    [self.closeButton setImage:[CVideoBundle CVideoImageWithName:@"icon_close"] forState:UIControlStateNormal];
    [self.closeButton addTarget:self action:@selector(closeButtonClicked:) forControlEvents:UIControlEventTouchUpInside];
    [self.backView addSubview:self.closeButton];
    self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc]initWithCustomView:self.backView];
}
+ (NSString *)CVideoBundlePathForResource:(NSString *)name ofType:(NSString *)type {
    NSString *bundlePath = [self getCVideoBundlePath];
    return [[NSBundle bundleWithPath:bundlePath] pathForResource:name ofType:type];
}

+ (UIImage *)CVideoImageWithName:(NSString *)name {
    //bundle放入framework中,framework嵌入embeded binaries中的图片路径
    name = [NSString stringWithFormat:@"%@@%dx", name, (int)[UIScreen mainScreen].scale];
    NSString *imagePath = [CVideoBundle CVideoBundlePathForResource:name ofType:@"png"];
    UIImage *image = [UIImage imageWithContentsOfFile:imagePath];
    //bundle单独拖入Demo中的bundle路径
//    NSString *imagePath = [NSString stringWithFormat:@"%@/%@",[self getCVideoBundlePath],name];
//    UIImage *image = [UIImage imageNamed:imagePath];
    return image;
}

+ (NSString *)getCVideoBundlePath {
    static NSString *bundlePath;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        //bundle放入framework中,framework嵌入embeded binaries中的bundle路径
        bundlePath = [[NSBundle mainBundle] pathForResource:@"Frameworks/CVideo.framework/CVideo" ofType:@"bundle"];
        //bundle单独拖入Demo中的bundle路径
//        bundlePath = [[NSBundle mainBundle] pathForResource:@"CVideo" ofType:@"bundle"];
    });
    return bundlePath;
}

2、显然,虽然将bundle放入framework中,提供给接入方只需要提供framework文件给接入方而不需要提供bundle文件,但是打包的时候会报错,所以还是要将bundle和framework分开提供。

2.gif
  • 图片的路径。
-(void)setupBackNaviBar
{
    self.navigationItem.leftBarButtonItem = nil;
    self.backView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 100, 44)];
    CVideoAddAreaButton *backButton=[CVideoAddAreaButton buttonWithType:UIButtonTypeCustom];
    backButton.shouldExpandClickArea = YES;
    [backButton setFrame:CGRectMake(0, 0, 44, 44)];
    [backButton setImage:[CVideoBundle CVideoImageWithName:@"icon_back"] forState:UIControlStateNormal];
    [backButton addTarget:self action:@selector(onNaviBack) forControlEvents:UIControlEventTouchUpInside];
    [self.backView addSubview:backButton];
    
    self.closeButton=[CVideoAddAreaButton buttonWithType:UIButtonTypeCustom];
    self.closeButton.shouldExpandClickArea = NO;
    [self.closeButton setFrame:CGRectMake(32, 0, 44, 44)];
    [self.closeButton setImage:[CVideoBundle CVideoImageWithName:@"icon_close"] forState:UIControlStateNormal];
    [self.closeButton addTarget:self action:@selector(closeButtonClicked:) forControlEvents:UIControlEventTouchUpInside];
    [self.backView addSubview:self.closeButton];
    self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc]initWithCustomView:self.backView];
}
+ (NSString *)CVideoBundlePathForResource:(NSString *)name ofType:(NSString *)type {
    NSString *bundlePath = [self getCVideoBundlePath];
    return [[NSBundle bundleWithPath:bundlePath] pathForResource:name ofType:type];
}

+ (UIImage *)CVideoImageWithName:(NSString *)name {
    //bundle放入framework中,framework嵌入embeded binaries中的图片路径
    name = [NSString stringWithFormat:@"%@@%dx", name, (int)[UIScreen mainScreen].scale];
//    NSString *imagePath = [CVideoBundle CVideoBundlePathForResource:name ofType:@"png"];
//    UIImage *image = [UIImage imageWithContentsOfFile:imagePath];
    //bundle单独拖入Demo中的bundle路径
    NSString *imagePath = [NSString stringWithFormat:@"%@/%@",[self getCVideoBundlePath],name];
    UIImage *image = [UIImage imageNamed:imagePath];
    return image;
}

+ (NSString *)getCVideoBundlePath {
    static NSString *bundlePath;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        //bundle放入framework中,framework嵌入embeded binaries中的bundle路径
//        bundlePath = [[NSBundle mainBundle] pathForResource:@"Frameworks/CVideo.framework/CVideo" ofType:@"bundle"];
        //bundle单独拖入Demo中的bundle路径
        bundlePath = [[NSBundle mainBundle] pathForResource:@"CVideo" ofType:@"bundle"];
    });
    return bundlePath;
}

Demo地址。

相关文章

网友评论

    本文标题:iOS 打Framework

    本文链接:https://www.haomeiwen.com/subject/qtdgfctx.html