使用CocoaPods开发并打包静态库

Cocoapods作为OS X和iOS开发平台的类库管理工具,已经非常完善和强大。通常我们用pod来管理第三方开源类库,但我们也极有可能会开发一个用pod管理依赖关系的静态类库给其他人使用,而又不愿意公开源代码,比如一些SDK,那么就需要打包成.a文件。本文将以一个依赖于ASIHTTPRequest的静态类库,来演示如何创建使用了CocoaPods的静态类库以及打包的过程。

开发静态库(Static Library)

创建静态库,有2种方法。

不基于pod手动创建(deprecated)

过程比较繁琐,纯体力活不推荐,大体步骤说下

  1. 在Xcode中创建一个Cocoa Touch Static Library
  2. 创建Podfile文件;
  3. 执行pod install完成整个项目的搭建;
  4. 如果需要demo,手动创建示例程序,使用pod添加对私有静态库的依赖,重复执行pod install完成示例项目的搭建。

基于pod自动创建

只需要输入pod的lib命令即可完成初始项目的搭建,下面详细说明具体步骤,以BZLib作为项目名演示。

1.执行命令pod lib create BZLib。在此期间需要确认下面4个问题。
Would you like to provide a demo application with your library? [ Yes / No ]
yes
Which testing frameworks will you use? [ Specta / Kiwi / None ]
Kiwi
Would you like to do view based testing? [ Yes / No ]
No
What is your class prefix?
BZ

第一个问题询问是否提供一个demo项目,通常选择Yes,其他的可以根据需要选择。命令执行完后,就会创建好一个通过cocoapods管理依赖关系的基本类库框架。

2.打开BZLib.podspec文件,修改类库配置信息,结果像这样。
Pod::Spec.new do |s|
  s.name             = "BZLib"
  s.version          = "0.1.0"
  s.summary          = "A short description of BZLib."
  s.description      = <<-DESC
                       An optional longer description of BZLib

                       * Markdown format.
                       * Don't worry about the indent, we strip it!
                       DESC
  s.homepage         = "https://github.com/<GITHUB_USERNAME>/BZLib"
  # s.screenshots     = "www.example.com/screenshots_1", "www.example.com/screenshots_2"
  s.license          = 'MIT'
  s.author           = { "brycezhang" => "brycezhang.cn@gmail.com" }
  s.source           = { :git => "https://github.com/<GITHUB_USERNAME>/BZLib.git", :tag => s.version.to_s }
  # s.social_media_url = 'https://twitter.com/<TWITTER_USERNAME>'

  s.platform     = :ios, '6.0'
  s.requires_arc = true

  s.source_files = 'Pod/Classes/**/*.{h,m}'
  s.resource_bundles = {
    'BZLib' => ['Pod/Assets/*.png']
  }

  s.public_header_files = 'Pod/Classes/**/*.h'
  s.frameworks = 'MobileCoreServices', 'CFNetwork', 'CoreGraphics'
  s.libraries  = 'z.1'
  s.dependency 'YSASIHTTPRequest', '~> 2.0.1'
end

按照默认配置,类库的源文件将位于Pod/Classes文件夹下,资源文件位于Pod/Assets文件夹下,可以修改s.source_filess.resource_bundles来更换存放目录。s.public_header_files用来指定头文件的搜索位置。
s.frameworkss.libraries指定依赖的SDK中的framework和类库,需要注意,依赖项不仅要包含你自己类库的依赖,还要包括所有第三方类库的依赖,只有这样当你的类库打包成.a.framework时才能让其他项目正常使用。示例中s.frameworkss.libraries都是ASIHTTPRequest的依赖项。
podspec文件的详细说明可以看Podspec Syntax Reference

3.进入Example文件夹,执行pod install,让demo项目安装依赖项并更新配置。
localhost:Example bryce$ pod install --no-repo-update
Analyzing dependencies
Fetching podspec for `BZLib` from `../`
Downloading dependencies
Installing BZLib 0.1.0 (was 0.1.0)
Using Kiwi (2.3.1)
Installing Reachability (3.2)
Installing YSASIHTTPRequest (2.0.1)
Generating Pods project
Integrating client project
4.添加代码。因为是示例,只简单封装一下GET请求。

添加BZHttphelper类,注意文件存放的位置在Pod/Classes目录下,跟podspec配置要一致。
运行Pod install,让demo程序加载新建的类。也许你已经发现了,只要新增加类/资源文件或依赖的三方库都需要重新运行Pod install来应用更新
编写代码。示例代码很简单,创建了一个GET请求的包装方法。

#import "BZHttphelper.h"
#import <YSASIHTTPRequest/ASIHTTPRequest.h>

@implementation BZHttphelper

- (void)getWithUrl:(NSString *)url withCompletion:(void (^)(id responseObject))completion failed:(void (^)(NSError *error))failed
{
    ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:url]];
    __weak ASIHTTPRequest *weakrequest = request;
    [request setCompletionBlock:^{
         NSString *responseString = [weakrequest responseString];
         completion(responseString);
     }];

    [request setFailedBlock:^{
         NSError *error = [weakrequest error];
         failed(error);
     }];
    [request start];
}

@end

demo项目中调用测试。

#import "BZViewController.h"
#import <BZLib/BZHttphelper.h>

@interface BZViewController ()
{
    BZHttphelper *_httpHelper;
}
@end

@implementation BZViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    _httpHelper = [BZHttphelper new];
    [_httpHelper getWithUrl:@"http://wcf.open.cnblogs.com/blog/u/brycezhang/posts/1/5" withCompletion:^(id responseObject) {
         NSLog(@"[Completion]:%@", responseObject);
     } failed:^(NSError *error) {
         NSLog(@"[Failed]:%@", error);
     }];
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

成功打印,调用成功!

2014-11-23 16:52:23.946 BZLib[6329:96133] [Completion]:<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">博客园
...

提交本地代码库

1.修改s.source。根据你的实际路径修改。
s.source = { :git => "/Users/name/workspace/BZLib", :tag => '0.1.0' }
2.提交源码,并打tag。
git add .
git commit -a -m 'v0.1.0'
git tag -a 0.1.0 -m 'v0.1.0'

验证类库

开发完成静态类库之后,需要运行pod lib lint验证一下类库是否符合pod的要求。可以通过添加--only-errors忽略一些警告。

pod lib lint BZLib.podspec --only-errors --verbose
...
BZLib passed validation.

打包类库

需要使用一个cocoapods的插件cocoapods-packager来完成类库的打包。当然也可以手动编译打包,但是过程会相当繁琐。

  • 安装打包插件
    终端执行以下命令

    sudo gem install cocoapods-packager
  • 打包
    命令很简单,执行

    pod package BZLib.podspec --library --force

    其中--library指定打包成.a文件,如果不带上将会打包成.framework文件。--force是指强制覆盖。最终的目录结构如下

    |____BZLib.podspec
    |____ios
    | |____libBZLib.a

需要特别强调的是,该插件通过对引用的三方库进行重命名很好的解决了类库命名冲突的问题。

文中的示例代码下载
BZLib

本文是通过pod及其插件实现了创建和打包的功能,如果对具体实现细节感兴趣可以查看相关源码,或者查看文末的扩展阅读进一步了解。

扩展阅读

Posted by Bryce Zhang 
版权声明:自由转载-非商用-非衍生-保持署名 | Creative Commons BY-NC-ND 3.0

分类:  iOS
标签:  iOS
3
0
« 上一篇: iOS自动化编译
» 下一篇: Vno博客样式分享
posted @  2014-11-23 18:54  brycezhang 阅读( 20999) 评论( 43编辑  收藏
  
#1楼   2015-01-07 20:51  tinkl   
需要特别强调的是,该插件通过对引用的三方库进行重命名很好的解决了类库命名冲突的问题:
意思是处理项目引用2个以上相同库的问题?
  
#2楼 [ 楼主2015-01-13 10:27  brycezhang   
@ tinkl
是的。比如你的类库使用了ASI,然后打包成静态库.a文件。外部调用的项目也使用了ASI,那么不会造成冲突。因为在打包的时候,你的类库里的ASI被重命名为项目+ASI的前缀。
  
#3楼   2015-01-14 09:34  tinkl   
@ brycezhang
好的,多谢作者。解决我的困惑。
幸好没有自己去改第三方库的前缀名称,不然会死的。
  
#4楼   2015-01-20 20:45  夜归人   
您好,请教个问题,如何隐藏不需要暴露给其他人的内部类使用的头文件呢
  
#5楼 [ 楼主2015-01-21 14:26  brycezhang   
@ 夜归人
设置podspec文件的public_header_files,只添加需要暴露的头文件即可。详见 Podspec Syntax Reference
  
#6楼   2015-01-21 14:55  夜归人   
@ brycezhang
谢谢!
  
#7楼   2015-05-08 16:12  逍遥灬Leo   
您好,请教个问题
使用这个方法打包好的 framework
在app中使用报如下错误:
Undefined symbols for architecture arm64:
"_SCNetworkReachabilitySetDispatchQueue", referenced from:
-[PodBZLib_Reachability startNotifier] in libBZLib.a(Reachability.o)
-[PodBZLib_Reachability stopNotifier] in libBZLib.a(Reachability.o)
"_SCNetworkReachabilityCreateWithAddress", referenced from:
+[PodBZLib_Reachability reachabilityWithAddress:] in libBZLib.a(Reachability.o)
"_inflateEnd", referenced from:
-[PodBZLib_ASIDataDecompressor closeStream] in libBZLib.a(ASIDataDecompressor.o)
.........
我应该如何解决这个问题?
  
#8楼   2015-07-03 17:41  Ken.D   
您好,请教一下,ASIHTTPRequest是如何安装的?为什么我在.podspec添加的所有第三方的类库都安装不了?ASIHTTPRequest又是如何实现重命名的?
  
#9楼   2015-08-19 10:33  songxing10000   
这个风格好nice啊,好像个人网站的博客,求风格指南啊博主
  
#11楼 [ 楼主2015-08-22 16:16  brycezhang   
@ songxing10000
你要css的话,可以发给你^_^
  
#12楼   2015-09-14 17:29  ckw1988   
真赞。从cocoapods上看到这贴,特地过来留言感谢
  
#13楼   2015-09-18 14:03  xiaoliu_zzu   
@ 逍遥灬Leo
你好,我也遇到这样的问题,怎么解决的
  
#14楼   2015-09-22 18:05  xiaoliu_zzu   
我遇到的一些问题
1 YSASIHTTPRequest 已经被移除了,不能导入,所以可以用AFNetworking来测试
2 .podspec文件的s.source 路径用本地文件夹的路径即可
例如我的工程在桌面:
s.source= { :git => "/Users/user/Desktop/BZLib", :tag => '0.1.0' }
3 pod/Classes下放一个文件夹,文件夹中放相应的文件
e.g:pod/Classes/HTTPHelper/HTTPHelper.h
pod/Classes/HTTPHelper/HTTPHelper.m
此时:podspec中
s.source_files = 'Pod/Classes/**/*.{h,m}'
s.public_header_files = 'Pod/Classes/**/*.h'
4 当我们打包好,导入工程中测试的时候,会发现,报了好多错
那是因为我们用插件打包只能把文件打包进入,不能把系统的框架打包进去,所以,我们在工程中要导入相应的框架(.podspec文件中的s.frameworks我是没有设置的,至于设置之后是否还会出现导入运行报错,有待测试),此时我们需要导入相应的框架,如果是AFNetworking,那么导入的框架为MobileCoreServices.framework,SystemConfiguration.framework,libz.dylib
error :
Undefined symbols for architecture x86_64:
"_UTTypeCopyPreferredTagWithClass", referenced from:
-[PodBZLib_AFStreamingMultipartFormData appendPartWithFileURL:name:error:] in BZLib(AFURLRequestSerialization.o)
"_UTTypeCreatePreferredIdentifierForTag", referenced from:
-[PodBZLib_AFStreamingMultipartFormData appendPartWithFileURL:name:error:] in BZLib(AFURLRequestSerialization.o)
"_kUTTagClassFilenameExtension", referenced from:
-[PodBZLib_AFStreamingMultipartFormData appendPartWithFileURL:name:error:] in BZLib(AFURLRequestSerialization.o)
"_kUTTagClassMIMEType", referenced from:
-[PodBZLib_AFStreamingMultipartFormData appendPartWithFileURL:name:error:] in BZLib(AFURLRequestSerialization.o)
ld: symbol(s) not found for architecture x86_64
  
#15楼   2015-09-28 17:11  温小贝   
你好,我设置了暴露的头文件如下
s.public_header_files = 'Pod/Classes/WebRequest.h'

成功打包成.a后在iOS文件下,只有.a文件正常吗?

在工程中引入.a文件,发现无法引用WebRequest.h 请问还有什么缺漏的步骤吗
  
#16楼   2015-10-08 15:16  温小贝   
楼主 我生成.a文件了,在其他项目中直接导入.a文件,引用不到需要引用的.h文件,请教下这是什么原因
  
#17楼   2015-10-08 16:51  -dark-   
打包那块还是不明白,按照步骤走了,我的。a文件何在,从哪里取?
  
#18楼   2015-10-08 17:54  温小贝   
楼主 可否加q咨询下 前面的步骤我都走下来,到最后一步,pod package BZLib.podspec --library --force,有在iOS文件夹生成.a,直接把.a放入其他项目,引用不了里面的文件。暴露的头文件我是有设置的
  
#19楼   2015-10-08 17:54  温小贝   
qq 343206288 卡在这边好久了 希望得到你的解答 谢谢!
  
#20楼   2015-10-08 18:10  温小贝   
博主 快点出现吧
  
#21楼   2015-10-09 23:08  ab0809   
@ 温小贝
我也是啊,没有头文件,但是打包成framework就有头文件了。。。等待卤煮出现
  
#22楼   2015-10-10 18:11  -dark-   
.a问题解决了,现在是找不到.h头文件,引入到其他项目中,无法使用sdk中的代码!
  
#23楼   2015-10-12 13:48  温小贝   
@ -dark-
我也是这个问题,试验了多次,求楼主现身,跟我们讲解下
  
#24楼   2015-10-12 15:30  温小贝   
@ -dark-
你解决了这个问题了吗
  
#25楼   2015-10-12 15:30  温小贝   
@ ckw1988
你打包成功后,如何引用.a,我现在引入到其他项目中,找不到.h头文件,无法使用sdk中的代码!
  
#26楼   2015-10-12 17:46  温小贝   
使用静态库时,出现
Undefined symbols for architecture i386:
"_OBJC_CLASS_$_PSJRequest", referenced from:
objc-class-ref in ViewController.o
  
#27楼   2015-10-12 17:49  温小贝   
@ 夜归人
@Ken.D
@ab0809
@逍遥灬Leo
@ckw1988

使用CocoaPods开发并打包静态库,你们现在打包成功后,有没有出现引用.h出现问题的。qq 343206288 求指教
Undefined symbols for architecture i386:
"_OBJC_CLASS_$_PSJRequest", referenced from:
objc-class-ref in ViewController.o
  
#28楼   2015-10-12 20:37  -dark-   
@ 温小贝
没有
  
#29楼   2015-10-12 20:40  -dark-   
@ 温小贝
你那已经出来。h了吗,我不用cocopods打静态库的时候好好地,都已经被两个项目用过了,都已经上线通过了,但是现在要升级适配,所以用cocopods方便些,但是。h不出来,郁闷!
  
#30楼   2015-10-13 09:47  温小贝   
@ -dark-
没有.h,我从原先创建的Pods-Classes里面拉出来用的,可是不行,会出现我说的那些问题。 博主是不是转行了,15年问的问题都没有人回答。
你不用cocoapods打包可以解决类库命名冲突吗
  
#31楼   2015-10-13 09:49  温小贝   
@ -dark-
qq 343206288 有空可以互相讨论下
  
#32楼   2015-10-13 10:40  -dark-   
@ 温小贝
我的QQ号760495545,我们已经加了好友了,我的qq昵称坏坏
  
#33楼   2015-12-07 14:25  羊羊羊
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值