文章写于2016/04/08,搬家到此处

第一篇 iOS封装Framework

如果我们希望与别人共享某些函数,却又不愿意暴露实现的细节,怎么办呢?
这时候可以将我们的代码封装成framework,对外提供接口而不暴露实现;
不仅如此,将代码整合成framework还有很多其他的好处,这里就不一一列举。

下面就来看看如何打包成 framework 吧。

1、 创建工程


通过OS X > Framework&Library > Bundle 创建工程:

imgimg

2、添加 Headers


在 Build Phases 中添加 Headers:

img

Headers 展开后是这样的:

img

3、添加项目代码


将需要封装打包的文件加入项目中,这里最好用 copy 的方式加入:

img

img

4、合并头文件


为了方便别人使用 framework,最好创建一个头文件,并且在头文件下包含你所有想要公开的类,如此,当别人使用你的 framework 时只需要导入这一个头文件就可以了。

img

5、公开类


当代码加入了项目后,所有的 .h 文件都会自动出现在 Headers 的 Project 下面,然后,我们将需要公开的类拖到 Public 下面。

img

这里需要注意:Private 仍然是公开的而不是私有的,不要被它的名字误导了,私有类保留在 Project 下就好。

img

6、更改一些设置:


6.1 info.plist > Bundle OS Type code = FMWK

img

6.2 Build Settings > Base SDK = Latest iOS,选择最新的

img

6.3 Build Settings > Linking :

  • Dead Code Stripping = NO;
  • Link With Standard Libraries = NO;
  • Mach-O Type = Static Library.

对于Mach-O Type可能有两种情况:(1)选择 Static Library 打出来的是静态库;(2)选择 Relocatable Object File 打出来是动态库。

这里建议使用静态库,动态库在提交 AppStore 审核的时候貌似会被拒;但是网上看了一些资料说动态库也是可以的,不过会有一些机审的规则需要注意下,比如不要把x86/i386的包和arm架构的包lipo在一起,就单纯使用真机包。(关于这个没有测试过,也不知道是不是真的,如果有朋友测试过的希望告知下,谢谢!)

img

6.4 Build Settings > Packaging > Wrapper Extension = framework.

img

7、修改输出路径


7.1 为了方便找到运行后生成的framework,我们提前在项目目录下创建一个目录 build,用来存放运行后生成的文件;

img

7.2 然后,需要修改下输出路径:

Build Settings > Per-configuration Build Products Path = $(SRCROOT)/build/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)

img

8、编译


8.1 选择 Generic iOS Device, 编译;

img

8.2 选择模拟器,编译。

img

8.3 编译成功后,会在 build 下产生2个文件夹,一个是 device 编译生成的,一个是 simulator 编译生成的,他们里面存放着对应的 framework。

img

9、合并


此时,已经有了适用于设备和模拟器的2个framework,接下来,需要将他们合并,使其同时适用于设备与模拟器。

9.1 这里合并的并不是2个framework,而是各自的二进制文件,如下图中的 JJFramework;

img

9.2 那么如何合并呢?首先,打开终端,cd 到 build 文件夹;然后输入命令:

lipo -create 设备二进制文件 模拟器二进制文件 -output 合成文件的名字 ;

注意:(1)注意空格。(2)合成后的文件名字需要和合成前的名字一样,否则使用framework时会报错。

如上图,合并2个 JJFramework 输入如下命令:

lipo -create Debug-iphoneos/JJFramework.framework/JJFramework Debug-iphonesimulator/JJFramework.framework/JJFramework -output JJFramework。

build 文件夹下的 JJFramework 就是合成后的二进制文件了。

img

9.3 将设备或模拟器运行生成的framework移出来,用合成的二进制文件替换原本二进制文件:

img img

10、删除 info.plist


到这里就基本上大功告成了。
另外,如果framework中没有用到过 info.plist,可以将其删除以免发生冲突。(我就遇到过一次这坑爹的情况)
img

OK, framework打包完成。

其实封装 framework 有很多种方法,以上只是其中一种;而且应该还有更简单的方法,有时间的话,后续会补上。

第二篇 使用bundle管理资源

上一篇通过 Bundle 创建 framework,这一篇直接通过 iOS 的 Framework来实现,更加简单。

本篇使用的 Xcode 版本为 7.2.1 。

一、首先,iOS -> Framework&Library -> Cocoa Touch Framework 创建工程。

img

工程的名字要与你所期望的 SDK 名字一样。这里以 ExpeSDK 作为项目名。

二、工程创建完成后,删除自带的 ExpeSDK.h 和 ExpeSDKTests.m 文件,因为用不到的,移到废纸篓。

img

三、在 Build Settings 中更改一些配置

3.1 Architectures 默认是 armv7和 arm64。可以增加 armv7s 架构,主要是为了兼容5C,如果不考虑5C的话,可以忽略这一步。

3.2 更改输出路径:在项目根目录下创建一个build目录,更改如下配置,输出文件就会在build文件下,这一步只是为了方便找到输出文件而已。

Per-configuration Build Products Path > $(SRCROOT)/build/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)

3.3 推荐如下设置:

Mach-O Type > Static Library;( 静态库,如果需要提审 Appstore 的话不允许使用动态库的)

Dead Code Stripping > NO;(是否消除无效代码)

Link With Standard Libraries 默认是YES,如果没有特殊要求的话,默认就可以。

​ 设为 NO 也是可以打包的,但是使用framework时要配置Other Linker Flags。

Enable Bitcode > NO;(支持旧库)

四、将需要共享的文件copy到工程。这里copy过来的文件是 config.h 和 config.m ;

五、Build Phases -> Headers :

将需要共享的头文件拖入 Public, 私有的保留在 Project。

img

六、编译

模拟器编译:

img

Device 编译:

img

七、合并二进制文件

编译成功后,在build目录下会生成模拟器和设备的framework,合并他们的二进制文件,使framework能够在设备和模拟器上通用;

device的framework:

img

simulator的framework:

img

7.1 打开终端,cd 到 build 目录:

cd build文件路径

7.2 输入合成命令:(lipo -create 设备二进制文件 模拟器二进制文件 -output 合成文件的名字)

lipo -create Debug-iphoneos/ExpeSDK.framework/ExpeSDK Debug-iphonesimulator/ExpeSDK.framework/ExpeSDK -output ExpeSDK

合成完毕后,build目录下会生成一个新的二进制文件:

img

7.3 替换二进制文件

然后将新的二进制文件替换掉 device framework 中的二进制文件。

img

移出framework。

OK,framework制作完成!


很多时候,我们需要用到图片,xib等等这些资源,就需要 bundle 来管理。

创建 Bundle 最简单的方法:新建一个文件,命名为 xxx.bundle 就OK 了。

此处,我新建一个tuxiang.bundle,然后右击显示包内容,放入2张图片 tx_1.jpg 和 tx_2.png 。

1、新建一个app工程showApp

2、将上面的 ExpeSDK.framework 和 tuxiang.bundle 加入到项目中,如此,当程序运行时,xcode会自动将 tuxiang.bundle 拷贝到 app mainBundle.

在ExpeSDK.framework的config.m中我已经写好了获取tuxiang.bundle中图片的方法,代码如下:

- (UIView*)configUI
{
    UIImage * image = [config getPNGImage:@"tx_2"];
    UIImageView * imgView = [[UIImageView alloc] initWithImage:image];
    imgView.frame = CGRectMake(0, 20, 375, 600);
    return imgView;
}
+ (UIImage*)getPNGImage:(NSString*)_image_name
{
    NSBundle * txBundle = [self getBundle:@"tuxiang"];
    NSString * imgPath = [txBundle pathForResource:_image_name ofType:@"png"];
    return [UIImage imageWithContentsOfFile:imgPath];
}
+ (UIImage*)getJPGImage:(NSString*)_image_name
{
    NSBundle * bundle = [self getBundle:@"tuxiang"];
    NSString * imgPath = [bundle pathForResource:_image_name ofType:@"jpg"];
    return [UIImage imageWithContentsOfFile:imgPath];
}

+ (NSBundle*)getBundle:(NSString*)_bundle_name
{
    NSLog(@"mainBundle resourcePath = %@",[NSBundle mainBundle].resourcePath);
    
    /* 从 mainBundle 获取 tuxiang.bundle */
    // 方法 1
    //    NSString * component = [NSString stringWithFormat:@"%@.bundle",_bundle_name];
    //    NSString * bundlePath = [[NSBundle mainBundle].resourcePath stringByAppendingPathComponent:component];
    
    // 方法 2
    NSString * bundlePath = [[NSBundle mainBundle] pathForResource:_bundle_name ofType:@"bundle"];
    
    NSBundle * bundle = [NSBundle bundleWithPath:bundlePath];
    return bundle;
}

img点击并拖拽以移动

在config.h文件中提供对外的方法:

- (UIView*)configUI;

img点击并拖拽以移动

3、在 showApp 中调用 configUI:

先导入头文件

#import "ExpeSDK/config.h"

img点击并拖拽以移动

然后在viewDidLoad中调用函数

- (void)viewDidLoad 
{
    [super viewDidLoad];
    
    config * ObjCon = [[config alloc] init];
    [self.view addSubview:[ObjCon configUI]];
}

img点击并拖拽以移动

4、运行:

img

的确是预期的效果。

第三篇 在工程中直接制作framework

如果我们写了一个工程,可以直接在工程中制作 framework.

1、建立工程,工程名 showLog

img

2、在 showLog 中新建一个类 LogMessage,在这里写一个函数,最终的目的是打包成framework共享这个函数方法;

LogMessage.h

@interface LogMessage : NSObject
+ (void)logInfo; //共享的方法
@end

img点击并拖拽以移动

LogMessage.m

@implementation LogMessage
+ (void)logInfo
{
    NSLog(@"log info success!");
}
@end

img点击并拖拽以移动

3、接下来,在项目中建立 framework

img

会看到新建工程的界面,选择 Cocoa Touch Framework 。这里起名叫 LogSDK.

img

新的 target 建好以后,可以看到工程中多了1、2块文件,删除原生的 .h 与 .m 文件:

img

4、选择新的target: LogSDK,General > Deployment Info > Deployment Target 选择最低;

img

按照下图修改配置:

img

img

5、定位到 LogSDK > Build Phases,将 .m 文件拖到 Compile Sources, 将需要公开的 .h 文件拖到Headers > Pulic,需要私有的拖到Headers > Project:

img

6、更改输出路径:

在项目文件下新建 build 目录

img

LogSDK > Build Settings > Build Locations :

img

更改上图中的配置如下:

$(SRCROOT)/build/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)

7、编译:

需要先选定到 LogSDK:

img

然后分别进行模拟器和 Device 的编译;

8、编译成功后,按照上一篇的第7步合并。


Jerod
47 声望4 粉丝