一漏设、前言
上篇文章主要介紹了如何在App中使用CocoaPods
引入第三方庫(kù),本篇文章將介紹怎樣使用CocoaPods
進(jìn)行lib
庫(kù)的開(kāi)發(fā)(lib
庫(kù)指靜態(tài)庫(kù)或動(dòng)態(tài)庫(kù))。
二盟榴、CocoaPods lib 創(chuàng)建
如果還未進(jìn)行開(kāi)發(fā),需要利用CocoaPods
從零開(kāi)始創(chuàng)建婴噩,那么恭喜你擎场,CocoaPods
會(huì)為你搭建好整個(gè)開(kāi)發(fā)環(huán)境。利用pod lib create MyLibrary
命令几莽,通過(guò)一些向?qū)Ш笱赴欤瑫?huì)自動(dòng)幫你生成lib工程及demo工程。
生成的工程目錄如下:
MyLibrary.xcworkspace中的結(jié)構(gòu)如下:
通過(guò)一個(gè)小小的命令章蚣,我們的工程框架就搭好了站欺,可以在Pods工程里添加代碼和文件,來(lái)實(shí)現(xiàn)我們的功能纤垂,然后在MyLibrary工程里可以添加對(duì)lib庫(kù)的測(cè)試代碼矾策。
三、利用已有工程搭建CocoaPods lib工程
有時(shí)候峭沦,我們的lib
庫(kù)已經(jīng)開(kāi)發(fā)很久了贾虽,也有相應(yīng)的demo
,只不過(guò)想升級(jí)一下逼格或xxx的原因吼鱼,想通過(guò)CocoaPods
來(lái)管理蓬豁,而不是傳統(tǒng)的.xcodeproj
或.xcworkspace
绰咽。
這種情況下,我們可以直接模仿上面的工程目錄地粪,通過(guò)編寫(xiě)Podfile
和podspec
取募,就可以了。
四驶忌、podspec
-
podspec簡(jiǎn)介
podspec
是pod specification
的縮寫(xiě)矛辕。通過(guò)上面的展示,已經(jīng)可以知道podspec
是對(duì)lib
庫(kù)的配置文件付魔,Podfile
會(huì)根據(jù)該文件進(jìn)行文件的加載聊品,所以,podspec
的編寫(xiě)也是非常重要的几苍。
-
podspec創(chuàng)建
podspec的創(chuàng)建跟Podfile一樣翻屈,可以自己手動(dòng)新建一個(gè)文件,然后后綴改為.podspec
妻坝。也可以命令行執(zhí)行pod spec create MyLibrary
伸眶。
-
podspec編寫(xiě)
像Podfile
一樣,podspec
也有一套自己的語(yǔ)法(官網(wǎng)介紹)刽宪。
#一個(gè)podspec文件包含一個(gè)Spec和若干個(gè)subspec厘贼,podfile可以引入整個(gè)podspec或subspec
Pod::Spec.new do |s|
#Pod的名稱(chēng),必填圣拄,如Podfile中pod 'AFNetworking'嘴秸,AFNetworking就是name
s.name = "MyLibrary" s.version = "0.0.1" #版本,必填
#簡(jiǎn)介庇谆,必填
s.summary = "A short description of library."
#詳細(xì)的描述岳掐,支持多行字符串,必填
s.description = <<-DESC
Add long description of the pod here.
DESC
#主頁(yè)饭耳,必填
s.homepage = "http://EXAMPLE/MyLibrary"
#遵守的開(kāi)源協(xié)議串述,必填。注意GPL可能給公司帶來(lái)很大風(fēng)險(xiǎn)寞肖,不要輕易使用
s.license = "MIT"
#pod庫(kù)作者纲酗,必填
s.author = { "wangbingwf" => "wangbingwf@163.com" }
#平臺(tái)版本信息,這里表示支持iOS新蟆,7.0及以上系統(tǒng)
s.platform = :ios, "7.0"
#當(dāng)支持多平臺(tái)時(shí)耕姊,使用deployment_target替代platform
#s.osx.deployment_target = '8.0'
#代碼路徑,這里雖然填寫(xiě)的是git倉(cāng)庫(kù)的路徑栅葡,但Podfile中使用path方式引入podspec時(shí)茉兰,并不會(huì)再?gòu)膅it上下載代碼,而是使用本地的代碼欣簇,所以就可以在這種方式下開(kāi)發(fā)lib庫(kù)规脸。
#這里支持git坯约,svn,http等莫鸭。并且可以設(shè)置tag或version等信息
s.source = { :git => "https://git.coding.net/yourgit/MyLibrary.git", :tag => s.version.to_s}
# ———— Subspecs ————————————————————————————————————#
# ———— MyLibraryCFiles ———————————————————————————————#
#創(chuàng)建一個(gè)subspec
s.subspec 'MyLibraryCFiles' do |subcfiles|
#subspec包含的代碼文件闹丐,上面source是路徑,這里source_files是具體要包含哪些文件
#其中**表示包含子目錄被因,*表示當(dāng)前目錄下的所有文件
#下面表示當(dāng)前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庫(kù)中,被一起編譯
#這里通常使用私有第三方庫(kù)時(shí)梨与,需要依賴(lài)某個(gè)lib或framework時(shí)使用堕花。
#添加如下選項(xiàng)后,會(huì)將.a添加到工程中粥鞋,并且添加LIBRARY_SEARCH_PATHS路徑
#但是需要注意的是缘挽,如果使用pod package對(duì)該pod庫(kù)進(jìn)行打包,這個(gè).a并不會(huì)打進(jìn)去呻粹。
#比如說(shuō)使用pod package對(duì)MyLibrary打包成MyLibrary.a壕曼,inner.a并不會(huì)被編譯進(jìn)MyLibrary.a。
#此時(shí)等浊,如果如果對(duì)外提供MyLibrary.a腮郊,inner.a也同樣需要提供出去
subcfiles.vendored_libraries = "MyLibrary/lib/ios/inner.a"
#pod工程的配置
#對(duì)于HEADER_SEARCH_PATHS,對(duì)將設(shè)置的字符串直接拷貝到xcode中筹燕,不會(huì)像上面source_files這樣使用相對(duì)路徑轧飞。
#所以,我在這里先獲取當(dāng)前路徑庄萎,再設(shè)置進(jìn)去踪少。最后加**表示recursive塘安,即循環(huán)查找子目錄的意思
$dir = File.dirname(__FILE__)
$dir = $dir + "/MyLibrary/cfiles/**" #$dir:/Users/wangbing/TempCode/MyLibrary/cfiles/**
subcfiles.pod_target_xcconfig = { "HEADER_SEARCH_PATHS" => $dir}
#demo工程的配置糠涛,上面是對(duì)pod工程的設(shè)置,當(dāng)需要對(duì)demo工程設(shè)置時(shí)兼犯,使用user_target_xcconfig忍捡,這里就不做介紹了
#相對(duì)于public_headers,這些文件不會(huì)被公開(kāi)給Demo
subcfiles.private_header_files = "MyLibrary/cfiles/**/*.h"
#保護(hù)目錄結(jié)構(gòu)不變切黔,如果不設(shè)置砸脊,所有頭文件都將被放到同一個(gè)目錄下
subcfiles.header_mappings_dir = "MyLibrary/cfiles/**"
end
# ———— MyLibraryMain ———————————————————————————————#
#創(chuàng)建一個(gè)subspec
s.subspec 'MyLibraryMain' do |submain|
#引入代碼文件
submain.source_files = "MyLibrary/main/**/*.{h,m}"
#設(shè)置公開(kāi)頭文件
submain.public_header_files = "MyLibrary/main/public.h"
#設(shè)置資源文件
submain.resource = "MyLibrary/resources/configFiles.bundle"
#設(shè)置MyLibraryMain模塊依賴(lài)的系統(tǒng)庫(kù),注意纬霞,這里加的是系統(tǒng)庫(kù)
submain.frameworks = "SystemConfiguration"
#設(shè)置依賴(lài)凌埂,這里可以依賴(lài)當(dāng)前spec中的subspec,也可以依賴(lài)github上公開(kāi)的開(kāi)源庫(kù)诗芜,如'AFNetworking'瞳抓。
submain.dependency "MyLibrary/MyLibraryCFiles"
end
end
-
podspec坑
-
坑——HEADER_SEARCH_PATHS
在我實(shí)際項(xiàng)目使用過(guò)程中埃疫,C
文件的存在給我編寫(xiě)spec
帶來(lái)了很大問(wèn)題。
故事是這樣的孩哑,我們項(xiàng)目中要引用另一個(gè)團(tuán)隊(duì)編寫(xiě)的.a
庫(kù)栓霜,暫且稱(chēng)為inner.a
。這個(gè)庫(kù)是C
寫(xiě)的横蜒,同時(shí)胳蛮,頭文件中存在多層嵌套。
這要求在使用該靜態(tài)庫(kù)時(shí)丛晌,要在HEADER_SEARCH_PATHS
中添加頭文件的路徑仅炊。
于是我一開(kāi)始在podspec中是這么寫(xiě)的
subcfiles.pod_target_xcconfig = { "HEADER_SEARCH_PATHS" =>"MyLibrary/cfiles/**"}
于是,編譯出錯(cuò)了茵乱,找不到頭文件茂洒,因?yàn)檫@個(gè)設(shè)置在xcode中是這樣的:
Shit!為什么不像上面似的,給加相對(duì)路徑呢瓶竭,畢竟是路徑的設(shè)置嘛督勺。但是也可以解決的,解決方案有三:
- 如果知道Demo工程和lib庫(kù)之間的路徑關(guān)系斤贰,可以通過(guò)
${PODS_ROOT}/../../MyLibrary/cfiles/**
來(lái)解決智哀。 - 通過(guò)設(shè)置絕對(duì)路徑來(lái)解決:
在podspec
中使用ruby
腳本,獲取當(dāng)前路徑荧恍,而podspec
和lib
庫(kù)的位置一般不會(huì)變瓷叫,所以最終使用了這種方式來(lái)設(shè)置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}
- 利用
CocoaPods
總會(huì)添加的兩個(gè)默認(rèn)路徑送巡,設(shè)置header_mappings_dir保護(hù)目錄結(jié)構(gòu)不發(fā)生變化摹菠。
#設(shè)置cfiles及子目錄結(jié)構(gòu)保持不變
subcfiles.header_mappings_dir = "MyLibrary/cfiles/**"
#將這些文件設(shè)置為private_file或public_file
subcfiles.private_header_files = "MyLibrary/cfiles/**/*.h"
#因?yàn)槲业腃頭文件有嵌套,需要查找子目錄骗爆,所以需要將non-recursive改為recursive
subcfiles.pod_target_xcconfig = { "HEADER_SEARCH_PATHS" => "${PODS_ROOT}/Headers/Private/**"}
通過(guò)方法3同樣使用了${PODS_ROOT}
次氨,與方法1有什么區(qū)別呢?區(qū)別就是摘投,如果按照方法3煮寡,可以忽略Demo工程與lib庫(kù)的路徑關(guān)系。因?yàn)樵趫?zhí)行pod install
后犀呼,系統(tǒng)會(huì)在Pods
工程目錄下生成Private
和Public
目錄幸撕,就不用考慮原來(lái)cfiles
的路徑了,如下圖外臂。
五坐儿、CocoaPods打包靜態(tài)庫(kù)
如果你開(kāi)發(fā)的SDK并不想開(kāi)源,那么在通過(guò)CocoaPods管理并開(kāi)發(fā)之后,還可以通過(guò)CocoaPods進(jìn)行打包貌矿。生成framework
或.a
累铅。打包命令是pod package
。
像上面的例子中站叼,我的打包命令為:pod package MyLibrary.podspec --force --no-mangle --embedded --subspecs= MyLibraryMain
娃兽。然后將生成的framework和inner.a共同交給使用者使用即可。
這里需要注意:
- 打包命令會(huì)根據(jù)
podspec
文件下載代碼到一個(gè)臨時(shí)文件中進(jìn)行打包尽楔,并不是使用的本地文件铃彰,所以記得要提交并打tag膘魄。 - 上面的
HEADER_SEARCH_PATHS
問(wèn)題瑞妇,使用方法1和方法2同樣會(huì)導(dǎo)致pod package
失敗始腾。因?yàn)槟悴恢?code>cfiles的路徑,無(wú)法添加到HEADER_SEARCH_PATHS
呕寝。但卻可以使用方法3! -
podspec
文件中使用vendor
標(biāo)識(shí)的framework
或libraries
勋眯,并不會(huì)真正編譯到最終的framework
中。這真的很讓我受傷下梢,我查了好久客蹋。。孽江。好久讶坯。。岗屏。好久辆琅。。这刷。也正因?yàn)檫@個(gè)問(wèn)題婉烟,我決定放棄pod package
方式。準(zhǔn)備嘗試自己寫(xiě)個(gè)腳本進(jìn)行打包暇屋,還在準(zhǔn)備中似袁。。率碾。
六叔营、總結(jié)
研究CocoaPods
的初衷是為了組件化開(kāi)發(fā)屋彪,目前算是有了一點(diǎn)初步的認(rèn)識(shí)所宰。
我們把不同的功能模塊放在不同的文件夾中,通過(guò)podspec
進(jìn)行配置畜挥,通過(guò)podfile
進(jìn)行引用仔粥,通過(guò)pod package
進(jìn)行打包。一切是很方便的。
不過(guò)在我的實(shí)際應(yīng)用中躯泰,目前在打包和public_headers
方面還有一些問(wèn)題谭羔,I'm working on it!
最后,大家有疑惑的可以留言麦向,寫(xiě)的有問(wèn)題的歡迎糾正瘟裸!