iOS组件化 - 公共组件库的制作

iOS组件化 - 公共组件库的制作

2019-12-09 | |

前言

对于iOS开发者来说,在项目中使用别人写好的第三方库是非常普遍的一种现象,而通常我们会使用 CocoaPods 来管理项目所依赖的第三库。本文主要介绍如何将写好的代码制作成组件发布到 CocoaPods 上,让别的开发人员可以使用。

博文中引用的 Demo 已经上传到 github 上面了,有需要的小伙伴可以去下载

介绍

索引文件

也叫描述文件,用来描述组件信息的文件。每个组件库都会有一个描述文件与之对应,以 组件名.podspec 的文件形式存在,一般与组件源码所在的目录同级。索引文件中记录了组件的名称、作者、版本号、源码地址、系统要求等很多与组件相关的配置信息,Cocoapods 就是通过这些信息来查找我们组件的源码的。

索引库

存放组件索引(描述)文件的仓库。CocoaPods 并不会存放组件的源码,它只是管理组件的 podspec(描述)文件。当我们发布完组件后,CocoaPods 就会保存这个 podspec 文件(对于公共组件,CocoaPods 在 github 上有一个 索引库 ,它里面保存了所有已发布的组件的描述信息的文件)。当我们使用 CocoaPods 来搜索第三方组件时,实际上就是搜索这个 podspec 文件,它会根据里面的字段信息来查找组件的源码,下载并安装到我们的项目中。

注册

第一次发布组件时,需要先注册一个 CocoaPods 账号。注册成功后可以一直使用,以后就不需要再注册了。

1
2
# 注册
pod trunk register 邮箱 用户名

执行完上面的命令后,CocoaPods 会发一个确认邮件到你的邮箱上,你需要登录邮箱进行确认并完成注册。

可以使用 pod trunk me 来查看你的注册信息

1
2
3
4
5
6
7
8
➜ ~ pod trunk me

- Name: 用户名
- Email: xxx@xxx.com
- Since: February 28th, 2017 19:27
- Pods: None
- Sessions:
- September 19th, 2017 21:52 - April 11th, 2020 03:35. IP:183.14.29.27

步骤

注册完后就可以开始制作组件库了。

准备组件
  1. 创建测试工程
    其实测试工程的创建对于组件的发布没有必然关系,但是这里还是建议为自己的组件创建一个测试工程。这样方便以后组件的测试、升级和维护。

    这里有两种方式来创建测试工程:

    I. 通过 Xcode 来创建项目,并在项目根目录下创建 podspec 文件。

    1
    2
    # 使用 CocoaPods 提供的命令创建 podspec 文件
    pod spec create BlobPublicComponentDemo

    II. 通过 CocoaPods 提供的命令来创建项目。

    1
    2
    # 创建测试工程
    pod lib create BlobPublicComponentDemo

    推荐使用第二种方式来创建测试工程,因为这样创建出来的工程已经帮我们生成了 podspec 的模板文件,而且也添加了 git 管理以及 pod 环境。

    这里使用第二种方式来创建工程。

    当命令执行完毕后,会有一些选项供我们选择。请根据组件的实际情况,选择对应的选项。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    # 选择平台
    What platform do you want to use?? [ iOS / macOS ]
    > ios

    # 选择语言
    What language do you want to use?? [ Swift / ObjC ]
    > objc

    # 是否需要为你的组件库创建一个测试工程
    Would you like to include a demo application with your library? [ Yes / No ]
    > yes

    # 选择测试框架
    Which testing frameworks will you use? [ Specta / Kiwi / None ]
    > none

    # 是否需要 UI 测试
    Would you like to do view based testing? [ Yes / No ]
    > no

    # 测试工程类名的前缀
    What is your class prefix?
    > XC

    Running pod install on your new library.

    当上面的选择执行完毕后,会在本地创建一个名为 BlobPublicComponentDemo 的项目,而且会帮我们自动打开此项目。



    Pods 中的 Development Pods 目录下的 BlobPublicComponentDemo 目录就是我们组件的根目录。

  2. 编写组件代码
    请根据实际情况来编写组件的核心业务功能代码。源码放在组件根目录底下的 Classes 目录里面,资源文件放在组件根目录底下的 Assets 目录里面。这里不做过多概述。

  3. 关联远程仓库
    在 github(gitlab、码云等第三方托管平台)上创建一个公共的仓库,然后关联上本地仓库。

    1
    2
    # 关联远程仓库
    git remote add origin '远程仓库地址'
编写 podspec 文件

当组件准备完毕后,就可以开始编写 podspec 文件了。
这里只介绍 podspec 文件中最基本的字段信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
Pod::Spec.new do |s|
# 组件库的名称。将来发布成功后,可以通过 CocoaPods 来搜索这个名字
s.name = 'BlobPublicComponentDemo'
# 组件库的版本号。一般和远程仓库地址的 tag 标签保持一致
s.version = '0.0.1'
# 组件库的简介。将来组件被搜索出来后会显示这个简介
s.summary = '公共组件测试'
# 组件库的详细描述,字符长度需要比上面的简介长,不然验证的时候会有警告
s.description = <<-DESC
DESC

# 组件对应的远程仓库的主页,同样会在搜索的时候显示出来
s.homepage = 'https://github.com/fanxiaocong/BlobPublicComponentDemo'
# 许可证。这里使用默认的 MIT license
s.license = { :type => 'MIT', :file => 'LICENSE' }
# 作者信息(名字、邮箱)
s.author = { 'fanxiaocong' => '1016697223@qq.com' }
# 组件对应的远程仓库地址,将来 CocoaPods 就是通过这个地址来找到我们的组件的源码
# CocoaPods 拉取的是组件远程仓库中 tag 标签处的代码,所以在验证 podspec 文件之前必须保证在远程仓库上打好 tag 了
s.source = { :git => 'https://github.com/fanxiaocong/BlobPublicComponentDemo.git', :tag => s.version.to_s }
# 组件所要求的系统最低版本
s.ios.deployment_target = '9.0'

# 组件源码的路径
# 它是相对路径,相对于 podspec 文件的路径
# 多个路径使用 , 来分隔。如:s.source_files = '路径1','路径2'
# 一般只包含源码文件(.h .m .mm)
# ** 表示指定路径下的所有目录
# * 表示指定路径下的所有文件 *.{h,m} 表示所有以 .h 或 .m 结尾的文件
# BlobPublicComponentDemo/Classes/**/* 表示 Classes 目录中的所有子目录里面的文件,不包括 Classes 目录里面的文件
# BlobPublicComponentDemo/Classes/*.{h,m} 表示 Classes 目录中的所有 .h 和 .m 文件
s.source_files = 'BlobPublicComponentDemo/Classes/*.{h,m}'

# 资源文件的路径
# 图片、xib、storyboard、json、xml、html、txt、bundle 等文件
# 以键值对的形式来匹配资源路径
# 键:BlobPublicComponentDemo,bundle名,在组件中必须通过加载 bundle 的方式来加载这些资源文件,具体参考 Demo 源码
# 值:资源文件的路径所组件的数组,也是相对于 podspec 文件路径
s.resource_bundles = {
'BlobPublicComponentDemo' => ['BlobPublicComponentDemo/Assets/*.png']
}

# 组件所依赖的系统的 framework 框架,多个使用 , 隔开
s.frameworks = 'UIKit'

# 如果组件需要使用到系统库,则可以在此配置
# s.libraries = 'sqlite3.0', 'libz.tbd'

# 组件依赖的其它第三方库,必须是已经发布到 CocoaPods 上的库
s.dependency 'XCMacros', '~> 1.0.4'

# 如果组件需要用到本地(非系统以及其它已发布到 CocoaPods)的静态库,则可以通过这个字段来配置路径,多个路径之间使用 , 隔开
# s.vendored_libraries = 'BlobPublicComponentDemo/Classes/xxx/xxx.a'

# 如果组件需要用到本地(非系统以及其它已发布到 CocoaPods)的 framework 库,则可以通过这个字段来配置路径,多个路径之间使用 , 隔开
# s.vendored_frameworks = 'BlobPublicComponentDemo/Classes/xxx/xxx.framework'
end

编写完 podspec 文件后,最好可以在工程中引入组件库,测试一下自己的组件能否被正常使用。

首先进入到 Podfile 文件所在的那一级目录(Example 目录下)。

1
cd xxx/Example

然后执行 pod install,完成后就可以在测试工程中引入组件中的类。
1
pod install

当项目能够正常运行并且测试通过后,就可以将代码提交到远程仓库了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 添加到暂存区
git add .

# 提供到本地仓库
git commit -m '提交代码'

# 推送到远程仓库
git push origint master

# 本地打上标签,标签号要与组件的版本号保持一致
git tag 0.0.1

# 推送标签到远程仓库
git push --tags

推送 podspec 文件

推送之前请先确保 podspec 文件书写正确,并且可以验证通过。

1
2
3
4
5
6
7
8
9
10
# 本地验证 podspec 文件是否可以通过,后面可以添加选项
# 选项:
# --verbose 查看详细的验证信息,可以跟踪到警告以及错误的日志
# --allow-warnings 允许警告。默认情况下只要存在警告就不能验证通过,添加这个选项可以忽略掉所有警告
# --use-libraries 如果组件中使用了静态库,则需要添加此选项,否则验证不会通过
# --source '索引库地址' 如果组件中依赖了其它的私有组件库,就需要将对应的私有索引库地址添加进来(此选项一般用于私有组件库,公共组件库不需要)
pod lib lint xxx.spec 选项1 选项2

# 本地和远程验证 podspec 文件是否可以通过,选项同上(一般公共组件库通过这个命令来验证)
pod spec lint xxx.spec 选项1 选项2

验证通过后,就可以将 podspec 文件推送到 CocoaPods 的索引库中。

1
2
# 推送 podspec 文件,必要的选项同样需要添加
pod trunk push xxx.spec 选项1 选项2

发布成功后,别人就可以通过 Cocoapods 搜索到我们发布的组件库。
1
pod search xxx

第一次发布组件时,组件可能会搜索不到,会有延迟,一般一到两天左右。如果还是搜索不到,建议先删除掉 Cocoapods 缓存在本地的索引文件,然后再搜索。
1
rm ~/Library/Caches/CocoaPods/search_index.json

更新维护

后期当我们给组件库增加了新的功能或修复了某些 Bug,就需要给组件库升级,具体是以下几步:

  1. 修改 podspec 文件中的版本号。
  2. 提交代码并打上标签(标签号与 podspec 文件中的版本号保持一致)。
  3. 验证并推送 podspec 文件。

Tips

Podfile

项目中配置第三方组件的文件。项目通过 Cocoapods 初始化后,会在项目的根目录底下生成一个 Podfile 文件。在这个文件中我们可以编写项目所依赖的组件名称及其版本号,然后执行 pod install 命令,就可以将这些组件下载并安装到我们的项目中了。

Podfile.lock

当第一次执行 pod install 命令后,Cocoapods 除了会安装添加在 Podfile 文件中组件外,还会在本地生成一个 Podfile.lock 的文件。这个文件里面记录了当前项目中所有已经安装过的组件的名称及其对应的版本号,后续再通过 pod install 命令来安装新组件的时候,就会过滤掉此文件中已经记录过的组件,只会安装新加入的组件,并且会将新组件的名称及版本号添加到 Podfile.lock 文件里面。因此,此文件可以用来做版本管理,当团队协作开发时,只要大家的 Podfile.lock 文件相同,就可以保证项目所依赖的版本库是一致的。

pod install

根据 Podfile 文件里面的内容下载安装组件。第一次执行此命令时,会根据 Podfile 文件里面的组件名称和版本号来安装对应的组件,如果没有指定版本号,则会安装组件最新发布的那个版本,同时还会生成一个 Podfile.lock 的文件,并将已经安装的组件的名称和版本信息记录在 Podfile.lock 文件中。 后续再执行 pod install 命令时,不管是添加新组件还是移除已存在的组件,都不会对 Podfile.lock 中记录的组件的进行更新,即使这个组件已经发布了新的版本。
作用:

  1. 安装新组件
  2. 删除已有组件
pod update

此命令是用来更新组件库的。不论 Podfile 文件中有没有指定组件版本号,或者 Podfile.lock 文件中是否记录过组件,它都会直接去索引库(本地或远程)中获取组件的最新版本进行安装,并且会将最新的版本号写入 Podfile.lock 文件中。

  1. 不带任何选项,它会从 github 上的远程索引库中获取最新的版本进行更新。
    1
    2
    # 更新至与远程索引库相同的版本
    pod update
  2. 选项 --no-repo-update,它会从缓存在本地的索引库中获取最新的版本进行更新。
    1
    2
    # 更新至与本地索引库相同的版本
    pod update --no-repo-update