美文网首页iOS 伪组件专题
Pods依赖库快速开发入门

Pods依赖库快速开发入门

作者: Startry | 来源:发表于2016-02-24 11:24 被阅读1046次

    CocoaPods是所有iOS开发熟知的一个第三方类库依赖管理工具。只要稍微有些经验的iOS开发者都会使用三方依赖库管理工具来管理工程依赖, CocoaPods是目前最火热权威的管理工具。

    CocoaPods的基本使用现在网站上遍历都是的教程, 官方文档的简明教程也足够清晰明朗。本篇文章主要告诉大家如何去开发一个CocoaPods依赖库, 重点内容分三块:

    1. 如何创建一个Pod Repo
    2. 如何将库提交到中央Spec库或私有Spec库中供大家使用
    3. 如何在开发中添加resource、framework以及其它依赖

    创建一个Pod Repo

    通过模板创建

    关于如何创建一个Pod Repo, @wtlucky_星魂丨飘渺灬的一篇博文使用Cocoapods创建私有podspec里有介绍如何使用pod lib create (libName)去创建一个Pod Repo。简单示例如下:

    pod lib create STDemoKit
    

    执行如上命令, 根据lib需要选择对应的语言(Objc/Swift)、是否需要生产示例项目以及是否需要基础测试target等选项, 就会生产一个默认的名叫STDemoKit的Pod库。

    就这么一行命令, 自己动手敲一把, 绝对印象会加深很多的~


    手动创建

    CocoaPods会利用自带的模板去创建, 非常简单方便使用, 本文就不再赘述, 只是描述下如何手动去创建一个Pod Repo。

    手动创建CocoaPods库的关键在于描述文件podspec, 手动创建私有库的第一步就是复制或新建一个podspec。(podspec格式描述固定, 直接从官方网站复制来的快)

    手动创建私有库的关键两行代码在于:

    Pod::Spec.new do |spec|
      spec.name          = 'STDemoKit'
      spec.source_files  = 'MyLib/Classes/**/*.{h,m,c}'
    ## 补充必要的一些描述, 用于通过lint校验
    end
    

    在podspec所在文件夹下创建一个名为MyLib的文件夹, 并在MyLib文件夹下创建一个名为Classes*的文件夹, 放置自己实现的示例代码在该文件夹下。

    自己动手创建podspec示例

    通过上述的步骤, 已经创建了自己的pod库, 然后需要的是本地测试, 测试自己的创建的本地库需要再创建一个Example工程, 同时在Podfile中指定本地库所在位置, 示例如下:

    pod "STDemoKit", :path => "~/目标库地址"
    

    在Podfile中指定本地的库地址后, 执行下pod install即可测试自己创建的库了。

    如何提交库到Spec

    在告诉读者怎么提交库到Spec的时候, 需要问大家一个问题: 什么是Spec?

    我引用和翻译一下官方文档的描述:

    PodSpec(Spec)是一个用来描述一个固定版本的Pod库的文件, 根据版本推移, 一个库会有多个PodSpec(Spec)文件去描述它。该描文件描述了该版本库的引用地址、需要引用的文件、应用编译配置项以及类似库名字、库版本和描述相关的其它元数据。

    A Podspec, or Spec, describes a version of a Pod library. One Pod, over the course of time, will have many Specs. It includes details about where the source should be fetched from, what files to use, the build settings to apply, and other general metadata such as its name, version, and description.

    利用CocoaPods模板创建的库的podspec描述文件如下:

    PodSepc文件示例

    回归主题: 怎么提交Spec

    使用Cocoapods创建私有podspec中有一个章节《向Spec Repo提交podspec》, 该章节有<font color='red'>详细</font>的说明介绍如果向Pod库提交podspec, 本文只是列出两个命令, 方便大家快速查阅, 分别是提交podspec验证podspec有效性的命令。

    一般情况下, 都需要先执行下有效性验证才会去向Spec库提交自己的podspec, 这个是开发者的基本素质吧~

    验证podspec有效性命令:

    # 需要在podspec文件所在目录下执行
    pod lib lint
    

    提交podspec命令:

    pod repo push 索引库名 STDebugConsole.podspec
    

    补充:
    关于索引库, 有区分官方库和非官方库。一般大公司都会维护一个官方索引库自有索引库官方索引库一般是git官方库的一个镜像, 为了加快公司内对库索引更新的速度。自由索引库一般维护了公司业务产品自有依赖的基础组件和业务组件。

    Repo添加文件依赖

    在实际工程开发过程中, 我发现很多童鞋都不了解怎么去添加资源文件到工程中, 其实我自己一开始也不太了解哈, 后面在工程应用中逐渐熟悉起来的。我结合自己的使用经验以及参考CocoaPods官方描述文档, 在这里简单描述一下。

    我先举几个常用的实际场景:

    添加framework

    假设我们已经通过前面说的模板去创建了一个私有库STShareKit, 然后我需要往STShareKit库添加分享库ShareSDK.framework, 我是不是直接和开发普通工程一样直接往文件目录一拖就好了呢? <font color='orange'>实践证明这种方式是不可取的</font>。

    因为STShareKit本身是一个库, 如果直接网里面拖framework, 只会把对应的target引用写进项目的pbproj下, 只是一次性的被根项目引用, 并且不能被库本身引用, 因此通过纯粹的拖动是不可取的。(其实本人觉得如果Xcode做的智能点, 应该是可以解决这个问题的, 吐槽下)

    参考前面PodSepc文件示例的podspec文件描述, 核心解决关键在于下述代码:

    s.vendored_frameworks = [
        'Pod/Frameworks/*.framework'
    ]
    s.frameworks = 'UIKit', 'Foundation'
    

    通过在podspec中添加上述两个文件描述并执行一次pod install, 一个可以解决第三方动态库, 一个可以添加本身库依赖的系统库。

    大家会不会好奇通过podspec描述的文件是怎么添加上去的, 是怎么被主工程和库给引用的。对Xcode环境配置熟悉的童鞋肯定能够猜到, 环境配置不是在pbproj描述下就是通过xcconfig进行注入的。如果大家对xcconfig想要进一步了解, 请大家移步我之前写的文章《iOS开发必备 - 环境变量配置(Debug & Release)》

    那么我们打开STShareKit.xcconfig文件进行一探究竟。(需要在引用工程执行完pod install命令才会生成)。

    FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/../Pod/Frameworks"
    GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
    HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" # ...此处有省略
    

    第一行FRAMEWORK_SEARCH_PATHS基本已经解除了大家的困惑了吧~

    添加资源文件

    添加资源文件的方式和添加第三方framework的方式相同, 核心解决关键在下述代码:

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

    这里有个特殊的地方, 通过上述写法书写的方式在pod命令执行过程中会创建一个名为ONESDriver.bundle的bundle来包含所有防止在物理目录Pod/Assets下的资源文件。

    添加资源文件还有另外一种方式(不推荐):

    s.resources = 'Pod/Assets/**/*'
    

    通过这种方式写法会被所有的资源文件不添加bundle直接copy进入主工程, 很容易发生重名冲突等问题, 不建议用这个写法~

    补充: 大家如果把上述描述文件修改和下面一样, 大家猜猜会发生什么事情呢? (库名为STShareKit)

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

    接下来抛给大家一个问题, 资源文件是怎么添加到主工程里的, 是通过xcconfig吗?
    我一开始以为是通过xcconfig进行配置, 后面并没有找到对应的配置项目, 在工程下面的Build Phases, CocoaPods会默认添加一个执行脚本:

    Build Phases拷贝脚本

    打开Target Support Files目录下Pods文件夹下的Pods-resources.sh脚本文件, 全局搜索STShareKit.bundle, 可以发现在脚本里有如下代码:

    install_resource "${BUILT_PRODUCTS_DIR}/STShareKit.bundle"
    

    看到这行代码基本已经解释了整个bundle是怎么进去到主工程里的了, 具体的细节请大家自行研究install_resource的实现。

    源代码分目录(区分group)

    做个私有库开发或者细心的童鞋会发现, 本身在开发库时候明明已经区分了物理目录的, 但是在引用工程里的Pods文件夹却是平铺展开的。对于处女座的开发者来说, 都是一怔灾难, 平铺看上怎么都是别扭的。以知名库JSONModel为例子:

    开发库时候的目录分级:

    JSONModel源码中目录

    引用库时候的目录分级:

    JSONModel引入后目录

    是不是看到这个平级目录很抓狂~ 官方Guide来解救有代码整齐强迫症的童鞋们了, 在A specification with subspecs章节, 有如下的一个样本podspec

    Pod::Spec.new do |spec|
        spec.name          = 'ShareKit'
        spec.source_files  = 'Classes/ShareKit/{Configuration,Core,Customize UI,UI}/**/*.{h,m,c}'
        # ...
    
        spec.subspec 'Evernote' do |evernote|
        evernote.source_files = 'Classes/ShareKit/Sharers/Services/Evernote/**/*.{h,m}'
    end
    
    spec.subspec 'Facebook' do |facebook|
        facebook.source_files   = 'Classes/ShareKit/Sharers/Services/Facebook/**/*.{h,m}'
        facebook.compiler_flags = '-Wno-incomplete-implementation -Wno-missing-prototypes'
        facebook.dependency 'Facebook-iOS-SDK'
    end
    
    # ...
    end
    

    呵呵, 有强迫症的童鞋是否已经找到了救星了呢? 通过描述subspec来对代码进行不同的层级区分, 这样使得引用的库能够有一定的层次感, 阅读和逻辑结构更加清晰。

    想要了解的更加清晰, 可以参考知名库AFNetworkingpodspec实现以及引用时候其生产的目录结构!

    总结

    关于如何使用如何使用CocoaPods创建私有库, 个人感觉使用Cocoapods创建私有podspec已经写的非常的详细, 本篇文章的意义不大。本篇文章对于开发私有库时候的文件等资源文件添加的细节进行了一些补充, 方便大家更加快速的入门, 对于各路高手来说, 这篇文章只有带人引路的作用。

    PS: 水平有限, 有错误的地方请及时指出~

    参考文献

    1. 使用Cocoapods创建私有podspec
    2. CocoaPods官方指南

    相关文章

      网友评论

        本文标题:Pods依赖库快速开发入门

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