你真的會用 CocoaPods 嗎

CocoaPods 可以說是 iOS 開發(fā)應(yīng)用最廣泛的包管理工具榛瓮,本篇文章主要介紹 CocoaPods 的第三方庫是怎樣從網(wǎng)絡(luò)集成到我們本地的項目當(dāng)中童谒,也是制作私有庫、開源庫和 iOS 項目組件化的一個知識鋪墊。

讓我們從一張圖片開始:

CocoaPods 工作流程
未命名文件

遠(yuǎn)程索引庫

遠(yuǎn)程索引庫里存放的是各種框架的描述信息确垫,這個庫托管在 Github 上隔披,地址如下:

https://github.com/CocoaPods/Specs

每個框架下有數(shù)個版本收津,每個版本有一個 json 格式的描述信息裳扯,如下:

{
  "name": "CAIStatusBar",
  "version": "0.0.1",
  "summary": "A simple indicator",
  "homepage": "https://github.com/apple5566/CAIStatusBar.git",
  "license": "MIT",
  "authors": {
    "apple5566": "zaijiank110@sohu.com"
  },
  "platforms": {
    "ios": "6.0"
  },
  "source": {
    "git": "https://github.com/apple5566/CAIStatusBar.git",
    "tag": "0.0.1"
  },
  "source_files": "CAIStatusBar/**/*.{h,m}",
  "resources": "CAIStatusBar/CAIStatusBar.bundle",
  "requires_arc": true
}

其中 git 字段表示該框架的托管地址,也就是上面時序圖中的 遠(yuǎn)程框架庫噪珊。

本地索引庫

install cocoapods 命令后晌缘,需要執(zhí)行 pod setup 這個命令,pod setup 命令就是將遠(yuǎn)程索引庫克隆到本地來痢站,本地索引庫的路徑如下:

~/.cocoapods/repos/master

本地索引庫和遠(yuǎn)程索引庫的目錄一致磷箕,結(jié)構(gòu)如下:

本地索引庫
本地索引庫

本地索引文件

當(dāng)執(zhí)行 pod search 命令時,如果本地索引文件不存在阵难,會創(chuàng)建這個文件岳枷。

tianziyaodeMacBook-Air:~ Tian$ pod search afn
Creating search index for spec repo 'master'..

如果這個文件存在,則會在此文件中進(jìn)行索引多望,確認(rèn)所需要的框架是否存在嫩舟,本地索引文件的路徑如下:

~/資源庫/Caches/CocoaPods

制作 CocoaPods 庫

上面的流程清楚以后,制作 CocoaPods 庫相信應(yīng)該不會太難了怀偷,大致分為以下幾步:

  1. 托管框架源碼到 Git家厌;
  2. 創(chuàng)建框架描述信息;
  3. 上傳框架描述信息到 https://github.com/CocoaPods/Specs椎工;
  4. 命令行 pod setup 饭于, 創(chuàng)建本地索引庫;
  5. 命令行 pod install 维蒙,將框架集成到項目中掰吕;

現(xiàn)在開始動手吧!首先在桌面新建一個 testLib 目錄颅痊,在該目錄下新建一個 Classes 目錄殖熟,用來存放框架源碼,然后將 testLib 托管到 Git斑响。

你可以給 Classes 目錄任意的命名菱属,Classes 只是一種約定俗稱的命名钳榨。

pod spec

pod spec 命令用于創(chuàng)建框架的描述信息文件,文檔如下:

https://guides.cocoapods.org/syntax/podspec.html

現(xiàn)在在 testLib 目錄下執(zhí)行:

pod spec create testLib

目錄下會創(chuàng)建一個 testLib.podspec 文件纽门,然后編輯這個文件薛耻,主要有以下幾個字段:

  • version:這個 spec 映射的版本,保證 Git 的 releases 與此對應(yīng)赏陵;
  • homepage:項目主頁饼齿;
  • source:框架源代碼的托管地址;
  • tag:與 version 對應(yīng)蝙搔;
  • source_files:框架源代碼的目錄缕溉、文件、文件類型等規(guī)則杂瘸;

CocoaPods 公開庫

根據(jù)上面的步驟倒淫,現(xiàn)在你需要將生成的 testLib.podspec 文件上傳到遠(yuǎn)程索引庫伙菊,在此之前败玉,你需要注冊一個 Trunk 賬號,文檔如下:

https://guides.cocoapods.org/making/getting-setup-with-trunk.html

現(xiàn)在執(zhí)行下面的命令镜硕,記得修改郵箱昵稱描述等:

pod trunk register ziyao.tian@gmail.com 'Tian' --description='macbook air'

你的郵箱會收到一封郵件运翼,打開郵件里面的鏈接,會有類似 you can back termainal 的提示兴枯,現(xiàn)在回到終端血淌。

pod lib lint

檢查 testLib.podspec 的合法性,根據(jù)錯誤提示修復(fù)問題财剖,當(dāng)顯示 passed validation 后悠夯,執(zhí)行下面的命令:

pod trunk push testLib.podspec

提示信息如下:

Updating spec repo `master`

--------------------------------------------------------------------------------
 ??  Congrats

 ??  testLib (0.0.7) successfully published
 ??  October 17th, 00:38
 ??  https://cocoapods.org/pods/testLib
 ??  Tell your friends!
--------------------------------------------------------------------------------

此時你的 testLib.podspec 就會 pull request 到遠(yuǎn)程索引庫,CocoaPods 官方審核通過后躺坟,就可以出現(xiàn)在遠(yuǎn)程索引庫中沦补,當(dāng)遠(yuǎn)程索引庫收錄后:

pod setup

這時你的本地索引庫,會新加入 testLib.podspec 這條記錄咪橙,但是本地索引文件還未更新夕膀,因此刪除掉以下路徑的本地索引文件:

~/資源庫/Caches/CocoaPods/search_index.json

執(zhí)行 pod search testLib 命令,當(dāng) search_index.json 文件重建完畢后美侦,就可以在使用這個遠(yuǎn)程框架庫了产舞。

CocoaPods 私有庫

有了公開庫,當(dāng)然也就有私有庫菠剩,私有庫主要分為遠(yuǎn)程和本地兩種易猫,什么時候會用到私用庫呢?也就是需要將源碼封裝成庫具壮,但又不希望將源碼公開准颓,一般的使用場景是公司內(nèi)部的組件化開發(fā)违霞。

本地私有庫

本地私有庫就是創(chuàng)建一個倉庫,將其存儲在本地瞬场,在本地的其他工程中直接使用买鸽。首先在桌面新建一個庫,路徑如下:

LocalLib/NetWork/Classes/Test.swift

接著創(chuàng)建一個殼工程贯被,現(xiàn)在你的目標(biāo)是使用 pod 的方式眼五,將 NetWork 這個庫集成到殼工程中。

創(chuàng)建本地 GIt 倉庫

NetWork 加入到 Git彤灶,命令如下:

git init
git add.
git commit -m 'x'

創(chuàng)建庫描述文件

和公開庫一樣看幼,我們需要先創(chuàng)建一個 spec 文件,命令如下:

pod spec create LocalLib

編輯 NetWork.podspec 文件幌陕,修改成下面這樣:

Pod::Spec.new do |s|

  s.name         = "NetWork"
  s.version      = "0.0.1"
  s.summary      = "A short description of NetWork."
  s.description  = "A short description of NetWork.xxxxxxxxxxxxxxxxxx"
  s.homepage     = "http://EXAMPLE/NetWork"
  s.license      = "MIT"
  s.author             = { "tianziyao" => "ziyao.tian@gmail.com" }
  s.source       = { :git => "", :tag => "#{s.version}" }
  s.source_files  = "Classes", "Classes/**/*.{h,m,swift}"

end

現(xiàn)在你的本地庫已經(jīng)準(zhǔn)備完畢了诵姜,下面就可以使用這個庫了。

導(dǎo)入本地私有庫

現(xiàn)在進(jìn)入到殼工程目錄下搏熄,執(zhí)行命令:

pod init

編輯 Podfile 文件棚唆,如下:

target 'Test' do
  use_frameworks!

  pod 'NetWork', :path => '../NetWork'

  target 'TestTests' do
    inherit! :search_paths
  end

  target 'TestUITests' do
    inherit! :search_paths
  end

end

這里有一個 path 關(guān)鍵字,它表示在 pod install 執(zhí)行時心例,在指定的路徑下尋找 NetWork.podspec 文件宵凌。

下面執(zhí)行 pod install 命令,提示信息如下:

Analyzing dependencies
Fetching podspec for `NetWork` from `../NetWork`
Downloading dependencies
Installing NetWork (0.0.1)
Generating Pods project
Integrating client project

現(xiàn)在 NetWork 這個庫就集成到了殼工程中止后。

與使用遠(yuǎn)程庫不同瞎惫,本地庫的源文件會在 Development Pods 這個目錄下,而不是 Pods 目錄译株,順便一提瓜喇,CocoaPods 的庫開發(fā),一般也是這樣搭建環(huán)境的歉糜,開發(fā)完成后再修改 spec 文件乘寒,將其 pull request 到遠(yuǎn)程索引庫。

CocoaPods 模板庫

本地私有庫這個方式還存在以下問題:

  • 需要手動創(chuàng)建 podspec 文件现恼;
  • 無法單獨測試肃续,需要依托于殼工程運行;

假設(shè)我們有一個基礎(chǔ)組件叉袍,里面全部是擴(kuò)展文件始锚,無法單獨運行,如果依托殼工程運行喳逛,只有這一個組件瞧捌,那么這個殼工程實際跟測試工程是一樣的,但殼工程內(nèi)有多個組件呢?

我們在殼工程中進(jìn)行測試的話姐呐,不但要對其他的組件進(jìn)行編譯殿怜,而且自己負(fù)責(zé)的組件也可能會收到其他組件的影響,這樣也就失去了組件化開發(fā)的本意曙砂,那么怎么優(yōu)化呢头谜?

單獨測試

首先在 LocalLib/NetWork/ 路徑下創(chuàng)建一個測試工程 Example,然后將 Classes 拖到這個測試工程中鸠澈,這里需要注意的是柱告,ExampleClasses 是引用關(guān)系,不要 Copy笑陈。

簡單粗暴的拖拽际度,現(xiàn)在 Example 工程就可以使用 NetWork 庫了。

另外一種方式是將 NetWork 通過 CocoaPods 安裝在 Example 中涵妥,和安裝在殼工程一樣乖菱。

看到這里,是不是感覺很煩蓬网?就是想做個測試而已窒所,還要拖來拖去,那么繁瑣拳缠。

不要著急下面來介紹一種更快捷高效的方式墩新,執(zhí)行下面的命令:

pod lib create BaseMoudle
////////////////////////////////////////////////////////////////////////
What language do you want to use?? [ Swift / ObjC ] 
 > Swift

Would you like to include a demo application with your library? [ Yes / No ]
 > Yes

Which testing frameworks will you use? [ Quick / None ]
 > None

Would you like to do view based testing? [ Yes / No ]
 > Yes

現(xiàn)在我們就有了一個 CocoaPods 的模板工程贸弥,它的結(jié)構(gòu)是這樣的:

.
├── BaseMoudle
│   ├── Assets
│   └── Classes
│       └── ReplaceMe.swift
├── BaseMoudle.podspec
├── Example
│   ├── BaseMoudle
│   ├── BaseMoudle.xcodeproj
│   ├── BaseMoudle.xcworkspace
│   ├── Podfile
│   ├── Podfile.lock
│   ├── Pods
├── LICENSE
├── README.md
└── _Pods.xcodeproj -> Example/Pods/Pods.xcodeproj

看吧窟坐,把源碼拖到 ReplaceMe.swift 的同級目錄,執(zhí)行 pod install绵疲,就完成了本地私有庫和其測試工程哲鸳。

這一步可能會有 Swift 語言版本的問題,保持測試工程和私有庫源碼語言版本一致就可以盔憨。

遠(yuǎn)程私有庫

遠(yuǎn)程私有庫工作流程
遠(yuǎn)程私有庫

現(xiàn)在使用 pod lib create 就可以方便的生成一個本地私有庫了徙菠,但是本地私有庫有一定的局限性,例如:

  • 需要在 Podfile 文件中主動指明路徑郁岩;
  • 版本升級不容易維護(hù)婿奔;
  • 多人開發(fā)時,不方便進(jìn)行合作问慎;

遠(yuǎn)程私有庫就可以方便的解決以上的問題萍摊,制作遠(yuǎn)程私有庫分為以下幾個步驟:

  1. 創(chuàng)建私有 Git 遠(yuǎn)程倉庫;
  2. 創(chuàng)建私有 CocoaPods 遠(yuǎn)程索引庫如叼;
  3. 創(chuàng)建 Pod 所需要的項目工程文件冰木,并上傳到 Git 遠(yuǎn)程私有庫;
  4. 驗證 podspec 描述文件;
  5. 向私有 CocoaPods 遠(yuǎn)程索引庫提交 podspec 描述文件踊沸;
  6. 使用 Pod 庫歇终;

Git 倉庫的創(chuàng)建在此就不在贅述了,本文中我使用碼市做示例逼龟,私有 CocoaPods 遠(yuǎn)程索引庫實際上也是一個 Git 倉庫评凝,現(xiàn)在我們有兩個私有庫,一個用來存放 Pod 庫的源碼腺律,一個用來存放 Pod 庫的描述文件肥哎。

SSH 授權(quán)

添加私有索引庫需要使用 SSH 授權(quán),也是和 Git 倉庫一樣的疾渣,了解的同學(xué)可以跳過這一步驟篡诽,首先創(chuàng)建公鑰:

ssh-keygen

然后找到下面的文件:

~/.ssh/id_rsa.pub

里面存放的字符就是公鑰了,然后將公鑰添加碼市榴捡,鏈接如下:

https://coding.net/user/account/setting/keys

添加私有遠(yuǎn)程索引庫

現(xiàn)在執(zhí)行 pod repo杈女,可以看到下面的信息:

master
- Type: git (master)
- URL:  https://github.com/CocoaPods/Specs.git
- Path: /Users/Tian/.cocoapods/repos/master

現(xiàn)在我們只有一個 CocoaPods 遠(yuǎn)程索引庫,也是官方的索引庫吊圾,下面執(zhí)行:

pod repo add TZYSpecs git@git.coding.net:tianziyao/TZYSpecs.git

此時我們的 CocoaPods 遠(yuǎn)程索引庫就安裝好了达椰,到下面的路徑去看一下:

~/.cocoapods/repos

上傳源碼到 Git

還記得 pod lib create 命令嗎?前面我們使用它來制作了本地私有庫项乒,現(xiàn)在它又排上用場了啰劲,執(zhí)行:

pod lib create BaseComponent

源碼拖到 ReplaceMe.swift 的同級目錄,它現(xiàn)在看起來應(yīng)該是這個樣子:

.
├── BaseComponent
│   ├── Assets
│   └── Classes
│       ├── Extension
│       │   ├── Array+Safe.swift
│       │   ├── CALayer+PauseAimate.swift
│       │   ├── UIImage+.swift
│       │   └── UIView+Property.swift
├── BaseComponent.podspec
├── Example
├── LICENSE
├── README.md
└── _Pods.xcodeproj -> Example/Pods/Pods.xcodeproj

執(zhí)行 pod install檀何,就完成了本地私有庫和其測試工程蝇裤,通過測試之后,我們就可以把這個本地私有庫制作成遠(yuǎn)程私有庫了频鉴。

首先修改 BaseComponent.podspec 文件:

Pod::Spec.new do |s|

  s.name             = 'BaseComponent'
  s.version          = '0.1.0'
  s.summary          = '基礎(chǔ)組價'
  s.description      = '包括基本配置栓辜,常量,擴(kuò)展垛孔,工具類等'
  s.homepage         = 'https://coding.net/u/tianziyao/p/BaseComponent'
  s.license          = { :type => 'MIT', :file => 'LICENSE' }
  s.author           = { 'tianziyao' => 'ziyao.tian@gmail.com' }
  s.source           = { :git => 'https://git.coding.net/tianziyao/BaseComponent.git', :tag => s.version.to_s }
  s.ios.deployment_target = '8.0'
  s.source_files = 'BaseComponent/Classes/**/*'

end

然后使用質(zhì)量檢查工具驗證一下藕甩,保證在 BaseComponent.podspec 路徑下,執(zhí)行:

pod lib lint

如果你使用 Swift周荐,會得到一個提示:

 -> BaseComponent (0.1.0)
    - WARN  | [iOS] swift_version: The validator for Swift projects uses Swift 3.0 by default, if you are using a different version of swift you can use a `.swift-version` file to set the version for your Pod. For example to use Swift 2.3, run: 
    `echo "2.3" > .swift-version`

[!] BaseComponent did not pass validation, due to 1 warning (but you can use `--allow-warnings` to ignore it).
You can use the `--no-clean` option to inspect any issue.

根據(jù)提示修復(fù)就好了狭莱,在這里你可能會遇到很多 Swift 語言版本的問題,善用搜索引擎吧概作,通過檢驗以后提示如下:

 -> BaseComponent (0.1.0)

BaseComponent passed validation.

下面執(zhí)行:

git add .
git commit -m 'x'

然后和遠(yuǎn)程倉庫進(jìn)行關(guān)聯(lián):

git remote add origin https://git.coding.net/tianziyao/BaseComponent.git
git pull origin master 
git push origin master

上傳 Spec 到遠(yuǎn)程索引庫

首先執(zhí)行下面的命令:

pod spec lint

提示如下:

 -> BaseComponent (0.1.0)
    - ERROR | [iOS] unknown: Encountered an unknown error ([!] /usr/local/bin/git clone https://git.coding.net/tianziyao/BaseComponent.git /var/folders/2v/qkx5m4sx4dg86x4c82yfyjdc0000gn/T/d20171021-69604-1bekfgk --template= --single-branch --depth 1 --branch 0.1.0

Cloning into '/var/folders/2v/qkx5m4sx4dg86x4c82yfyjdc0000gn/T/d20171021-69604-1bekfgk'...
warning: Could not find remote branch 0.1.0 to clone.
fatal: Remote branch 0.1.0 not found in upstream origin
) during validation.

Analyzed 1 podspec.

[!] The spec did not pass validation, due to 1 error.

根據(jù)提示腋妙,我們需要先建立一個 Tag:

git tag '0.1.0'
git push --tags
pod spec lint

檢驗通過后,提示如下:

 -> BaseComponent (0.1.0)

Analyzed 1 podspec.

BaseComponent.podspec passed validation.

然后將 podspec 文件推到遠(yuǎn)程私有索引庫:

pod repo push TZYSpecs BaseComponent.podspec

現(xiàn)在看一下本地索引庫中是否已經(jīng)添加成功:

~/.cocoapods/repos

再看一看你的遠(yuǎn)程索引庫中是否添加成功仆嗦,現(xiàn)在搜索一下本地索引文件試試:

-> BaseComponent (0.1.0)
   基礎(chǔ)組價
   pod 'BaseComponent', '~> 0.1.0'
   - Homepage: https://coding.net/u/tianziyao/p/BaseComponent
   - Source:   https://git.coding.net/tianziyao/BaseComponent.git
   - Versions: 0.1.0 [TZYSpecs repo]

現(xiàn)在我們可以找到自己的遠(yuǎn)程私有庫了辉阶,下面將 Podfile 文件改成這樣:

project 'Ting.xcodeproj'

source 'https://github.com/CocoaPods/Specs.git'
source 'git@git.coding.net:tianziyao/TZYSpecs.git'

target 'Ting' do

  use_frameworks!
  
  pod 'BaseComponent'
  pod 'Alamofire'
  
  target 'TingTests' do
    inherit! :search_paths
    
  end

  target 'TingUITests' do
    inherit! :search_paths
    
  end

end

執(zhí)行 pod install,整個遠(yuǎn)程私有庫的搭建和使用就完成了。

CocoaPods 庫升級

我們使用遠(yuǎn)程私有庫的目的就是為了版本升級和多人開發(fā)谆甜,那么遠(yuǎn)程私有庫如何進(jìn)行升級垃僚,升級后其他人又如何使用呢?現(xiàn)在我們給 BaseComponent 進(jìn)行升級规辱,給它再增加一些功能:

.
├── BaseComponent
│   ├── Assets
│   └── Classes
│       ├── Const
│       │   └── Const.swift
│       ├── Extension
│       │   ├── Array+Safe.swift
│       │   ├── CALayer+PauseAimate.swift
│       │   ├── UIImage+.swift
│       │   └── UIView+Property.swift
│       └── Tool
│           ├── AlertTool.swift
│           ├── CacheTool.swift
│           ├── DeviceMessage.swift
│           └── NoticeLocalTool.swift
├── BaseComponent.podspec
├── Example
├── LICENSE
├── README.md
└── _Pods.xcodeproj -> Example/Pods/Pods.xcodeproj

BaseComponent 的測試工程中測試無誤后谆棺,將 BaseComponent.podspecversion 修改一下:

Pod::Spec.new do |s|
  s.name             = 'BaseComponent'
  s.version          = '0.2.0'
  s.summary          = '基礎(chǔ)組價'
  s.description      = '包括基本配置,常量罕袋,擴(kuò)展改淑,工具類等'
  s.homepage         = 'https://coding.net/u/tianziyao/p/BaseComponent'
  s.license          = { :type => 'MIT', :file => 'LICENSE' }
  s.author           = { 'tianziyao' => 'ziyao.tian@gmail.com' }
  s.source           = { :git => 'https://git.coding.net/tianziyao/BaseComponent.git', :tag => s.version.to_s }
  s.ios.deployment_target = '8.0'
  s.source_files = 'BaseComponent/Classes/**/*'

end

現(xiàn)在檢查一下私有庫是否有錯誤:

pod lib lint

檢查通過后就可以將 BaseComponent0.2.0 版本推到遠(yuǎn)程私有庫中,同時建立 0.2.0 的 Tag浴讯。

然后檢查一下 spec 文件:

pod spec lint

檢查通過后朵夏,執(zhí)行:

pod repo push TZYSpecs BaseComponent.podspec

遠(yuǎn)程私有庫和遠(yuǎn)程私有索引庫全部更新完畢,現(xiàn)在我們回到使用者的視角榆纽,這個庫可以使用了嗎仰猖?還不行。

因為本地的索引文件還沒有更新奈籽,這個源還找不到饥侵,現(xiàn)在進(jìn)入殼工程,執(zhí)行:

pod update --no-repo-update
pod install

BaseComponent0.2.0 版本就乖乖的進(jìn)入了殼工程衣屏。

CocoaPods 庫依賴

在上面的殼工程中躏升,我們引入了 Alamofire 這個框架,但是如果用著用著突然覺得不爽了狼忱,要換框架膨疏,這時 Alamofire 的引用在工程中已經(jīng)無處不再了,這樣換的話是不是很痛苦藕赞?

所以我們一般在開發(fā)中都會封裝網(wǎng)絡(luò)請求成肘,做到分層解耦,這樣如果換框架斧蜕,只修改網(wǎng)絡(luò)請求這層的封裝就可以了,那么現(xiàn)在我們需要將 Alamofire 封裝成 Network砚偶,再把 Network 弄到我們的 BaseComponent 里面去批销,怎么做呢?

現(xiàn)在先將 Network 拖到 BaseComponentClasses 目錄中染坯,因為 BaseComponent 的測試工程沒有 Alamofire均芽,所以 Network 肯定是會報錯了,不要慌单鹿,下面我們修改 spec 文件:

Pod::Spec.new do |s|
  s.name             = 'BaseComponent'
  s.version          = '0.2.0'
  s.summary          = '基礎(chǔ)組價'
  s.description      = '包括基本配置掀宋,常量,擴(kuò)展,工具類等'
  s.homepage         = 'https://coding.net/u/tianziyao/p/BaseComponent'
  s.license          = { :type => 'MIT', :file => 'LICENSE' }
  s.author           = { 'tianziyao' => 'ziyao.tian@gmail.com' }
  s.source           = { :git => 'https://git.coding.net/tianziyao/BaseComponent.git', :tag => s.version.to_s }
  s.ios.deployment_target = '8.0'
  s.source_files = 'BaseComponent/Classes/**/*'
  s.dependency 'Alamofire'
  s.dependency 'SDWebImage'

end

dependency 指明了這個庫的依賴劲妙,改好之后 pod install湃鹊,Alamofire 就安裝到了 BaseComponent 的測試工程中,現(xiàn)在就可以使用 Alamofire 進(jìn)行網(wǎng)絡(luò)請求封裝镣奋,直接 import 就可以了:

import Foundation
import Alamofire
import SDWebImage

open class Network {
    
    open class func request(url: String, parameters: [String:Any]?) {
        Alamofire.request(url, method: .get, parameters: parameters).responseJSON { (response) in
            guard let JSON = response.result.value else { return }
            print(JSON)
        }
    }
}

extension UIImageView {
    
    public func image(with url: URL?) {
        self.sd_setImage(with: url)
    }
    
}

現(xiàn)在再進(jìn)行一次遠(yuǎn)程私有庫升級币呵,整個依賴就做好了,需要注意的是侨颈,已經(jīng)做了依賴的話余赢,相關(guān)的庫就可以從 Podfile 文件中去掉了:

project 'Ting.xcodeproj'

source 'https://github.com/CocoaPods/Specs.git'
source 'git@git.coding.net:tianziyao/TZYSpecs.git'

target 'Ting' do

  use_frameworks!
  
  pod 'BaseComponent'
  # pod 'Alamofire'
  
  target 'TingTests' do
    inherit! :search_paths
    
  end

  target 'TingUITests' do
    inherit! :search_paths
    
  end

end

現(xiàn)在是我們依賴的是公開庫,直接升級 CocoaPods 私有庫就可以哈垢,但是如果依賴的是另外一個私有庫妻柒,這個依賴關(guān)系最終還要上傳到私有索引庫中,這樣其他人在使用的時候才會知道這個依賴關(guān)系耘分,現(xiàn)在走一下升級的流程蛤奢,你會得到類似這個報錯:

[!] The `TargetComponent.podspec` specification does not validate.

這個報錯是因為 TargetComponent 這個庫沒有在官方的索引庫當(dāng)中,忽略就可以了陶贼,當(dāng)然啤贩,在使用的時候,TargetComponent 這個庫可以在你的本地索引文件中找到拜秧,否則無法使用痹屹。

CocoaPods 資源依賴

現(xiàn)在我們可以讓一個庫依賴另外一個庫,但是看下面這段代碼:

/// 獲取中間的視圖
open class func tabBarMiddleView() -> TZYTabBarMiddleView {
    let view = Bundle.main.loadNibNamed("TZYTabBarMiddleView", owner: nil, options: nil)?.first
    return (view as? TZYTabBarMiddleView) ?? TZYTabBarMiddleView()
}

這段代碼讀取了一個 XIB 文件枉氮,這個庫的結(jié)構(gòu)是這樣的:

.
├── Assets
└── Classes
    └── MainModule
        ├── Controller
        │   ├── TZYNavBarC.swift
        │   └── TZYTabBarC.swift
        └── View
            ├── TZYNavBar.swift
            ├── TZYTabBar.swift
            ├── TZYTabBarMiddleView.swift
            └── TZYTabBarMiddleView.xib

我們可以成功調(diào)用這個方法嗎志衍?不能,因為 TZYTabBarMiddleView.xib 這個文件的 Target 是 MainModule聊替,使用 CocoaPods 把這個庫安裝到我們項目后楼肪,XIB 文件即使在,也是在 Pods 這個工程里惹悄,而我們在殼工程中使用 TZYTabBarMiddleView.xib春叫,也是必然找不到的。

下面我們把模板庫的測試工程編譯一下泣港,打開 Products 目錄下的 .app 文件暂殖,看一下文件結(jié)構(gòu):

.
├── Base.lproj
│   ├── LaunchScreen.nib
│   └── Main.storyboardc
├── Frameworks
│   ├── Alamofire.framework
│   │   ├── Alamofire
│   │   ├── Info.plist
│   │   └── _CodeSignature
│   │       └── CodeResources
│   ├── BaseComponent.framework
│   │   ├── BaseComponent
│   │   ├── Info.plist
│   │   └── _CodeSignature
│   │       └── CodeResources
│   ├── SDWebImage.framework
│   │   ├── Info.plist
│   │   ├── SDWebImage
│   │   └── _CodeSignature
│   │       └── CodeResources
│   ├── TargetComponent.framework
│   │   ├── Info.plist
│   │   ├── TZYTabBarMiddleView.nib
│   │   ├── TargetComponent
│   │   └── _CodeSignature
│   │       └── CodeResources
├── Info.plist
├── PkgInfo
├── TargetComponent_Example
├── _CodeSignature
│   └── CodeResources
└── libswiftRemoteMirror.dylib

通過路徑可以看到,TZYTabBarMiddleView.nib 是在:

mainBundle/Frameworks/TargetComponent.framework

這個路徑下面当纱,因此 mainBundle.loadXIb 肯定是找不到資源文件的呛每,那么該如何修改呢?

open class func tabBarMiddleView() -> TZYTabBarMiddleView {
    let view = Bundle(for: TZYTabBarMiddleView.self).loadNibNamed("TZYTabBarMiddleView", owner: nil, options: nil)?.first
    //let view = Bundle.main.loadNibNamed("TZYTabBarMiddleView", owner: nil, options: nil)?.first
    return (view as? TZYTabBarMiddleView) ?? TZYTabBarMiddleView()
}

這部分的重點就是 Bundle(for aClass: Swift.AnyClass) 這個方法坡氯。

CocoaPods 圖片依賴

上面我們講到了怎樣使用 Pod 庫里面的 XIB 文件晨横,但是還有其他資源文件洋腮,例如圖片、音頻手形、視頻啥供,圖片我們一般是放在 Assets.xcassets,但是 Pod 庫并沒有對應(yīng)的路徑叁幢,那么它所需要的圖片放在哪里滤灯,已經(jīng)如何使用呢?現(xiàn)在使用 pod lib create 命令創(chuàng)建一個 Pod 庫曼玩,進(jìn)入以下路徑:

組件名/Assets

把一些圖片拖入到 Assets 文件夾內(nèi)鳞骤,然后在 podspec 文件中加入以下代碼:

s.resource_bundles = {
  '組件名' => ['組件名/Assets/*.png'] //只加載 png 文件
  # '組件名' => ['組件名/Assets/*'] //加載所有文件
}

然后執(zhí)行 pod install,Pod 庫中就出現(xiàn)了之前拖入 Assets 文件夾的圖片黍判,但是現(xiàn)在還不能使用豫尽,我們先來看一下打包以后這些圖片的路徑:

.
├── Base.lproj
│   ├── LaunchScreen.nib
│   └── Main.storyboardc
│       ├── Info.plist
│       ├── UIViewController-vXZ-lx-hvc.nib
│       └── vXZ-lx-hvc-view-kh9-bI-dsS.nib
├── Frameworks
│   ├── TargetComponent.framework
│   │   ├── Info.plist
│   │   ├── TZYTabBarMiddleView.nib
│   │   ├── TargetComponent
│   │   ├── TargetComponent.bundle
│   │   │   ├── Info.plist
│   │   │   ├── tabbar_bg_320x49_@3x.png
│   │   │   └── zxy_icon_48x48_@2x.png
│   │   └── _CodeSignature
│   │       └── CodeResources
│   └── libswiftUIKit.dylib
├── Info.plist
├── PkgInfo
├── TargetComponent_Example
├── _CodeSignature
│   └── CodeResources
├── embedded.mobileprovision
└── libswiftRemoteMirror.dylib

可以看到,打包后的路徑在:

mainBundle/Frameworks/TargetComponent.framework/TargetComponent.bundle

這個路徑下面顷帖,而代碼中的 UIImage(named: "tabbar_bg") 讀取的是 mainBundle 下的資源文件美旧,因此還是找不到的,那么這時使用圖片贬墩,應(yīng)該將代碼改成這樣:

backgroundImage = UIImage.image(withName: "tabbar_bg_320x49_@3x.png")
extension UIImage {
    
    public class func image(withName name: String) -> UIImage? {
        let bundle = Bundle(for: UIImage.self)
        guard let path = bundle.path(forResource: name, ofType: nil, inDirectory: "TargetComponent.bundle") else {
            return nil
        }
        return UIImage(contentsOfFile: path)
    }
}

這里需要注意的是榴嗅,文件名需要完整。以上是在代碼中加載圖片陶舞,如果是在 XIB 中加載圖片嗽测,應(yīng)該怎樣做呢?那么再看一下上面的目錄結(jié)構(gòu)肿孵,TZYTabBarMiddleView.nibTargetComponent.bundle 處于同一個目錄唠粥,我們可以在 TZYTabBarMiddleView.xib 中通過相對路徑,使用 TargetComponent.bundle 里面的圖片停做,因此在 XIB 中晤愧,圖片名應(yīng)該是這樣的:

TargetComponent.bundle/tabbar_bg_320x49_@3x

CocoaPods 子庫

現(xiàn)在我們實現(xiàn)了一個完整的遠(yuǎn)程私有庫,可以升級蛉腌,依賴其他的庫官份,提供給其他人使用,但是現(xiàn)在還有一點問題眉抬,其他人如果要用我們的庫贯吓,就需要把 BaseComponent 完整的克隆過來,但是他可能只需要 BaseComponent 里面的 Network蜀变,其他的擴(kuò)展、工具等并不想使用介评,也不想導(dǎo)入過來库北,怎么辦爬舰?有兩種方案:

  1. Network 剝離出來,再單獨建一個遠(yuǎn)程私有庫寒瓦;
  2. 使用子庫遷出 Network情屹;

第一種方案大家已經(jīng)知道了,就是上面的一大篇杂腰,麻煩不說垃你,而且東西一多起來,這里一個庫喂很,那里一個庫惜颇,也不容易管理,所以少辣,下面就有請子庫隆重登場凌摄。

在開始之前,我們先來開一個東西漓帅,下面是 pod search AFN 中的一條記錄:

-> AFNetworking (3.1.0)
   A delightful iOS and OS X networking framework.
   pod 'AFNetworking', '~> 3.1.0'
   - Homepage: https://github.com/AFNetworking/AFNetworking
   - Source:   https://github.com/AFNetworking/AFNetworking.git
   - Versions: 3.1.0, 3.0.4, 3.0.3, 3.0.2, 3.0.1, 3.0.0, 3.0.0-beta.3, 3.0.0-beta.2, 3.0.0-beta.1, 2.6.3, 2.6.2, 2.6.1, 2.6.0, 2.5.4, 2.5.3, 2.5.2, 2.5.1, 2.5.0, 2.4.1,
   2.4.0, 2.3.1, 2.3.0, 2.2.4, 2.2.3, 2.2.2, 2.2.1, 2.2.0, 2.1.0, 2.0.3, 2.0.2, 2.0.1, 2.0.0, 2.0.0-RC3, 2.0.0-RC2, 2.0.0-RC1, 1.3.4, 1.3.3, 1.3.2, 1.3.1, 1.3.0, 1.2.1,
   1.2.0, 1.1.0, 1.0.1, 1.0, 1.0RC3, 1.0RC2, 1.0RC1, 0.10.1, 0.10.0, 0.9.2, 0.9.1, 0.9.0, 0.7.0, 0.5.1 [master repo]
   - Subspecs:
     - AFNetworking/Serialization (3.1.0)
     - AFNetworking/Security (3.1.0)
     - AFNetworking/Reachability (3.1.0)
     - AFNetworking/NSURLSession (3.1.0)
     - AFNetworking/UIKit (3.1.0)

注意 Subspecs 這里锨亏,它就是本節(jié)要講的東西,首先將 spec 改成下面這樣:

Pod::Spec.new do |s|
  s.name             = 'BaseComponent'
  s.version          = '0.4.0'
  s.summary          = '基礎(chǔ)組價'
  s.description      = '包括基本配置忙干,常量器予,擴(kuò)展,工具類等'
  s.homepage         = 'https://coding.net/u/tianziyao/p/BaseComponent'
  s.license          = { :type => 'MIT', :file => 'LICENSE' }
  s.author           = { 'tianziyao' => 'ziyao.tian@gmail.com' }
  s.source           = { :git => 'https://git.coding.net/tianziyao/BaseComponent.git', :tag => s.version.to_s }
  s.ios.deployment_target = '8.0'
  # s.source_files = 'BaseComponent/Classes/**/*'

  s.subspec 'Network' do |n|
    n.source_files = 'BaseComponent/Classes/Network/**/*'
    n.dependency 'Alamofire'
    n.dependency 'SDWebImage'
  end

  s.subspec 'Const' do |c|
    c.source_files = 'BaseComponent/Classes/Const/**/*'
  end

  s.subspec 'Extension' do |e|
    e.source_files = 'BaseComponent/Classes/Extension/**/*'
  end

  s.subspec 'Tool' do |t|
    t.source_files = 'BaseComponent/Classes/Tool/**/*'
  end

end

在這里要注意 source_filesdependency 以及版本的變化捐迫,修改完成推到遠(yuǎn)程索引庫乾翔,并打好 0.4.0 的分支,執(zhí)行:

pod spec lint
pod repo push TZYSpecs BaseComponent.podspec
pod update --no-repo-update
pod search Base

現(xiàn)在就可以找到了:

-> BaseComponent (0.4.0)
   基礎(chǔ)組價
   pod 'BaseComponent', '~> 0.4.0'
   - Homepage: https://coding.net/u/tianziyao/p/BaseComponent
   - Source:   https://git.coding.net/tianziyao/BaseComponent.git
   - Versions: 0.4.0, 0.3.0, 0.2.0, 0.1.0 [TZYSpecs repo]
   - Subspecs:
     - BaseComponent/Network (0.4.0)
     - BaseComponent/Const (0.4.0)
     - BaseComponent/Extension (0.4.0)
     - BaseComponent/Tool (0.4.0)

那么如何使用呢弓乙?把 Podfile 改成這樣:

project 'Ting.xcodeproj'

source 'https://github.com/CocoaPods/Specs.git'
source 'git@git.coding.net:tianziyao/TZYSpecs.git'

target 'Ting' do

  use_frameworks!
  
  pod 'BaseComponent/Network'
  
  # 也可以用下面的寫法
  # pod 'BaseComponent', :subspecs => ['Network', 'Extension']
  
  target 'TingTests' do
    inherit! :search_paths
    
  end

  target 'TingUITests' do
    inherit! :search_paths
    
  end

end

現(xiàn)在 pod install末融,就完成了子庫的創(chuàng)建和使用。

結(jié)尾

這篇文章斷斷續(xù)續(xù)寫了快一周暇韧,其實一般我們用不到 CocoaPods 這些功能勾习,不過了解一下 CocoaPods 的工作原理也是沒有壞處的。

這篇文章主要是為了使用 CocoaPods 進(jìn)行組件化開發(fā)懈玻,關(guān)于組件化開發(fā)的思想巧婶,可以看下面這篇文章:

iOS 組件化實踐思考

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市涂乌,隨后出現(xiàn)的幾起案子艺栈,更是在濱河造成了極大的恐慌,老刑警劉巖湾盒,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件湿右,死亡現(xiàn)場離奇詭異,居然都是意外死亡罚勾,警方通過查閱死者的電腦和手機(jī)毅人,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進(jìn)店門吭狡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人丈莺,你說我怎么就攤上這事划煮。” “怎么了缔俄?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵弛秋,是天一觀的道長。 經(jīng)常有香客問我俐载,道長蟹略,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任瞎疼,我火速辦了婚禮科乎,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘贼急。我一直安慰自己茅茂,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布太抓。 她就那樣靜靜地躺著空闲,像睡著了一般。 火紅的嫁衣襯著肌膚如雪走敌。 梳的紋絲不亂的頭發(fā)上碴倾,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天,我揣著相機(jī)與錄音掉丽,去河邊找鬼跌榔。 笑死,一個胖子當(dāng)著我的面吹牛捶障,可吹牛的內(nèi)容都是我干的僧须。 我是一名探鬼主播,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼项炼,長吁一口氣:“原來是場噩夢啊……” “哼担平!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起锭部,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤暂论,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后拌禾,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體取胎,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年湃窍,在試婚紗的時候發(fā)現(xiàn)自己被綠了扼菠。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片摄杂。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡坝咐,死狀恐怖循榆,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情墨坚,我是刑警寧澤秧饮,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站泽篮,受9級特大地震影響盗尸,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜帽撑,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一泼各、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧亏拉,春花似錦扣蜻、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至笙僚,卻和暖如春芳肌,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背肋层。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工亿笤, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人栋猖。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓净薛,卻偏偏與公主長得像,于是被迫代替她去往敵國和親掂铐。 傳聞我的和親對象是個殘疾皇子罕拂,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容