使用CocoaPods創建公開、私有pod

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步驟如下:

  1. 使用pod lib create NAME命令為pod創建目錄結構和相關模版文件。
  2. 更新pod的元數據(metadata),如版本信息、source、license等。
  3. 添加代碼。包括添加代碼到pod和example project。
  4. 使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參數。

輸入上面命令后,終端會詢問你以下問題:

  1. What platform do you want to use?? [ iOS / macOS ],選擇iOS,直接回車默認選擇第一個。

  2. What language do you want to use?? [ Swift / ObjC ],選擇Swift。CocoaPods會把你的庫設置為framework。

  3. Would you like to include a demo application with your library? [ Yes / No ],選擇Yes。如果你想要包含一個示例工程,或計劃在app中測試你的庫,這里需要選擇Yes,以便模板文件為你的庫創建Xcode工程。也就是如果你計劃為pod添加截圖,這里需要選擇Yes。

  4. 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文件中添加了所有必要的包含和設置,因此不必將它們包含在每個文件中。

  5. Would you like to do view based testing? [ Yes / No ],選擇Yes。根據你建立的倉庫,你可能會發現基于快照的測試是驗證視圖不同部分不同操作的最佳方法,這里建議使用FBSnapShotTestCase。如果你使用的是Specta/Expecta,那么其會包含一個pod來改進語法。

  6. What is your class prefix?如果你選擇的語言是ObjC,其最后會要求提供類前綴。

設置完畢后,Xcode會打開新創建的工程,以便你在剛創建的pod上工作。其Project Navigator目錄如下:

podLibCreate.png
  1. 可以修改Podspec的元數據。
  2. 這是一個demo庫。
  3. 這是你之前選擇的測試framework。
  4. 在這里修改pod庫代碼。
  5. 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并運行。如下所示:

BlinkLabel.gif

點擊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倉庫步驟如下:

  1. 為最近一次提交添加標簽。
  2. 使用pod spec lint NAME命令驗證源代碼與.podspec文件配置是否正確。
  3. 使用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的質量指標。

參考資料:

  1. Creating Your First CocoaPod

  2. Making a CocoaPod

  3. What's the difference between 'pod spec lint' and 'pod lib lint'?

  4. 'pod spec lint' fails with Swift 4

歡迎更多指正:https://github.com/pro648/tips/wiki

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,119評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,382評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,038評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,853評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,616評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,112評論 1 323
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,192評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,355評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,869評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,727評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,928評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,467評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,165評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,570評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,813評論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,585評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,892評論 2 372

推薦閱讀更多精彩內容