使用CocoaPods开发lib库

cocoapods.png

一、前言

上篇文章主要介绍了如何在App中使用CocoaPods引入第三方库,本篇文章将介绍怎样使用CocoaPods进行lib库的开发(lib库指静态库或动态库)。

二、CocoaPods lib 创建

如果还未进行开发,需要利用CocoaPods从零开始创建,那么恭喜你,CocoaPods会为你搭建好整个开发环境。利用pod lib create MyLibrary命令,通过一些向导后,会自动帮你生成lib工程及demo工程。

pod-lib-create.png

生成的工程目录如下:

MyLibrary目录结构.png

MyLibrary.xcworkspace中的结构如下:

MyLibrary.xcworkspace工程目录.png

通过一个小小的命令,我们的工程框架就搭好了,可以在Pods工程里添加代码和文件,来实现我们的功能,然后在MyLibrary工程里可以添加对lib库的测试代码。

三、利用已有工程搭建CocoaPods lib工程

有时候,我们的lib库已经开发很久了,也有相应的demo,只不过想升级一下逼格或xxx的原因,想通过CocoaPods来管理,而不是传统的.xcodeproj.xcworkspace
这种情况下,我们可以直接模仿上面的工程目录,通过编写Podfilepodspec,就可以了。

四、podspec

  • podspec简介

podspecpod specification的缩写。通过上面的展示,已经可以知道podspec是对lib库的配置文件,Podfile会根据该文件进行文件的加载,所以,podspec的编写也是非常重要的。

  • podspec创建

podspec的创建跟Podfile一样,可以自己手动新建一个文件,然后后缀改为.podspec。也可以命令行执行pod spec create MyLibrary

  • podspec编写

Podfile一样,podspec也有一套自己的语法(官网介绍)。

#一个podspec文件包含一个Spec和若干个subspec,podfile可以引入整个podspec或subspec
Pod::Spec.new do |s|

  #Pod的名称,必填,如Podfile中pod 'AFNetworking',AFNetworking就是name
  s.name         = "MyLibrary"      s.version      = "0.0.1"  #版本,必填

  #简介,必填
  s.summary      = "A short description of library."  

  #详细的描述,支持多行字符串,必填
  s.description  = <<-DESC
                Add long description of the pod here.
                   DESC  

  #主页,必填
  s.homepage     = "http://EXAMPLE/MyLibrary"  

  #遵守的开源协议,必填。注意GPL可能给公司带来很大风险,不要轻易使用
  s.license      = "MIT"  

  #pod库作者,必填
  s.author             = { "wangbingwf" => "wangbingwf@163.com" }  

  #平台版本信息,这里表示支持iOS,7.0及以上系统
  s.platform     = :ios, "7.0"    

  #当支持多平台时,使用deployment_target替代platform
  #s.osx.deployment_target = '8.0'  

  #代码路径,这里虽然填写的是git仓库的路径,但Podfile中使用path方式引入podspec时,并不会再从git上下载代码,而是使用本地的代码,所以就可以在这种方式下开发lib库。
  #这里支持git,svn,http等。并且可以设置tag或version等信息
  s.source       = { :git => "https://git.coding.net/yourgit/MyLibrary.git", :tag => s.version.to_s} 

  # ———— Subspecs ————————————————————————————————————#
  # ———— MyLibraryCFiles ———————————————————————————————#
  #创建一个subspec
   s.subspec 'MyLibraryCFiles' do |subcfiles|

    #subspec包含的代码文件,上面source是路径,这里source_files是具体要包含哪些文件
    #其中**表示包含子目录,*表示当前目录下的所有文件
    #下面表示当前subspec包含MyLibrary/cfiles目录及其子目录中的所有.h和.c文件;以及MyLibrary/log目录下的所有.h和.c文件
    subcfiles.source_files = ["MyLibrary/cfiles/**/*.{h,c}",
                              "MyLibrary/log/*.{h,c}"]

    #不包含的文件
    subcfiles.exclude_files = ["MyLibrary/jni/**/*",
                            "MyLibrary/profile/unit_test/*"]

    #加入到pod库中,被一起编译
    #这里通常使用私有第三方库时,需要依赖某个lib或framework时使用。
    #添加如下选项后,会将.a添加到工程中,并且添加LIBRARY_SEARCH_PATHS路径
    #但是需要注意的是,如果使用pod package对该pod库进行打包,这个.a并不会打进去。
    #比如说使用pod package对MyLibrary打包成MyLibrary.a,inner.a并不会被编译进MyLibrary.a。
    #此时,如果如果对外提供MyLibrary.a,inner.a也同样需要提供出去
    subcfiles.vendored_libraries = "MyLibrary/lib/ios/inner.a"

    #pod工程的配置
    #对于HEADER_SEARCH_PATHS,对将设置的字符串直接拷贝到xcode中,不会像上面source_files这样使用相对路径。
    #所以,我在这里先获取当前路径,再设置进去。最后加**表示recursive,即循环查找子目录的意思
    $dir = File.dirname(__FILE__)
    $dir = $dir + "/MyLibrary/cfiles/**"  #$dir:/Users/wangbing/TempCode/MyLibrary/cfiles/**
    subcfiles.pod_target_xcconfig = { "HEADER_SEARCH_PATHS" => $dir}

    #demo工程的配置,上面是对pod工程的设置,当需要对demo工程设置时,使用user_target_xcconfig,这里就不做介绍了

    #相对于public_headers,这些文件不会被公开给Demo
    subcfiles.private_header_files = "MyLibrary/cfiles/**/*.h"
    #保护目录结构不变,如果不设置,所有头文件都将被放到同一个目录下
    subcfiles.header_mappings_dir = "MyLibrary/cfiles/**"
    end

# ———— MyLibraryMain ———————————————————————————————#
  #创建一个subspec
  s.subspec 'MyLibraryMain' do |submain|

    #引入代码文件
    submain.source_files = "MyLibrary/main/**/*.{h,m}"

    #设置公开头文件
    submain.public_header_files = "MyLibrary/main/public.h"

    #设置资源文件
    submain.resource  = "MyLibrary/resources/configFiles.bundle"

    #设置MyLibraryMain模块依赖的系统库,注意,这里加的是系统库
    submain.frameworks = "SystemConfiguration"

    #设置依赖,这里可以依赖当前spec中的subspec,也可以依赖github上公开的开源库,如'AFNetworking'。
    submain.dependency "MyLibrary/MyLibraryCFiles"
    end
end
  • podspec坑

  • 坑——HEADER_SEARCH_PATHS
    在我实际项目使用过程中,C文件的存在给我编写spec带来了很大问题。
    故事是这样的,我们项目中要引用另一个团队编写的.a库,暂且称为inner.a。这个库是C写的,同时,头文件中存在多层嵌套。
    这要求在使用该静态库时,要在HEADER_SEARCH_PATHS中添加头文件的路径。
    于是我一开始在podspec中是这么写的
subcfiles.pod_target_xcconfig = { "HEADER_SEARCH_PATHS" =>"MyLibrary/cfiles/**"}

于是,编译出错了,找不到头文件,因为这个设置在xcode中是这样的:

HEADER_SEARCH_PATHS

Shit!为什么不像上面似的,给加相对路径呢,毕竟是路径的设置嘛。但是也可以解决的,解决方案有三:

  1. 如果知道Demo工程和lib库之间的路径关系,可以通过${PODS_ROOT}/../../MyLibrary/cfiles/**来解决。
  2. 通过设置绝对路径来解决:
    podspec中使用ruby脚本,获取当前路径,而podspeclib库的位置一般不会变,所以最终使用了这种方式来设置HEADER_SEARCH_PATHS
$dir = File.dirname(__FILE__)
$dir = $dir + "/MyLibrary/cfiles/**"  #$dir:/Users/wangbing/TempCode/MyLibrary/cfiles/**
subcfiles.pod_target_xcconfig = { "HEADER_SEARCH_PATHS" => $dir}
  1. 利用CocoaPods总会添加的两个默认路径,设置header_mappings_dir保护目录结构不发生变化。
#设置cfiles及子目录结构保持不变
subcfiles.header_mappings_dir = "MyLibrary/cfiles/**"

#将这些文件设置为private_file或public_file
subcfiles.private_header_files = "MyLibrary/cfiles/**/*.h"

#因为我的C头文件有嵌套,需要查找子目录,所以需要将non-recursive改为recursive
subcfiles.pod_target_xcconfig = { "HEADER_SEARCH_PATHS" => "${PODS_ROOT}/Headers/Private/**"}

通过方法3同样使用了${PODS_ROOT},与方法1有什么区别呢?区别就是,如果按照方法3,可以忽略Demo工程与lib库的路径关系。因为在执行pod install后,系统会在Pods工程目录下生成PrivatePublic目录,就不用考虑原来cfiles的路径了,如下图。

cfiles目录

五、CocoaPods打包静态库

如果你开发的SDK并不想开源,那么在通过CocoaPods管理并开发之后,还可以通过CocoaPods进行打包。生成framework.a。打包命令是pod package

pod package

像上面的例子中,我的打包命令为:pod package MyLibrary.podspec --force --no-mangle --embedded --subspecs= MyLibraryMain。然后将生成的framework和inner.a共同交给使用者使用即可。

这里需要注意

  1. 打包命令会根据podspec文件下载代码到一个临时文件中进行打包,并不是使用的本地文件,所以记得要提交并打tag。
  2. 上面的HEADER_SEARCH_PATHS问题,使用方法1和方法2同样会导致pod package失败。因为你不知道cfiles的路径,无法添加到HEADER_SEARCH_PATHS。但却可以使用方法3!
  3. podspec文件中使用vendor标识的frameworklibraries,并不会真正编译到最终的framework中。这真的很让我受伤,我查了好久。。。好久。。。好久。。。也正因为这个问题,我决定放弃pod package方式。准备尝试自己写个脚本进行打包,还在准备中。。。

六、总结

研究CocoaPods的初衷是为了组件化开发,目前算是有了一点初步的认识。
我们把不同的功能模块放在不同的文件夹中,通过podspec进行配置,通过podfile进行引用,通过pod package进行打包。一切是很方便的。
不过在我的实际应用中,目前在打包和public_headers方面还有一些问题,I'm working on it!

最后,大家有疑惑的可以留言,写的有问题的欢迎纠正!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,080评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,422评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,630评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,554评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,662评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,856评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,014评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,752评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,212评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,541评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,687评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,347评论 4 331
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,973评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,777评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,006评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,406评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,576评论 2 349

推荐阅读更多精彩内容