CocoaPods 私有库 step by step

目录


环境

macOS 10.12.6
Xcode 9.1
CocoaPods 1.3.1
Swift 4.0


TL;DR(步骤概述)

1、创建示例工程
pod lib create XGLib
2、编写 Pod 库

如果使用了 Swift,需要指定 Swift 版本:在 Terminal 中的项目目录下,输入 echo "4.0" > .swift-version,会在项目根目录下生成一个 .swift-version 文件

3、Build 项目后,在 Demo 工程中调用
4、修改 podspec 文件

必须修改字段:

s.version
s.summary
s.source
5、本地校验pod lib lint
6、提交代码到远程仓库
7、为项目打上tag,并推送远端
git tag -m "first release v0.0.1" 0.0.1
git push --tags     #推送tag到远端仓库
8、联网校验pod spec lint
9、创建私有的 Spec 索引库

如果已经创建过,就不需要再创建了

10、将创建的私有 Spec 索引库添加到CocoaPods的目录下

如果已经添加过,就不需要再添加了

pod repo add CodingSpecRepo https://coding.net/u/rxg9527/p/SpecRepo
11、添加 Podspec 到私有 Spec 索引库中
pod repo push CodingSpecRepo XGLib.podspec
More: 私有库升级,添加库依赖,图片依赖,私有库子库

一、在CocoaPods的指令帮助下创建一个示例工程

# 指令
pod lib create MyLibrary
# 示例
pod lib create XGLib

之后会有一系列问题:

  1. 使用语言
  2. 是否需要为你创建一个Demo应用
  3. 想要使用哪个测试框架
  4. 是否需要UI Test
  5. 使用语言为Objective-C的话,会询问Objective-C类前缀使用什么

这里在第2个问题中输入Yes来创建一个Demo应用,以更好的调试和自测Pods库代码。

image


1、Pod Lib Create生成的模版
XGLib目录结构
├── .travis.yml
├── _Pods.xcproject
├── Example
│   ├── XGLib
│   ├── XGLib.xcodeproj
│   ├── XGLib.xcworkspace
│   ├── Podfile
│   ├── Podfile.lock
│   ├── Pods
│   └── Tests
├── LICENSE
├── XGLib.podspec
├── Pod
│   ├── Assets
│   └── Classes
│     └── RemoveMe.[swift/m]
└── README.md

文件:

  • .travis.yml - a setup file for travis-ci.
  • _Pods.xcproject - a symlink to your Pod's project for 支持Carthage
  • LICENSE - 默认MIT License.
  • XGLib.podspec - 该库的Podspec
  • README.md - 默认README
  • RemoveMe.swift/m - a single file to to ensure compilation works initially.

文件夹:

  • Pod - 个人Pods库的所有类
  • Example - 生成的Demo

2、生成的Workspace结构
workspace结构
  1. 编辑 Podspec metadata, 更改 README 和 Podspec
  2. Demo 工程
  3. 测试
  4. Pods 开发文件夹,真正修改类的区域。
  5. Finally the Pods used in setting Up the project.

注意:Swift的Class和function要声明为public,才能在Demo中可用


3、Development Pods文件夹

Development Pods 不同于普通的 CocoaPods,是 symlinked files,所以编辑 这些文件会改变源文件,因此可以在 Xcode 中做更改。Demo 和测试文件需要通过#import <MyLib/XYZ.h>的方式引入头文件。

注意: 因为 Development Pods 的实现细节, 当添加文件到 Pod/ClassesPod/Assets 或 更新 podspec,需要执行 pod installpod update
例如我们创建的 XGLib,在 pod lib create XGLib 的过程中已经执行过了 pod install ,之后添加文件只需执行 pod update


二、实际编写 Pod 库(类库代码仅作参考)

1、在XGLib中编写一个文件

Pod/Classes 目录下删除 RemoveMe.swift,创建一个 UILabel-Extension.swift,代码如下:

// Swift4.0代码(3.0可用)
//  UILabel-Extension.swift
//  XGLib

import Foundation

extension UILabel {
 
    convenience public init(bgColor: UIColor?,
                            text: String?,
                            textColor: UIColor?,
                            fontSize: CGFloat?,
                            isBold: Bool?,
                            textAlignment: NSTextAlignment?,
                            numberOfLines: Int?) {
        self.init()
        
        if let color = bgColor {
            backgroundColor = color
        }
        if let text = text {
            self.text = text
        }
        if let textColor = textColor {
            self.textColor = textColor
        }
        
        if let fontSize = fontSize {
            if let isBold = isBold {
                if isBold {
                    font = UIFont.boldSystemFont(ofSize: fontSize)
                } else {
                    font = UIFont.systemFont(ofSize: fontSize)
                }
            } else {
                font = UIFont.systemFont(ofSize: fontSize)
            }
        }
        
        if let textAlignment = textAlignment {
            self.textAlignment = textAlignment
        }
        
        if let numberOfLines = numberOfLines {
            self.numberOfLines = numberOfLines
        }        
    }

}

2、Build 项目后,在 Demo 工程中调用

⌘+B build项目(不先build的话,没有代码提示),之后 import 该项目,在 ViewController 中调用。成功运行项目。

image


3、修改 podspec 文件

podspec 文件主要有以下几个字段:

  • version:这个 spec 映射的版本,保证 Git 的 releases 与此对应;
  • homepage:项目主页;
  • source:框架源代码的托管地址;
  • tag:与 version 对应;
  • source_files:框架源代码的目录、文件、文件类型等规则;
image

4、如果类库使用了 Swift 语言,需要指定 Swift 版本

在终端中的项目目录下,输入 echo "4.0" > .swift-version,会在项目根目录下生成一个 .swift-version 文件,如图

image


5、提交代码到远程仓库

这里我个人提交到了国内的代码托管平台Coding,网址在rxg9527 - XGLib

同时根据我们输入的 s.version 版本号,我们要对相应的提交记录打上Tag,并Push到远程

git tag -m "first release v0.0.1" 0.0.1
git push --tags     #推送tag到远端仓库
image

6、校验私有库

我们可以用 pod lib lintpod spec lint 两条命令来对类库做验证。

  • pod lib lint
    本地检查 Pods,主要校验 podspec 文件

  • pod spec lint
    远程检查 Pods,这次 CocoaPods 会根据 podspec 文件里的 source 检查对应的仓库里有没有指定tag的仓库

这时如果一切顺利,Pod库的编写就大功告成,通过 CocoaPods 的质检环节了。


三、通过私有的 Spec 索引库管理使用私有库

1、创建私有的 Spec 库

团队或个人自建的Pods私有库编写完成后,我们需要创建一个私有的Spec库来存放。而 CocoaPods 所有的公有库都是存放在 CocoaPods 官方建立的 Spec 索引仓库中的。

示例中,我使用国内的Coding来存放 Spec 库。

image

2、将第1步创建的私有SpecRepo添加到CocoaPods的目录下
# 指令
pod repo add REPO_NAME SOURCE_URL
# 示例
pod repo add CodingSpecRepo https://coding.net/u/rxg9527/p/SpecRepo

此时添加的「私有SpecRepo」目录是在~/.cocoapods/repos/下的
[图片上传失败...(image-1ff75c-1512367322220)]

去检查一下这步添加操作是否成功

# 指令
cd ~/.cocoapods/repos/REPO_NAME
pod repo lint .
# 示例
cd ~/.cocoapods/repos/CodingSpecRepo
pod repo lint .
image

3、添加 Podspec 到私有 Spec 索引库中

首先确认已经为私有库打过tag并设置了version,然后运行

# 指令
pod repo push REPO_NAME SPEC_NAME.podspec
# 示例
pod repo push CodingSpecRepo XGLib.podspec

这条指令默认会执行 pod spec lint 做校验。

此时 ~/.cocoapods/repos/REPO_NAME下的目录结构会是

.
├── Specs
    └── [SPEC_NAME]
        └── [VERSION]
            └── [SPEC_NAME].podspec

本地 Spec 索引库目录结构
远程 Spec 索引库目录结构

4、使用私有库

现在私有库就可以在 Podfile 文件中指定使用了,通过 source 目录 的方式使用私有 Spec 索引库:

# 指令
source 'URL_TO_REPOSITORY'
# 示例
source 'https://coding.net/u/rxg9527/p/SpecRepo/git'

整个 Podfile 文件:

source 'https://github.com/CocoaPods/Specs.git' # CocoaPods 官方 Spec 索引库
source 'https://coding.net/u/rxg9527/p/SpecRepo/git'

platform :ios, '8.0'
use_frameworks!

target 'UsePrivatePodDemo' do
    pod 'XGLib', '~>0.0.1'
end

UsePrivatePodDemo 工程中,⌘+B build项目(不先build的话,没有代码提示),之后 import 该项目,在 ViewController 中调用。成功运行项目。


四、Other

1、私有库升级

UILabel-Extension.swift 添加方法:

import Foundation

extension UILabel {
    ……
    ……    
        /// 背景透明,不加粗,居中对齐
    convenience public init(centerText: String?,
                            textColor: UIColor?,
                            fontSize: CGFloat?) {
        self.init(bgColor: nil, text: centerText, textColor: textColor, fontSize: fontSize, isBold: false, textAlignment: .center, numberOfLines: nil)
    }
    
    /// 背景透明,加粗,居中对齐
    convenience public init(centerBoldText: String?,
                            textColor: UIColor?,
                            fontSize: CGFloat?) {
        self.init(bgColor: nil, text: centerBoldText, textColor: textColor, fontSize: fontSize, isBold: true, textAlignment: .center, numberOfLines: nil)
    }
    
}

然后跟之前一样:

  1. 在 Demo 工程中调用确认没问题
  2. pod lib lint本地校验
  3. 修改 podspec 文件,至少要修改提高 version
  4. 提交代码到远程仓库
  5. 根据 s.version 版本号,对相应的提交记录打 tag,并 Push 到远程
  6. pod spec lint联网校验
  7. pod repo push REPO_NAME SPEC_NAME.podspec,即pod repo push CodingSpecRepo XGLib.podspec

Okay, That's it!

远程私有库和远程私有索引库全部更新完毕,现在这个库只要更新本地的索引文件就可以使用了

pod update --no-repo-update
pod install

2、CocoaPods 库依赖

假设我们封装的私有库要基于某个公有库做封装,比如常见的项目中需要我们基于 Alamofire 做一层业务上的封装📦,那么如何在私有库的制作中,优雅的导入 Alamofire 呢?
CocoaPods 为我们提供了这种能力,通过修改 podspec 文件中的 s.dependency 字段就可以完成,同时可以像 Podfile 中那样指定版本号。
dependency 指明了这个库的依赖,下面我们通过依赖 Kingfisher 来示范:

1、 在 XGLib.podspec 中加入

s.dependency 'Kingfisher', '~> 4.0'

2、 新建 UIImageView-Extension.swift
3、 在 Demo 工程中执行 pod update --no-repo-update 会引入 KingfisherUIImageView-Extension.swift
4、 完成 UIImageView-Extension.swift

//
//  UIImageView-Extension.swift

import Foundation
import Kingfisher

extension UIImageView {
    
    public func setImage(with url: URL?) {
        self.kf.setImage(with: url)
    }
    
}

5、⌘+B build项目(不先build的话,没有代码提示),import 该项目,在 ViewController 中调用。

let iv = UIImageView(frame: CGRect(x: 20, y: 120, width: 280, height: 400))
iv.setImage(with: URL(string: "http://wx3.sinaimg.cn/large/9d0d09ably1fl8ilobp1sj213d1jv7e8.jpg"))
view.addSubview(iv)
image

6、像上一步私有库升级一样,开始升级流程


3、CocoaPods 图片依赖

Pod 库中的图片、音频、视频,一般在路径组件名/Assets中。
我们可以把一些图片拖入到 Assets 文件夹内,然后在 podspec 文件中加入以下代码:

s.resource_bundles = {
  'XGLib' => ['XGLib/Assets/*.png']
}

2、 在 Demo 工程中执行 pod update --no-repo-update 会引入图片资源
3、 ⌘+B build项目(不先build的话,没有代码提示),import 该项目,在 ViewController 中调用。

let iv2 = UIImageView(frame: CGRect(x: 120, y: 50, width: 200, height: 200))
let privatePodBundle = Bundle(for: privatePodClass.self)
if let path = privatePodBundle.path(forResource: "eat_full.png", ofType: nil, inDirectory: "XGLib.bundle") {
    iv2.image = UIImage(contentsOfFile: path)
}
view.addSubview(iv2)

4、像上一步私有库升级一样,开始升级流程


4、CocoaPods 子库

CocoaPods 有一个子库的概念,我们在使用一个库时,可能只需要里面一部分的功能,这时子库就起到了作用。作为范例,我们可以看一下 pod search AFNetworking 来看一下:

-> 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 就是 AFNetworking 的子库了,可以看到为了满足开发者的不同需求, AFNetworking 作者贴心的为我们制作了子库供调用。

我们也来实践一下子库的操作,首先整理XGLib/Classes目录结构
[图片上传失败...(image-889d58-1512367322220)]

其实修改 podsepc 文件,修改后如下

Pod::Spec.new do |s|
  s.name             = 'XGLib'
  s.version          = '0.2.0'
  s.summary          = '创建CocoaPods私有库教程的示例工程'
  s.description      = <<-DESC
创建CocoaPods私有库教程的示例工程,1年半前就想写了……Orz
升级0.2.0 加入子库,修改子库dependency
                       DESC

  s.homepage         = 'https://coding.net/u/rxg9527/p/XGLib/git'
  # s.screenshots     = 'www.example.com/screenshots_1', 'www.example.com/screenshots_2'
  s.license          = { :type => 'MIT', :file => 'LICENSE' }
  s.author           = { 'ruanxiaogang' => 'rxg9527@sina.cn' }
  s.source           = { :git => 'https://git.coding.net/rxg9527/XGLib.git', :tag => s.version.to_s }
  s.social_media_url = 'https://weibo.com/rxg9527'
  s.ios.deployment_target = '8.0'
  s.source_files = 'XGLib/Classes/**/*'
  
  s.resource_bundles = {
    'XGLib' => ['XGLib/Assets/*.png']
  }
  
  # s.public_header_files = 'Pod/Classes/**/*.h'
  # s.frameworks = 'UIKit', 'MapKit'
  
  s.subspec 'ImageView' do |i|
    i.source_files = 'XGLib/Classes/ImageView/**/*'
    s.dependency 'Kingfisher', '~> 4.0'
  end

  s.subspec 'Label' do |l|
    l.source_files = 'XGLib/Classes/Label/**/*'
  end

end

这里要注意 source_filesdependency 的变化,修改好之后,像之前私有库升级一样,开始升级流程。

一切顺利的话,现在我们执行 pod search XGLib 后,出来的搜索结果会是这样:

-> XGLib (0.2.0)
   创建CocoaPods私有库教程的示例工程
   pod 'XGLib', '~> 0.2.0'
   - Homepage: https://coding.net/u/rxg9527/p/XGLib/git
   - Source:   https://git.coding.net/rxg9527/XGLib.git
   - Versions: 0.2.0, 0.1.2, 0.1.1, 0.1.0, 0.0.2, 0.0.1 [CodingSpecRepo repo]
   - Subspecs:
     - XGLib/ImageView (0.2.0)
     - XGLib/Label (0.2.0)

这时我们就可以通过类似 pod 'XGLib/Label', '~>0.1' 的命令来直接引用子库了。