CocoaPods 私有库 step by step

作者: Vinc | 来源:发表于2017-12-04 10:52 被阅读199次

    目录


    环境

    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' 的命令来直接引用子库了。

    相关文章

      网友评论

      • LogLT:就是 你文章中“2、生成的Workspace结构“的那张图片中,的 2中写代码,push 4中controller。但是不现实,加载不上。
        但是在其它工程中添加pod。用4就没问题。
        Vinc:更新到最新稳定版本的 CocoaPods 后,在修改代码后,执行一下 pod install 或是 pod update 试试?
      • LogLT:你好,有个问题咨询下,我这pod lib create的 demo工程 demo中的controller push 的pod文件的controller。无法显示。但是生产pod后。在其它工程使用,没有问题。是什么情况?demo工程的配置问题吗?

      本文标题:CocoaPods 私有库 step by step

      本文链接:https://www.haomeiwen.com/subject/gphtixtx.html