CocoaPods 可以說是 iOS 開發應用最廣泛的包管理工具,本篇文章主要介紹 CocoaPods 的第三方庫是怎樣從網絡集成到我們本地的項目當中,也是制作私有庫、開源庫和 iOS 項目組件化的一個知識鋪墊。
讓我們從一張圖片開始:
CocoaPods 工作流程 |
---|
未命名文件
|
遠程索引庫
遠程索引庫里存放的是各種框架的描述信息,這個庫托管在 Github 上,地址如下:
https://github.com/CocoaPods/Specs
每個框架下有數個版本,每個版本有一個 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
字段表示該框架的托管地址,也就是上面時序圖中的 遠程框架庫
。
本地索引庫
在 install cocoapods
命令后,需要執行 pod setup
這個命令,pod setup
命令就是將遠程索引庫克隆到本地來,本地索引庫的路徑如下:
~/.cocoapods/repos/master
本地索引庫和遠程索引庫的目錄一致,結構如下:
本地索引庫 |
---|
本地索引庫
|
本地索引文件
當執行 pod search
命令時,如果本地索引文件不存在,會創建這個文件。
tianziyaodeMacBook-Air:~ Tian$ pod search afn
Creating search index for spec repo 'master'..
如果這個文件存在,則會在此文件中進行索引,確認所需要的框架是否存在,本地索引文件的路徑如下:
~/資源庫/Caches/CocoaPods
制作 CocoaPods 庫
上面的流程清楚以后,制作 CocoaPods 庫相信應該不會太難了,大致分為以下幾步:
- 托管框架源碼到 Git;
- 創建框架描述信息;
- 上傳框架描述信息到
https://github.com/CocoaPods/Specs
; - 命令行
pod setup
, 創建本地索引庫; - 命令行
pod install
,將框架集成到項目中;
現在開始動手吧!首先在桌面新建一個 testLib
目錄,在該目錄下新建一個 Classes
目錄,用來存放框架源碼,然后將 testLib
托管到 Git。
你可以給 Classes 目錄任意的命名,Classes 只是一種約定俗稱的命名。
pod spec
pod spec
命令用于創建框架的描述信息文件,文檔如下:
https://guides.cocoapods.org/syntax/podspec.html
現在在 testLib
目錄下執行:
pod spec create testLib
目錄下會創建一個 testLib.podspec
文件,然后編輯這個文件,主要有以下幾個字段:
- version:這個 spec 映射的版本,保證 Git 的
releases
與此對應; - homepage:項目主頁;
- source:框架源代碼的托管地址;
- tag:與 version 對應;
- source_files:框架源代碼的目錄、文件、文件類型等規則;
CocoaPods 公開庫
根據上面的步驟,現在你需要將生成的 testLib.podspec
文件上傳到遠程索引庫,在此之前,你需要注冊一個 Trunk 賬號,文檔如下:
https://guides.cocoapods.org/making/getting-setup-with-trunk.html
現在執行下面的命令,記得修改郵箱昵稱描述等:
pod trunk register ziyao.tian@gmail.com 'Tian' --description='macbook air'
你的郵箱會收到一封郵件,打開郵件里面的鏈接,會有類似 you can back termainal
的提示,現在回到終端。
pod lib lint
檢查 testLib.podspec
的合法性,根據錯誤提示修復問題,當顯示 passed validation
后,執行下面的命令:
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
到遠程索引庫,CocoaPods 官方審核通過后,就可以出現在遠程索引庫中,當遠程索引庫收錄后:
pod setup
這時你的本地索引庫,會新加入 testLib.podspec
這條記錄,但是本地索引文件還未更新,因此刪除掉以下路徑的本地索引文件:
~/資源庫/Caches/CocoaPods/search_index.json
執行 pod search testLib
命令,當 search_index.json
文件重建完畢后,就可以在使用這個遠程框架庫了。
CocoaPods 私有庫
有了公開庫,當然也就有私有庫,私有庫主要分為遠程和本地兩種,什么時候會用到私用庫呢?也就是需要將源碼封裝成庫,但又不希望將源碼公開,一般的使用場景是公司內部的組件化開發。
本地私有庫
本地私有庫就是創建一個倉庫,將其存儲在本地,在本地的其他工程中直接使用。首先在桌面新建一個庫,路徑如下:
LocalLib/NetWork/Classes/Test.swift
接著創建一個殼工程,現在你的目標是使用 pod
的方式,將 NetWork
這個庫集成到殼工程中。
創建本地 GIt 倉庫
將 NetWork
加入到 Git,命令如下:
git init
git add.
git commit -m 'x'
創建庫描述文件
和公開庫一樣,我們需要先創建一個 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
現在你的本地庫已經準備完畢了,下面就可以使用這個庫了。
導入本地私有庫
現在進入到殼工程目錄下,執行命令:
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
關鍵字,它表示在 pod install
執行時,在指定的路徑下尋找 NetWork.podspec
文件。
下面執行 pod install
命令,提示信息如下:
Analyzing dependencies
Fetching podspec for `NetWork` from `../NetWork`
Downloading dependencies
Installing NetWork (0.0.1)
Generating Pods project
Integrating client project
現在 NetWork
這個庫就集成到了殼工程中。
與使用遠程庫不同,本地庫的源文件會在 Development Pods
這個目錄下,而不是 Pods
目錄,順便一提,CocoaPods 的庫開發,一般也是這樣搭建環境的,開發完成后再修改 spec
文件,將其 pull request
到遠程索引庫。
CocoaPods 模板庫
本地私有庫這個方式還存在以下問題:
- 需要手動創建
podspec
文件; - 無法單獨測試,需要依托于殼工程運行;
假設我們有一個基礎組件,里面全部是擴展文件,無法單獨運行,如果依托殼工程運行,只有這一個組件,那么這個殼工程實際跟測試工程是一樣的,但殼工程內有多個組件呢?
我們在殼工程中進行測試的話,不但要對其他的組件進行編譯,而且自己負責的組件也可能會收到其他組件的影響,這樣也就失去了組件化開發的本意,那么怎么優化呢?
單獨測試
首先在 LocalLib/NetWork/
路徑下創建一個測試工程 Example
,然后將 Classes
拖到這個測試工程中,這里需要注意的是,Example
和 Classes
是引用關系,不要 Copy。
簡單粗暴的拖拽,現在 Example
工程就可以使用 NetWork
庫了。
另外一種方式是將 NetWork
通過 CocoaPods 安裝在 Example
中,和安裝在殼工程一樣。
看到這里,是不是感覺很煩?就是想做個測試而已,還要拖來拖去,那么繁瑣。
不要著急下面來介紹一種更快捷高效的方式,執行下面的命令:
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
現在我們就有了一個 CocoaPods 的模板工程,它的結構是這樣的:
.
├── 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
的同級目錄,執行 pod install
,就完成了本地私有庫和其測試工程。
這一步可能會有 Swift 語言版本的問題,保持測試工程和私有庫源碼語言版本一致就可以。
遠程私有庫
遠程私有庫工作流程 |
---|
遠程私有庫
|
現在使用 pod lib create
就可以方便的生成一個本地私有庫了,但是本地私有庫有一定的局限性,例如:
- 需要在
Podfile
文件中主動指明路徑; - 版本升級不容易維護;
- 多人開發時,不方便進行合作;
遠程私有庫就可以方便的解決以上的問題,制作遠程私有庫分為以下幾個步驟:
- 創建私有 Git 遠程倉庫;
- 創建私有 CocoaPods 遠程索引庫;
- 創建 Pod 所需要的項目工程文件,并上傳到 Git 遠程私有庫;
- 驗證
podspec
描述文件; - 向私有 CocoaPods 遠程索引庫提交
podspec
描述文件; - 使用 Pod 庫;
Git 倉庫的創建在此就不在贅述了,本文中我使用碼市做示例,私有 CocoaPods 遠程索引庫實際上也是一個 Git 倉庫,現在我們有兩個私有庫,一個用來存放 Pod 庫的源碼,一個用來存放 Pod 庫的描述文件。
SSH 授權
添加私有索引庫需要使用 SSH 授權,也是和 Git 倉庫一樣的,了解的同學可以跳過這一步驟,首先創建公鑰:
ssh-keygen
然后找到下面的文件:
~/.ssh/id_rsa.pub
里面存放的字符就是公鑰了,然后將公鑰添加碼市,鏈接如下:
https://coding.net/user/account/setting/keys
添加私有遠程索引庫
現在執行 pod repo
,可以看到下面的信息:
master
- Type: git (master)
- URL: https://github.com/CocoaPods/Specs.git
- Path: /Users/Tian/.cocoapods/repos/master
現在我們只有一個 CocoaPods 遠程索引庫,也是官方的索引庫,下面執行:
pod repo add TZYSpecs git@git.coding.net:tianziyao/TZYSpecs.git
此時我們的 CocoaPods 遠程索引庫就安裝好了,到下面的路徑去看一下:
~/.cocoapods/repos
上傳源碼到 Git
還記得 pod lib create
命令嗎?前面我們使用它來制作了本地私有庫,現在它又排上用場了,執行:
pod lib create BaseComponent
源碼拖到 ReplaceMe.swift
的同級目錄,它現在看起來應該是這個樣子:
.
├── 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
執行 pod install
,就完成了本地私有庫和其測試工程,通過測試之后,我們就可以把這個本地私有庫制作成遠程私有庫了。
首先修改 BaseComponent.podspec
文件:
Pod::Spec.new do |s|
s.name = 'BaseComponent'
s.version = '0.1.0'
s.summary = '基礎組價'
s.description = '包括基本配置,常量,擴展,工具類等'
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
然后使用質量檢查工具驗證一下,保證在 BaseComponent.podspec
路徑下,執行:
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.
根據提示修復就好了,在這里你可能會遇到很多 Swift 語言版本的問題,善用搜索引擎吧,通過檢驗以后提示如下:
-> BaseComponent (0.1.0)
BaseComponent passed validation.
下面執行:
git add .
git commit -m 'x'
然后和遠程倉庫進行關聯:
git remote add origin https://git.coding.net/tianziyao/BaseComponent.git
git pull origin master
git push origin master
上傳 Spec 到遠程索引庫
首先執行下面的命令:
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.
根據提示,我們需要先建立一個 Tag:
git tag '0.1.0'
git push --tags
pod spec lint
檢驗通過后,提示如下:
-> BaseComponent (0.1.0)
Analyzed 1 podspec.
BaseComponent.podspec passed validation.
然后將 podspec
文件推到遠程私有索引庫:
pod repo push TZYSpecs BaseComponent.podspec
現在看一下本地索引庫中是否已經添加成功:
~/.cocoapods/repos
再看一看你的遠程索引庫中是否添加成功,現在搜索一下本地索引文件試試:
-> BaseComponent (0.1.0)
基礎組價
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]
現在我們可以找到自己的遠程私有庫了,下面將 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
執行 pod install
,整個遠程私有庫的搭建和使用就完成了。
CocoaPods 庫升級
我們使用遠程私有庫的目的就是為了版本升級和多人開發,那么遠程私有庫如何進行升級,升級后其他人又如何使用呢?現在我們給 BaseComponent
進行升級,給它再增加一些功能:
.
├── 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.podspec
的 version
修改一下:
Pod::Spec.new do |s|
s.name = 'BaseComponent'
s.version = '0.2.0'
s.summary = '基礎組價'
s.description = '包括基本配置,常量,擴展,工具類等'
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
現在檢查一下私有庫是否有錯誤:
pod lib lint
檢查通過后就可以將 BaseComponent
的 0.2.0
版本推到遠程私有庫中,同時建立 0.2.0
的 Tag。
然后檢查一下 spec
文件:
pod spec lint
檢查通過后,執行:
pod repo push TZYSpecs BaseComponent.podspec
遠程私有庫和遠程私有索引庫全部更新完畢,現在我們回到使用者的視角,這個庫可以使用了嗎?還不行。
因為本地的索引文件還沒有更新,這個源還找不到,現在進入殼工程,執行:
pod update --no-repo-update
pod install
BaseComponent
的 0.2.0
版本就乖乖的進入了殼工程。
CocoaPods 庫依賴
在上面的殼工程中,我們引入了 Alamofire
這個框架,但是如果用著用著突然覺得不爽了,要換框架,這時 Alamofire
的引用在工程中已經無處不再了,這樣換的話是不是很痛苦?
所以我們一般在開發中都會封裝網絡請求,做到分層解耦,這樣如果換框架,只修改網絡請求這層的封裝就可以了,那么現在我們需要將 Alamofire
封裝成 Network
,再把 Network
弄到我們的 BaseComponent
里面去,怎么做呢?
現在先將 Network
拖到 BaseComponent
的 Classes
目錄中,因為 BaseComponent
的測試工程沒有 Alamofire
,所以 Network
肯定是會報錯了,不要慌,下面我們修改 spec
文件:
Pod::Spec.new do |s|
s.name = 'BaseComponent'
s.version = '0.2.0'
s.summary = '基礎組價'
s.description = '包括基本配置,常量,擴展,工具類等'
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
的測試工程中,現在就可以使用 Alamofire
進行網絡請求封裝,直接 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)
}
}
現在再進行一次遠程私有庫升級,整個依賴就做好了,需要注意的是,已經做了依賴的話,相關的庫就可以從 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
現在是我們依賴的是公開庫,直接升級 CocoaPods 私有庫就可以,但是如果依賴的是另外一個私有庫,這個依賴關系最終還要上傳到私有索引庫中,這樣其他人在使用的時候才會知道這個依賴關系,現在走一下升級的流程,你會得到類似這個報錯:
[!] The `TargetComponent.podspec` specification does not validate.
這個報錯是因為 TargetComponent
這個庫沒有在官方的索引庫當中,忽略就可以了,當然,在使用的時候,TargetComponent
這個庫可以在你的本地索引文件中找到,否則無法使用。
CocoaPods 資源依賴
現在我們可以讓一個庫依賴另外一個庫,但是看下面這段代碼:
/// 獲取中間的視圖
open class func tabBarMiddleView() -> TZYTabBarMiddleView {
let view = Bundle.main.loadNibNamed("TZYTabBarMiddleView", owner: nil, options: nil)?.first
return (view as? TZYTabBarMiddleView) ?? TZYTabBarMiddleView()
}
這段代碼讀取了一個 XIB 文件,這個庫的結構是這樣的:
.
├── Assets
└── Classes
└── MainModule
├── Controller
│ ├── TZYNavBarC.swift
│ └── TZYTabBarC.swift
└── View
├── TZYNavBar.swift
├── TZYTabBar.swift
├── TZYTabBarMiddleView.swift
└── TZYTabBarMiddleView.xib
我們可以成功調用這個方法嗎?不能,因為 TZYTabBarMiddleView.xib
這個文件的 Target 是 MainModule
,使用 CocoaPods 把這個庫安裝到我們項目后,XIB 文件即使在,也是在 Pods 這個工程里,而我們在殼工程中使用 TZYTabBarMiddleView.xib
,也是必然找不到的。
下面我們把模板庫的測試工程編譯一下,打開 Products 目錄下的 .app
文件,看一下文件結構:
.
├── 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 庫并沒有對應的路徑,那么它所需要的圖片放在哪里,已經如何使用呢?現在使用 pod lib create
命令創建一個 Pod 庫,進入以下路徑:
組件名/Assets
把一些圖片拖入到 Assets
文件夾內,然后在 podspec
文件中加入以下代碼:
s.resource_bundles = {
'組件名' => ['組件名/Assets/*.png'] //只加載 png 文件
# '組件名' => ['組件名/Assets/*'] //加載所有文件
}
然后執行 pod install
,Pod 庫中就出現了之前拖入 Assets
文件夾的圖片,但是現在還不能使用,我們先來看一下打包以后這些圖片的路徑:
.
├── 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
下的資源文件,因此還是找不到的,那么這時使用圖片,應該將代碼改成這樣:
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 中加載圖片,應該怎樣做呢?那么再看一下上面的目錄結構,TZYTabBarMiddleView.nib
和 TargetComponent.bundle
處于同一個目錄,我們可以在 TZYTabBarMiddleView.xib
中通過相對路徑,使用 TargetComponent.bundle
里面的圖片,因此在 XIB 中,圖片名應該是這樣的:
TargetComponent.bundle/tabbar_bg_320x49_@3x
CocoaPods 子庫
現在我們實現了一個完整的遠程私有庫,可以升級,依賴其他的庫,提供給其他人使用,但是現在還有一點問題,其他人如果要用我們的庫,就需要把 BaseComponent
完整的克隆過來,但是他可能只需要 BaseComponent
里面的 Network
,其他的擴展、工具等并不想使用,也不想導入過來,怎么辦?有兩種方案:
- 把
Network
剝離出來,再單獨建一個遠程私有庫; - 使用子庫遷出
Network
;
第一種方案大家已經知道了,就是上面的一大篇,麻煩不說,而且東西一多起來,這里一個庫,那里一個庫,也不容易管理,所以,下面就有請子庫隆重登場。
在開始之前,我們先來開一個東西,下面是 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
這里,它就是本節要講的東西,首先將 spec
改成下面這樣:
Pod::Spec.new do |s|
s.name = 'BaseComponent'
s.version = '0.4.0'
s.summary = '基礎組價'
s.description = '包括基本配置,常量,擴展,工具類等'
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_files
和 dependency
以及版本的變化,修改完成推到遠程索引庫,并打好 0.4.0
的分支,執行:
pod spec lint
pod repo push TZYSpecs BaseComponent.podspec
pod update --no-repo-update
pod search Base
現在就可以找到了:
-> BaseComponent (0.4.0)
基礎組價
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
現在 pod install
,就完成了子庫的創建和使用。
結尾
這篇文章斷斷續續寫了快一周,其實一般我們用不到 CocoaPods 這些功能,不過了解一下 CocoaPods 的工作原理也是沒有壞處的。
這篇文章主要是為了使用 CocoaPods 進行組件化開發,關于組件化開發的思想,可以看下面這篇文章: