你真的會用 CocoaPods 嗎?

CocoaPods 能夠說是 iOS 開發應用最普遍的包管理工具,本篇文章主要介紹 CocoaPods 的第三方庫是怎樣從網絡集成到咱們本地的項目當中,也是製做私有庫、開源庫和 iOS 項目組件化的一個知識鋪墊。html

讓咱們從一張圖片開始:ios

CocoaPods 工做流程
未命名文件

遠程索引庫

遠程索引庫裏存放的是各類框架的描述信息,這個庫託管在 Github 上,地址以下:git

github.com/CocoaPods/S…github

每一個框架下有數個版本,每一個版本有一個 json 格式的描述信息,以下: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 字段表示該框架的託管地址,也就是上面時序圖中的 遠程框架庫swift

本地索引庫

install cocoapods 命令後,須要執行 pod setup 這個命令,pod setup 命令就是將遠程索引庫克隆到本地來,本地索引庫的路徑以下:xcode

~/.cocoapods/repos/master
複製代碼

本地索引庫和遠程索引庫的目錄一致,結構以下:ruby

本地索引庫
本地索引庫

本地索引文件

當執行 pod search 命令時,若是本地索引文件不存在,會建立這個文件。bash

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

若是這個文件存在,則會在此文件中進行索引,確認所須要的框架是否存在,本地索引文件的路徑以下:網絡

~/資源庫/Caches/CocoaPods
複製代碼

製做 CocoaPods 庫

上面的流程清楚之後,製做 CocoaPods 庫相信應該不會太難了,大體分爲如下幾步:

  1. 託管框架源碼到 Git;
  2. 建立框架描述信息;
  3. 上傳框架描述信息到 https://github.com/CocoaPods/Specs
  4. 命令行 pod setup , 建立本地索引庫;
  5. 命令行 pod install ,將框架集成到項目中;

如今開始動手吧!首先在桌面新建一個 testLib 目錄,在該目錄下新建一個 Classes 目錄,用來存放框架源碼,而後將 testLib 託管到 Git。

你能夠給 Classes 目錄任意的命名,Classes 只是一種約定俗稱的命名。

pod spec

pod spec 命令用於建立框架的描述信息文件,文檔以下:

guides.cocoapods.org/syntax/pods…

如今在 testLib 目錄下執行:

pod spec create testLib
複製代碼

目錄下會建立一個 testLib.podspec 文件,而後編輯這個文件,主要有如下幾個字段:

  • version:這個 spec 映射的版本,保證 Git 的 releases 與此對應;
  • homepage:項目主頁;
  • source:框架源代碼的託管地址;
  • tag:與 version 對應;
  • source_files:框架源代碼的目錄、文件、文件類型等規則;

CocoaPods 公開庫

根據上面的步驟,如今你須要將生成的 testLib.podspec 文件上傳到遠程索引庫,在此以前,你須要註冊一個 Trunk 帳號,文檔以下:

guides.cocoapods.org/making/gett…

如今執行下面的命令,記得修改郵箱暱稱描述等:

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 拖到這個測試工程中,這裏須要注意的是,ExampleClasses 是引用關係,不要 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 文件中主動指明路徑;
  • 版本升級不容易維護;
  • 多人開發時,不方便進行合做;

遠程私有庫就能夠方便的解決以上的問題,製做遠程私有庫分爲如下幾個步驟:

  1. 建立私有 Git 遠程倉庫;
  2. 建立私有 CocoaPods 遠程索引庫;
  3. 建立 Pod 所須要的項目工程文件,並上傳到 Git 遠程私有庫;
  4. 驗證 podspec 描述文件;
  5. 向私有 CocoaPods 遠程索引庫提交 podspec 描述文件;
  6. 使用 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.podspecversion 修改一下:

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
複製代碼

檢查經過後就能夠將 BaseComponent0.2.0 版本推到遠程私有庫中,同時創建 0.2.0 的 Tag。

而後檢查一下 spec 文件:

pod spec lint
複製代碼

檢查經過後,執行:

pod repo push TZYSpecs BaseComponent.podspec
複製代碼

若是存在警告,能夠執行:

pod repo push xxx xx.podspec --verbose --allow-warnings
複製代碼

遠程私有庫和遠程私有索引庫所有更新完畢,如今咱們回到使用者的視角,這個庫可使用了嗎?還不行。

由於本地的索引文件尚未更新,這個源還找不到,如今進入殼工程,執行:

pod update --no-repo-update
pod install
複製代碼

BaseComponent0.2.0 版本就乖乖的進入了殼工程。

CocoaPods 庫依賴

在上面的殼工程中,咱們引入了 Alamofire 這個框架,可是若是用着用着忽然以爲不爽了,要換框架,這時 Alamofire 的引用在工程中已經無處再也不了,這樣換的話是否是很痛苦?

因此咱們通常在開發中都會封裝網絡請求,作到分層解耦,這樣若是換框架,只修改網絡請求這層的封裝就能夠了,那麼如今咱們須要將 Alamofire 封裝成 Network,再把 Network 弄到咱們的 BaseComponent 裏面去,怎麼作呢?

如今先將 Network 拖到 BaseComponentClasses 目錄中,由於 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 installAlamofire 就安裝到了 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 這個庫能夠在你的本地索引文件中找到,不然沒法使用。 保險起見,你也能夠在驗證和提交時使用 --sources 命令,例如:

pod repo push TZYSpecs TargetComponent.podspec --sources=git@git.coding.net:tianziyao/TZYSpecs.git,master
複製代碼

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.nibTargetComponent.bundle 處於同一個目錄,咱們能夠在 TZYTabBarMiddleView.xib 中經過相對路徑,使用 TargetComponent.bundle 裏面的圖片,所以在 XIB 中,圖片名應該是這樣的:

TargetComponent.bundle/tabbar_bg_320x49_@3x
複製代碼

CocoaPods 子庫

如今咱們實現了一個完整的遠程私有庫,能夠升級,依賴其餘的庫,提供給其餘人使用,可是如今還有一點問題,其餘人若是要用咱們的庫,就須要把 BaseComponent 完整的克隆過來,可是他可能只須要 BaseComponent 裏面的 Network,其餘的擴展、工具等並不想使用,也不想導入過來,怎麼辦?有兩種方案:

  1. Network 剝離出來,再單獨建一個遠程私有庫;
  2. 使用子庫遷出 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_filesdependency 以及版本的變化,修改完成推到遠程索引庫,並打好 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 進行組件化開發,關於組件化開發的思想,能夠看下面這篇文章:

iOS 組件化實踐思考

相關文章
相關標籤/搜索