怎樣在swift中創(chuàng)建一個(gè)CocoaPods
你可能對一些比較著名的開源的CocoaPods框架比較熟悉,比如Alamofire、MBProgressHUD。但是有時(shí)你可能找不到剛好滿足你需求的pod,也或者你需要把一個(gè)大的項(xiàng)目拆分成小的,可重用的組件。
幸運(yùn)的是,創(chuàng)建你自己的CocoaPods是件很容易的事!
如果你已經(jīng)為你的組件創(chuàng)建了一個(gè)Cocoa Touch框架,你已經(jīng)完成了大多數(shù)的比較難的工作。如果你沒有也不要害怕,因?yàn)樗€是很簡單的。
如果你只是曾經(jīng)創(chuàng)建過iOS app的類的話,那也是可以的。你可以簡單地通過拖拽類或者方法來創(chuàng)建新的pod,這對你專屬的使用會(huì)很有意義。
這篇教程是開端,How to Use CocoaPods with Swift(中文 英文)是結(jié)束。如果你之前從沒用過cocoaPods,那么這篇文章絕對是你學(xué)習(xí)的前提。
因此,來一杯熱可可開始學(xué)習(xí)吧!
開始
你的首要客戶是冰淇淋公司。他們的冰淇淋太受歡迎了以至于不能在柜臺(tái)接收用戶訂單了。他們雇傭你來做一個(gè)漂亮的iOS應(yīng)用,那樣就能讓用戶在他們的iPhone上下訂單了。你開始開發(fā)app了,并且進(jìn)展得還不錯(cuò)。
在這里下載開始程序-------這是教程 How to Use CocoaPods with Swift(中文 英文)里的最終版本。
app已經(jīng)有幾個(gè)pod依賴文件在下載中,所以你不需要運(yùn)行pod install來安裝它們。
注意:如果你已經(jīng)學(xué)習(xí)了 How to Use CocoaPods with Swift(中文 英文),那么接下來的部分看起來可能比較熟悉----只是對那篇教程的復(fù)習(xí)。所以可以根據(jù)自己的情況跳過一部分。打開 IceCreamShop.xcworkspace,然后是Main.storyboard,找到Views\Storyboards & Nibs這個(gè)分組,看看app是怎樣布局的。
下面是對選擇口味場景的一個(gè)大致了解,這是這個(gè)應(yīng)用的核心:
- PickFlavorViewController: 處理用戶交互,比如用戶選擇了一個(gè)冰淇淋口味。
- PickFlavorDataSource: 是展示冰淇淋口味的collectionview的數(shù)據(jù)源。
- IceCreamView:是一個(gè)自定義的view,可以用來展示一種冰淇淋,并且它以Falvor這個(gè)模型來支撐。
- ScoopCell:是一個(gè)自定義的collectionviewcell,它包含了一個(gè)ScoopView,這個(gè)view也是以Flavor這個(gè)model類來支撐的。
冰淇淋店的高層管理者很喜歡現(xiàn)在的app,但是他們又添加了一些新的需求:冰淇淋零售商需要在他們的app中有選擇個(gè)人口味的功能。等等,那沒有在最初的設(shè)計(jì)中。但是對于像你這樣厲害的開發(fā)者這沒有問題!
你能猜到怎么做嗎?是的,你需要在他自己的cocoapod中拉入這個(gè)方法。
配置你自己的pod
創(chuàng)建一個(gè)Xcode工程并且選擇iOS\Framework & Library\Cocoa TouchFramework,然后點(diǎn)擊下一步
輸入RWPickFlavor作為產(chǎn)品名字并且選擇Swift作為開發(fā)語言。選擇下一步。
這篇教程需要你將你的工程創(chuàng)建在~/Documents/Libraries目錄下.在你的主目錄下選擇Documents文件夾。如果你沒有Libraries文件夾,在底部點(diǎn)擊New Folder按鈕并且創(chuàng)建它。
最后,選擇Libraries文件夾并且點(diǎn)擊創(chuàng)建。
你保存你的pod的目錄是很重要的因?yàn)樵诒镜亻_發(fā)期間你需要在podFile中參考你的目錄。
通常,當(dāng)你使用CocoaPods,你會(huì)像下面那樣將依賴性文件加入你的Podfile中
- pod 'PodName', '~> 1.0'
但是當(dāng)你在開發(fā)自己的CocoaPod,你卻需要指明一個(gè)本地的路徑,就像這樣:
- pod 'MyPodName', :path => '~/Path/To/Folder/Containing/My/Pod'
這種方法有兩個(gè)好處:
- 它會(huì)使用在你電腦上的對應(yīng)的pod的本地文件,而不用從遠(yuǎn)端目錄下抓取。
- 通常,你不會(huì)修改加入到你的app中的pod,因?yàn)檫@些修改會(huì)在下次你運(yùn)行pod install的時(shí)候被覆蓋掉,因?yàn)閜od會(huì)從遠(yuǎn)端目錄下重新獲取并且你修改的資源文件也會(huì)被覆蓋。通過使用:path => syntax,你可以輕松地修改開發(fā)中的pod而不會(huì)被這個(gè)過程覆蓋,因?yàn)槟莻€(gè)路徑就是現(xiàn)在CocoaPod的來源,因此當(dāng)你再次運(yùn)行pod install的時(shí)候這些修改不會(huì)丟失。
然而你可以為你在開發(fā)的pods使用不同的路徑,一般我建議將他們放在~/Documents/Libraries下。如果你有一個(gè)團(tuán)隊(duì)在開發(fā)的話這也是一個(gè)很好的位置,因?yàn)閏ocoapods知道把“~”擴(kuò)展為用戶的目錄。因此你不需要在podFile中寫很復(fù)雜的代碼來表示絕對路徑。
你也可以在你創(chuàng)建的cocoapod中引用其他的cocoapod作為依賴性文件-你只需要一個(gè)podFile來管理你的cocoaPods依賴性文件。
關(guān)閉Xcode,然后在終端中輸入下面的命令行:
- cd ~/Documents/Libraries/RWPickFlavor
- pod init
- open -a Xcode Podfile
這就創(chuàng)建了一個(gè)新的podFile并且在Xcode中打開它。
用下面的內(nèi)容替換新的podFile中的內(nèi)容:
- platform :ios, '8.0'
- use_frameworks!
- target 'RWPickFlavor' do
- pod 'Alamofire', '~> 1.2'
- pod 'MBProgressHUD', '~> 0.9.0'
- end
這就聲明了RWPickerFlavor有外部依賴性文件Alamofire和MBProgressHUD。
保存并且關(guān)閉podFile,然后在終端中輸入下面的命令行:
- pod install
正如你希望的那樣,這就會(huì)創(chuàng)建一個(gè)workspace并且安裝各種必需的文件
注意:如果pod install命令給出了任何警告,那么你有可能用的是一個(gè)老版本的Cocoapods。基于swift語言的cocoapods,例如Alamofire,要求cocoapods版本在0.36.0及以上。你可以嘗試在終端中輸入以下命令來查看你的cocoapods版本:
- pod --version
如果是那個(gè)問題的話,在終端中輸入如下命令來安裝cocoapods的最新版本:
- sudo gem install CocoaPods
輸入以下命令行打開新創(chuàng)建的RWPickFlavor workspace:
- open RWPickflavor.xcworkspace
你的項(xiàng)目導(dǎo)航欄現(xiàn)在看起來應(yīng)該是這樣的:
現(xiàn)在你需要將 IceCreamShop workspace中的幾個(gè)文件拷貝到RWPickFlavor中。
#p#
首先,在 RWPickFlavor.xcworkspace 中創(chuàng)建下面的分組來歸類你將要拷貝的文件:
- Categories
- Controllers
- Factories
- Models
- Views(Ice Cream,Storyboards & Nibs)
從IceCreamShop.xcworkspace中的分組到對應(yīng)的RWPickFlavor.xcworkspace 中的分組,對所有的文件執(zhí)行拖拽并放開的操作 - 除了AppDelegate.swift 和LaunchScreen.xib,就像下面那樣:
如果有提示跳出,要保證Copy items if needed這個(gè)選項(xiàng)被確認(rèn)過了,這樣所有的文件才是真正被拷貝而不是簡單地鏈接。當(dāng)你完成以后,RWPickFlavor 應(yīng)該有下面的文件:
一旦你確定了所有的文件都已經(jīng)被拷貝過來了,從IceCreamShop中刪除所有的originals和任何空的分組,只剩下RWPickFlavor中的文件。小心不要?jiǎng)h除下面這些:
- AppDelegate.swift
- LaunchScreen.xib
- Images.xcassets
- Supporting Files 分組下的任何文件
現(xiàn)在打開Info.plist,在Supporting Files那個(gè)分組下,找到Main storyboard file base name那一行并刪除。
編譯運(yùn)行,應(yīng)該不會(huì)有錯(cuò)的,最終你會(huì)看到黑色的屏幕上顯示著 “Ice Cream Shop”的logo。
那么圖片呢?
你可能已經(jīng)注意到了你沒有拷貝Resources分組,這是因?yàn)槟阒恍枰截恇ackground.jpg這個(gè)圖片本身到RWPickFlavor的Resources文件夾下,不是整個(gè)的Images.xcassets文件。
首先,你在RWPickFlavor中創(chuàng)建一個(gè)Resources分組。
然后,在IceCreamShop中選擇 Images.xcassets,選中background右擊并選擇Show in Finder,就像下面那樣:
現(xiàn)在把background.png從finder中拖拽到RMPickFlavor的resources分組中。當(dāng)有彈出提示時(shí),再次選中Copy items if needed選項(xiàng)。當(dāng)你已經(jīng)拷貝了圖片,從IceCreamShop的Image.xcassets中刪除原始的background圖片。
最后,在Main.storyboard的Choose Your Flavor場景中的RMPickFlavor類里更新imageview的圖片,這樣他就指向了圖片background.jpg而不是background。
不管你信不信,創(chuàng)建你的pod的最困難的部分已經(jīng)完成了。
CocoaPods和Git
由于cocoapod是部署在git上面的, 每一個(gè)pod都需要有它自己的git目錄.如果你已經(jīng)有了git主機(jī),你可以用它來放你的目錄。
如果沒有,Github是一個(gè)很不錯(cuò)的選擇,因?yàn)樗槐姸嗟拈_發(fā)者所了解并且對開源的項(xiàng)目免費(fèi)。
Bitbucket是另外一個(gè)不錯(cuò)的選擇,它是免費(fèi)的并且沒有限制的,包括私有的目錄,可以供達(dá)5個(gè)開發(fā)人員共同開發(fā)。
這個(gè)教程使用了github,但是你也可以用你自己的git服務(wù)器。
GitHub目錄設(shè)置
下一步,點(diǎn)擊屏幕右上角的+(創(chuàng)建新的)圖標(biāo)并且選擇下方的New repository.
輸入RMPickFlavor作為目錄名,并且選擇Create repository。
Github將在你的賬戶下面創(chuàng)建一個(gè)新的目錄,然后你將看到一個(gè)下面屏幕所示的Quick setup所展示的你的目錄URL:
你將在某一時(shí)刻需要這個(gè)URL,所以保持這個(gè)頁面打開。
現(xiàn)在你需要第二個(gè)目錄來放你的私有pod規(guī)范 - 之后你將在這篇教程中用到它。
在一個(gè)新的標(biāo)簽頁中打開github.com;再次點(diǎn)擊Create New圖標(biāo)并選擇New repository。將這個(gè)目錄取名為RWPodSpecs,并選擇Create repository。
保持這個(gè)標(biāo)簽頁打開之后在你需要這個(gè)URL的時(shí)候你可以輕松獲取。
#p#
Podspec設(shè)置
現(xiàn)在你需要為RMPickFlavor創(chuàng)建一個(gè)RWPickFlavor.podspec文件。這個(gè)Podspec文件包含了一些基本的信息,比如pod的名字、版本和git下載URL.
在終端中輸入下面的命令行,在每一行輸入enter鍵。
- cd ~/Documents/Libraries/RWPickFlavor
- pod spec create RWPickFlavor
- open -a Xcode RWPickFlavor.podspec
這就創(chuàng)建了RWPickFlavor.podspec,在Xcode中打開。
在默認(rèn)的podspec文件中有很多不錯(cuò)的文檔和例子 - 然而,你不需要所有的這些。
用下面的內(nèi)容代替RWPickFlavor.podspec中的所有內(nèi)容
- # 1
- s.platform = :ios
- s.ios.deployment_target = '8.0'
- s.name = "RWPickFlavor"
- s.summary = "RWPickFlavor lets a user select an ice cream flavor."
- s.requires_arc = true
- # 2
- s.version = "0.1.0"
- # 3
- s.license = { :type => "MIT", :file => "LICENSE" }
- # 4 - Replace with your name and e-mail address
- s.author = { "[Your Name Goes Here]" => "[Your_Email@Your_Email_Domain.com]" }
- # For example,
- # s.author = { "Joshua Greene" => "jrg.developer@gmail.com" }
- # 5 - Replace this URL with your own Github page's URL (from the address bar)
- s.homepage = "[Your RWPickFlavor Homepage URL Goes Here]"
- # For example,
- # s.homepage = "https://github.com/JRG-Developer/RWPickFlavor"
- # 6 - Replace this URL with your own Git URL from "Quick Setup"
- s.source = { :git => "[Your RWPickFlavor Git URL Goes Here]", :tag => "#{s.version}"}
- # For example,
- # s.source = { :git => "https://github.com/JRG-Developer/RWPickFlavor.git", :tag => "#{s.version}"}
- # 7
- s.framework = "UIKit"
- s.dependency 'Alamofire', '~> 1.1'
- s.dependency 'MBProgressHUD', '~> 0.9.0'
- # 8
- s.source_files = "RWPickFlavor/**/*.{swift}"
- # 9
- s.resources = "RWPickFlavor/**/*.{png,jpeg,jpg,storyboard,xib}"
- end
正如podFile一樣,podspec也是用Ruby寫的。千萬小字不要出現(xiàn)打字錯(cuò)誤,否則pod可能會(huì)出現(xiàn)確認(rèn)或者安裝失敗的情況。
下面是正在進(jìn)行的:
1.首先你要寫清楚pod的基本信息?;赟wift的cocppods的部署目標(biāo)必須在iOS8.0及以上。如果你給了一個(gè)更低的版本,pod就不能正確安裝了。
2.podSpec實(shí)際上就是你的cocoapod的一個(gè)及時(shí)的截屏,并且用版本號(hào)來標(biāo)記。當(dāng)你更新一個(gè)pod,你也需要更新podspec的版本。所有的cocoapods都最好使用語義化版本號(hào)。如果你對Semantic Versioning不熟悉,請看How to Use CocoaPods with Swift
3.所有的pods都必須制定一個(gè)許可證。如果你沒有的話,當(dāng)你視圖安裝的時(shí)候cocoapods會(huì)給你一個(gè)警告,并且你也不能把它上傳到cocoapods trunk---specs目錄下。
4.然后請寫明你自己的信息,這是pod的作者。在占位文字的地方輸入你的名字和e-mail地址。
5.現(xiàn)在你需要在你pod的主頁上寫明URL。你可以就從你的github主頁的瀏覽器的地址欄里面拷貝并粘貼地址。
6.將這個(gè)URL替換為上面你創(chuàng)建的第一個(gè)目錄中的“Quick Setup”部分的git下載URL。通常,最好是使用http:或者h(yuǎn)ttps:開頭的URL,這樣使用的人就更容易明白。你也可以使用SSHurl。但是你需要確認(rèn)你的team中的所有人-無論是誰需要cocoapod的路徑-已經(jīng)有了配置你的git主機(jī)的公開/私密的鍵值對。
7.你要指明框架和任何pod依賴性文件。
8.你需要指明基于文件擴(kuò)展的(public source files)公用資源文件。在這兒,你需要用.swift作為擴(kuò)展。
9.最后,指明基于文件擴(kuò)展的resources。
就像許多其他的pod,你需要?jiǎng)?chuàng)建LICENSE 文件。
復(fù)制這兒的MIT license在你最喜歡的編輯器中,然后保存為LICENSE到~/Documents/Libraries/RWPickFlavor目錄下,沒有擴(kuò)展名。確保將[year]和[fullname]替換為真實(shí)值-啊,當(dāng)然是你的真實(shí)的年份和名字了。
Choose a License是一個(gè)很棒的幫你的項(xiàng)目找到合適的開源license的一個(gè)站點(diǎn),并且由hithub中的一些志愿者進(jìn)行創(chuàng)建和維護(hù)。
上傳至Git
最后你準(zhǔn)備將RMPickerFlavor上傳至git中的新家了。
在終端中輸入下面的命令行,將[Your RWPickFlavor Git URL]替換為你之前創(chuàng)建的RWPickFlavor目錄:
- cd ~/Documents/Libraries/RWPickFlavor
- git init
- git add .
- git commit -m "Initial commit"
- git tag 0.1.0
- git remote add origin [Your RWPickFlavor Git URL]
- git push -u origin master --tags
如果有彈出,輸入你的github的用戶名和密碼。
這就將RWPickFlavor文件夾中的所有文件都提交了,并創(chuàng)建了一個(gè)0.1.0的tag,并且把所有的東西上傳到遠(yuǎn)程目錄中。
恭喜你,你已經(jīng)創(chuàng)建了你的第一個(gè)cocoapod!
你已經(jīng)創(chuàng)建了你的第一個(gè)cocoapod,但是你能使用它嗎?是的,還不一定:
首先你需要將你的podspec添加到一個(gè)私人的specs目錄下;這樣當(dāng)你安裝的時(shí)候cocoapods就能找到pod了。幸運(yùn)的,你已經(jīng)為此創(chuàng)建了一個(gè)git目錄,所以這最后的一步是相對簡單明了的。
輸入下面的命令,要確保你還在 RWPickFlavor 目錄下:
- pod repo add RWPodSpecs [Your RWPodSpecs Git URL]
- pod repo push RWPodSpecs RWPickFlavor.podspec
要確保你已經(jīng)用之前創(chuàng)建的RWPodSpecs 目錄對應(yīng)的git url替換了[Your RWPodSpecs Git URL]
這就在你本地電腦上創(chuàng)建了RWPodSpecs的一個(gè)本地參考并且保存在你的電腦的~/.cocoapods目錄下,將RWPickFlavor.podspec上傳到那里。
需要你有了一個(gè)私人的pod規(guī)范目錄。比你想的要容易,對吧?
使用你的新CocoaPod
這是使用你的新創(chuàng)建的pod的最后時(shí)刻了。
打開IceCreamShop的podfile并且用下面的命令替換它的內(nèi)容
platform :ios, '8.0'
- source 'https://github.com/CocoaPods/Specs.git'
- source '[Your RWPodSpecs Git URL Goes Here]'
- use_frameworks!
- target 'IceCreamShop' do
- pod 'RWPickFlavor', :path => '~/Documents/Libraries/RWPickFlavor'
- end
確保你已經(jīng)用你的RWPodSpecs目錄對應(yīng)的gitURL替換了[Your RWPodSpecs Git URL Goes Here]
然后,在終端中運(yùn)行pod install。
最后,用下面的命令替換AppDelegate.swift中的所有內(nèi)容
- import UIKit
- import RWPickFlavor
- @UIApplicationMain
- class AppDelegate: UIResponder, UIApplicationDelegate {
- var window: UIWindow?
- var rootViewController: UIViewController!
- func application(application: UIApplication, didFinishLaunchingWithOptions
- launchOptions: [NSObject : AnyObject]?) -> Bool {
- setupRootViewController()
- window = UIWindow(frame: UIScreen.mainScreen().bounds)
- window?.rootViewController = rootViewController
- window?.makeKeyAndVisible()
- return true
- }
- func setupRootViewController() {
- let bundle = NSBundle(forClass: PickFlavorViewController.self)
- let storyboard = UIStoryboard(name: "Main", bundle: bundle)
- rootViewController = storyboard.instantiateInitialViewController() as! UIViewController
- }
- }
在setupRootViewController()中,你獲取了對RWPickFlavor包內(nèi)容的參考 ---它其實(shí)是一個(gè)動(dòng)態(tài)的框架--這個(gè)方法創(chuàng)建了Main.storyboard,并且初始化了根視圖
編譯運(yùn)行。看到熟悉的“Choose Your Flavour”你肯定會(huì)很開心。太棒了!
抽象所有的東西!
你如果像我這樣,你可能會(huì)想,“哇,app Delegate 肯定對RWPickFlavor的結(jié)構(gòu)影響很多”。
幸運(yùn)的是,你可以做一些事來降低耦合度:使用BetterBaseClasses,這是一個(gè)可以使其他pods使用更方便的pod。
在RWPickFlavor的pod文件中添加下面的代碼,就在Alamofire的后面:
- pod 'BetterBaseClasses', '~> 1.0'
同樣地,將下面的命令添加到RWPickFlavor.podspec,在Alamofire那一行的下面:
- s.dependency 'BetterBaseClasses', '~> 1.0'
現(xiàn)在用下面的內(nèi)容替換s.version
- s.version = "0.2.0"
現(xiàn)在你要將BetterBaseClasses聲明為一個(gè)依賴,然后and then bumping the version of your CocoaPod.
現(xiàn)在在終端中運(yùn)行pod install來安裝新的依賴性文件。
接下來,將下面的內(nèi)容導(dǎo)入到PickFlavorViewController中,還是在Alamofire的后面:
- import BetterBaseClasses
用下面的內(nèi)容替換類的定義:
- public class PickFlavorViewController: BaseViewController, UICollectionViewDelegate {
這就改變了PickFlavorViewController而使它繼承自BaseViewController,BaseViewController是BetterBaseClasses的一部分。
現(xiàn)在你需要將這些改變推送到你的RWPickFlavor和RWPodSpecs目錄下。在終端中運(yùn)行下面的命令:
- cd ~/Documents/Libraries/RWPickFlavor
- git add .
- git commit -m "Added BetterBaseClasses dependency"
- git tag 0.2.0
- git push origin master --tags
- pod repo push RWPodSpecs RWPickFlavor.podspec
接下來,你需要將這些改變拉取到IceCreamShop中。
更新IceCreamShop的PodFile,用下面的代碼替換pod 'RWPickFlavor'.
- pod 'RWPickFlavor', '~> 0.2.0'
下面你將更新PodFile來獲取你剛剛上傳的RWPickerFlavor的新版本。然后在終端中執(zhí)行pod install在IceCreamShop中跟新新的依賴。
最后,用下面的內(nèi)容替換AppDelegate.swift中的全部內(nèi)容:
- import UIKit
- import RWPickFlavor
- @UIApplicationMain
- class AppDelegate: UIResponder, UIApplicationDelegate {
- var window: UIWindow?
- func application(application: UIApplication, didFinishLaunchingWithOptions
- launchOptions: [NSObject : AnyObject]?) -> Bool {
- window = UIWindow(frame: UIScreen.mainScreen().bounds)
- window?.rootViewController = UINavigationController(rootViewController:
- PickFlavorViewController.instanceFromStoryboard())
- window?.makeKeyAndVisible()
- return true
- }
- }
那就簡單得多了!
BetterBaseClasses在UIViewController,UITableViewController以及其他UIKit類中添加分類。其中包含了一個(gè)叫UIViewController+BetterBaseClasses的分類,這個(gè)分類添加了一些很方便的方法比如 instanceFromStoryboard()使初始化ViewControllers非常簡單,不管它們是在main bundle或者是別的什么地方,就像這個(gè)例子中的框架一樣。
編譯運(yùn)行,這一次,你會(huì)看到熟悉的‘ Choose Your Flavor’。
接下來?
你可以在 這兒 下載到完整的IceCreamShop項(xiàng)目,以及RWPickFlavor pod。
現(xiàn)在你可以開始創(chuàng)建你自己的CocoaPods了!不過,你在這篇教程中學(xué)到的只是在涉及到cocoapod時(shí)的一小部分建議。請下載CocoaPods 指南來學(xué)習(xí)關(guān)于創(chuàng)建cocoapods的所有的內(nèi)容
在你創(chuàng)建了cocoapod之后,你可能會(huì)考慮將它添加到CocoaPods Master Specs Repo中,這樣全世界的開發(fā)者就可以通過CocoaPods.org獲取d熬它了。你可以看看這篇博客來學(xué)習(xí)怎么做CocoaPods Trunk。