CocoaPods是Swift和Objective-C項目依賴管理器,使用CocoaPods可以優雅的擴展你的項目。盡管在iOS、macOS項目中使用CocoaPods是非常常見的,但創建pod卻很少見。通過這篇文章,你將學會如何創建pod,以及優質pod都有哪些共同點。
1. 安裝CocoaPods
必須安裝CocoaPods才可以創建pod。CocoaPods作為Ruby的gem由RubyGems提供。在命令行執行以下命令安裝或更新CocoaPods:
$ sudo gem install cocoapods
使用系統自帶的Ruby安裝CocoaPods時,需要使用
sudo
權限。這篇文章使用CocoaPods 1.5.3版本。如果對CocoaPods不熟悉,建議先閱讀CocoaPods的安裝與使用這篇文章。
2. 創建pod
創建pod步驟如下:
- 使用
pod lib create NAME
命令為pod創建目錄結構和相關模版文件。 - 更新pod的元數據(metadata),如版本信息、source、license等。
- 添加代碼。包括添加代碼到pod和example project。
- 使pod公開可用。
目前,CocoaPods有超過四萬八千個庫,用于超過三百萬個應用程序。人們把各種各樣的東西制作為pod使用,這里有一些關于pod的建議:
- 工具(utility code):你是否對執行字符串有一套特定方法?是否有自己寫的用來執行特定動畫的子類?像這樣特定實用程序代碼會是很好的pod,其一般與其他代碼庫相分離。
- 第三方軟件包(third party packages):你是否封裝了一些第三方API?是否需要在app中集成其他應用的鉤子(hook)?如身份驗證。你的網站是否提供了一些API,供其他應用程序整合使用。pod可以輕松解決以上所有問題。
- UI組件(UI Components):你是否創建了一個平滑的UI小部件?其他用戶通過包含一個pod依賴關系,能夠為應用程序輕松添加一個復雜、令人愉快的UI組件。
- 項目組件化時大多使用CocoaPods做依賴管理。
這篇文章將創建一個閃爍的UILabel
,名稱為BlinkLabel。
pod lib 命令在創建pod時有以下作用:
-
pod lib lint NAME
:驗證你創建的pod是否符合規范,是否可以通過CocoaPods使用。 -
pod lib create NAME
:創建標準目錄結構、模板文件。pod lib create NAME
不是創建pod的唯一方法,但它是最簡潔的方法。
打開Terminal,定位到想要創建pod目錄,執行以下命令:
$ cd ~/Desktop
$ pod lib create BlinkLabel
pod lib create NAME
使用默認模版,如果想使用其他模版,可以添加--template-url=URL參數。
輸入上面命令后,終端會詢問你以下問題:
What platform do you want to use?? [ iOS / macOS ],選擇iOS,直接回車默認選擇第一個。
What language do you want to use?? [ Swift / ObjC ],選擇Swift。CocoaPods會把你的庫設置為framework。
Would you like to include a demo application with your library? [ Yes / No ],選擇Yes。如果你想要包含一個示例工程,或計劃在app中測試你的庫,這里需要選擇Yes,以便模板文件為你的庫創建Xcode工程。也就是如果你計劃為pod添加截圖,這里需要選擇Yes。
-
Which testing frameworks will you use? [ Quick / None ],選擇Quick。提交庫到CocoaPods前應當進行測試。CocoaPods推薦使用其附帶的測試framework,而非Apple的XCTest。在Objective-C中,可以選擇Specta/Expecta或Kiwi,其區別如下:
- Specta/Expecta:通過不同podspecs的模塊化方法。
- Kiwi:是對Stubs/Mocks/Expections的一種一體化方法。
CocoaPods已經在MyLib-Tests.pch文件中添加了所有必要的包含和設置,因此不必將它們包含在每個文件中。
Would you like to do view based testing? [ Yes / No ],選擇Yes。根據你建立的倉庫,你可能會發現基于快照的測試是驗證視圖不同部分不同操作的最佳方法,這里建議使用
FBSnapShotTestCase
。如果你使用的是Specta/Expecta,那么其會包含一個pod來改進語法。What is your class prefix?如果你選擇的語言是ObjC,其最后會要求提供類前綴。
設置完畢后,Xcode會打開新創建的工程,以便你在剛創建的pod上工作。其Project Navigator目錄如下:
- 可以修改Podspec的元數據。
- 這是一個demo庫。
- 這是你之前選擇的測試framework。
- 在這里修改pod庫代碼。
- Pod用到的框架。
在開始下一步工作前,先查看下pod目錄結構:
$ cd ~/Desktop
$ tree BlinkLabel -L 2
BlinkLabel
├── BlinkLabel
│ ├── Assets # 資源文件
│ └── Classes # 類文件
├── BlinkLabel.podspec
├── Example # demo和測試包
│ ├── BlinkLabel
│ ├── BlinkLabel.xcodeproj
│ ├── BlinkLabel.xcworkspace
│ ├── Podfile # demo app的依賴文件
│ ├── Podfile.lock
│ ├── Pods
│ └── Tests
├── LICENSE # 開源協議,默認MIT License
├── README.md # markdown格式的README
└── _Pods.xcodeproj -> Example/Pods/Pods.xcodeproj #為項目提供Carthage支持的符號鏈接(symlink)。
10 directories, 5 files
使用pod lib create NAME
命令創建pod時,會使用git進行版本管理。還會生成以下文件:
- .travis.yml :持續集成服務Travis CI配置文件。
- BlinkLabel.podspec :倉庫的Podspec。Podspec或Spec用來描述pod庫的版本信息,包括源代碼網址,應當使用的文件,以及其他metadata。隨著版本迭代,一個pod會有很多spec。你可以手動創建podspec,也可以使用
pod spec create NAME
命令創建,還可以使用pod lib create NAME
命令一次創建整個目錄結構。
在Xcode中打開BlinkLabel.podspec文件,可以看到CocoaPods已經使用模板填充了其內容。使用pod lib lint NAME
命令可以驗證.podspec文件是否符合規范。
在命令行輸入以下命令:
$ cd ~/Desktop/BlinkLabel
$ pod lib lint BlinkLabel.podspec
輸出如下:
-> BlinkLabel (0.1.0)
- WARN | summary: The summary is not meaningful.
- WARN | url: The URL (https://github.com/pro648/BlinkLabel) is not reachable.
- WARN | [iOS] swift: The validator used Swift 3.2 by default because no Swift version was specified. To specify a Swift version during validation, add the `swift_version` attribute in your podspec. Note that usage of the `--swift-version` parameter or a `.swift-version` file is now deprecated.
[!] BlinkLabel did not pass validation, due to 3 warnings (but you can use `--allow-warnings` to ignore them).
You can use the `--no-clean` option to inspect any issue.
可以看到在.podspec文件中,有三處需要修改:
- 修改summary,以便使其有意義。
- 主頁url不可用。
- 驗證時沒有指明swift版本。
下面是修改.podspec文件的建議:
- s.summary:A subclass on UILabel that provides a blink.
- 在GitHub創建名稱為BlinkLabel的倉庫。
- 在.podspec文件添加s.swift_version = '4.0'。
再次運行pod lib lint BlinkLabel
命令,這次提示The description is shorter than the summary.,修改s.description為This CocoaPods provides the ability to use a UILabel that may be started and stopped blinking.
運行以下命令,推送本地倉庫到GitHub:
$ git add .
$ git commit -m "Initial Commit"
$ git remote add origin https://github.com/pro648/BlinkLabel
$ git push -u origin master:master
如果你對分布式版本控制系統git還不熟悉,可以查看教你系統學習Git一文。
到目前為止,如果操作正確,其應當通過驗證:
$ pod lib lint BlinkLabel.podspec
-> BlinkLabel (0.1.0)
BlinkLabel passed validation.
3. 為pod添加代碼
現在,pod外殼已經創建好了,但其還沒有任何功能。CocoaPods創建的工程可以同時為pod和example project編寫代碼。
首先,刪除Pods/Development Pods/BlinkLabel下的ReplaceMe.swift文件,并在此目錄下創建一個名稱為BlinkLabel
,父類為UILabel
,語言為Swift的文件。更新BlinkLabel.swift文件內容如下:
public class BlinkLabel: UILabel {
public func startBlinking() {
UIView.animate(withDuration: 0.3, delay: 0.0, options: .repeat, animations: {
self.alpha = 0
}, completion: nil)
}
public func stopBlinking() {
alpha = 1
layer.removeAllAnimations()
}
}
剛剛,你為你的第一個pod添加了閃爍功能。該子類提供了一個使UILabel
閃爍的方法,一個使UILabel
停止blink的方法。
為了讓其他用戶更容易理解BlinkLabel的功能,為example project添加一些示例代碼。打開BlinkLabel/Example for BlinkLabel/ViewController.swift文件,更新其內容如下:
import UIKit
import BlinkLabel
class ViewController: UIViewController {
var isBlinking = false
let blinkLabel = BlinkLabel()
override func viewDidLoad() {
super.viewDidLoad()
isBlinking = true
// Setup the BlinkLabel.
blinkLabel.text = "I blink!"
blinkLabel.font = UIFont.preferredFont(forTextStyle: .body)
blinkLabel.textColor = .orange
blinkLabel.startBlinking()
view.addSubview(blinkLabel)
// Create a UIButton to toggle the blinking.
let toggleButton = UIButton.init(type: .system)
toggleButton.setTitle("Toggle Blinking", for:.normal)
toggleButton.addTarget(self, action: #selector(toggleBlinking), for: .touchUpInside)
view.addSubview(toggleButton)
// Create a UIStackView to layout blinkLabel and toggleButton.
let stackView = UIStackView.init(arrangedSubviews: [blinkLabel, toggleButton])
stackView.axis = .vertical
stackView.alignment = .center
stackView.spacing = 20
view.addSubview(stackView)
// Layout out stackView.
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
stackView.centerYAnchor.constraint(equalTo: self.view.centerYAnchor).isActive = true
}
@objc func toggleBlinking() {
if isBlinking {
blinkLabel.stopBlinking()
} else {
blinkLabel.startBlinking()
}
isBlinking = !isBlinking
}
}
這時,Xcode會發出錯誤警告,提示No such module 'BlinkLabel',這是因為BlinkLabel pod還沒有install到example project。
打開命令行,在BlinkLabel的根目錄執行以下操作:
$ cd Example
$ pod install
Analyzing dependencies
Fetching podspec for `BlinkLabel` from `../`
Downloading dependencies
Installing BlinkLabel 0.1.0
Using FBSnapshotTestCase (2.1.4)
Using Nimble (7.0.3)
Using Nimble-Snapshots (6.3.0)
Using Quick (1.2.0)
Generating Pods project
Integrating client project
Sending stats
Pod installation complete! There are 5 dependencies from the Podfile and 5 total pods installed.
[!] Automatically assigning platform `ios` with version `9.3` on target `BlinkLabel_Example` because no platform was specified. Please specify a platform for this target in your Podfile. See `https://guides.cocoapods.org/syntax/podfile.html#platform`.
可以看到其提示,沒有指定platform,默認使用了ios 9.3。我們還可以手動修改example project中的Podfile文件,添加以下信息:
platform:ios, '9.0'
inhibit_all_warnings!
再次執行pod install
命令,上面的提示將不再出現。
選中BlinkLabel-Example target并運行。如下所示:
點擊Toggle Blinking按鈕開始或結束閃爍。
創建pod的最后一步是修改README.md信息。打開BlinkLabel/Podsepc Metadata/README.md文件,可以看到CocoaPods生成的默認說明,增加如何使用pod的說明、截圖,使其更有價值。README是進入你的pod首先看到的東西,也是CocoaPods Quality Indexes的要素之一。這里是我的README。
最后,記得提交以上修改到GitHub倉庫。
4. 提交Pod到Specs倉庫
現在,你的本地計算機上運行了功能完備的pod,你還可以將其提交到公開的Specs倉庫,以便他人使用。
Specs是托管在GitHub上的公共倉庫,其索引了所有公開pod。你的源代碼并不一定要托管在GitHub。例如,將源代碼托管在碼云。
提交pod到Specs倉庫步驟如下:
- 為最近一次提交添加標簽。
- 使用
pod spec lint NAME
命令驗證源代碼與.podspec文件配置是否正確。 - 使用
pod trunk push NAME
命令提交spec到Specs倉庫。
進行以上操作前,要確保對BlinkLabel的本地更改已添加到git,并推送到了遠程倉庫。
4.1 添加Tag
為最近一次提交添加標簽:
$ git tag -a 0.1.0 -m "version 0.1.0"
$ git push origin 0.1.0
Counting objects: 1, done.
Writing objects: 100% (1/1), 161 bytes | 161.00 KiB/s, done.
Total 1 (delta 0), reused 0 (delta 0)
To https://github.com/pro648/BlinkLabel
* [new tag] 0.1.0 -> 0.1.0
使用tag標記特定提交,標簽名稱應當與.podspec文件中的s.version匹配。下一步將會驗證這一點。
4.2 使用pod spec lint NAME驗證
使用pod spec lint NAME
命令驗證源代碼與.podspec文件配置是否正確。
$ pod spec lint BlinkLabel.podspec
-> BlinkLabel (0.1.0)
Analyzed 1 podspec.
BlinkLabel.podspec passed validation.
pod lib lint NAME
命令與pod spec lint NAME
區別如下:
-
pod lib lint NAME
:只在本地lint你的pod,確保用于創建pod配置信息正確,但其不足以驗證pod,只有pod spec lint NAME
可以驗證pod。 -
pod spec lint NAME
:會在本地和遠程驗證pod。如代碼托管在GitHub,其會進行lint。如果pod spec lint NAME
沒有返回錯誤,就可以推送pod到CocoaPods。
4.3 提交spec到Specs倉庫
最后,執行以下命令提交spec到Specs倉庫。
$ pod trunk push BlinkLabel.podspec
如果這是你第一次提交spec到Specs倉庫,其會出現以下提示:
[!] You need to register a session first.
這時可以通過以下命令注冊賬號:
$ pod trunk register YOU_EMAIL@example.com 'NAME' --description='macbook'
Trunk會向你的郵箱發送郵件,你必須點擊郵件中的鏈接進行驗證。
如果你在.podspec文件中添加了不應出現的內容,如密碼、身份信息??梢允褂?code>pod trunk delete NAME VERSION刪除指定版本pod,一般不應刪除其他用戶依賴的版本,刪除后的版本將無法再次添加到Specs。如果你只是學習如何添加pod到CocoaPods,或確定沒有用戶使用你的pod,可以使用pod trunk deprecate NAME
命令將pod標記為不推薦使用,這樣其他用戶將無法搜索到你的pod。更多相關內容,可以查看CocoaPods的Pull Request FAQ #12199。
5. 使用私有pod
除了將pod推送到Specs,還可以創建私有pod,便于項目管理。
使用私有pod時,其Podfile文件如下:
pod 'BlinkLabel', :path => '~/Desktop/BlinkLabel'
# 或者
pod 'BlinkLabel', :podspec => 'https://github.com/pro648/BlinkLabel/BlinkLabel.podspec'
如果使用了多個私有pod,可以修改Podfile文件pod source如下:
# 使用默認source時,可以不寫Specs source。如果指定了私有.podspec,則必須寫明所有source,否則,將查找不到其他開源pod。
source 'https://github.com/CocoaPods/Specs.git'
source 'https://github.com/pro648/BlinkLabel/BlinkLabel.podspec'
總結
創建pod供他人使用會非常有趣,也是回饋開源社區的好方法。這篇文章向你展示了哪些類型代碼適合創建pod,如何創建pod,如何將pod添加到Specs以便其他用戶可以使用。另外,你還可以查看Quality Indexes,了解哪些因素會影響pod的質量指標。
參考資料: