利用 CocoaPod 和 Git 管理组件中的一些细节梳理

2,136 阅读6分钟

CocoaPod 与 Git 组件化相关细节

前言

随着项目的发展, 组件化几乎是一个必然的过程, 而使用 Git + CocoaPod 来管理组件是目前业界主流方式.

使用 Pod 来管理组件的优势是非常明显的, 网络上一些文章说的非常清楚, 个人最看重的是以下三点:

  1. 从根本上解决混乱引用导致的强耦合问题.
  2. 每个 Pod 可以独立维护, 独立单元测试, 单独走 Git Flow 流程.
  3. 稳定的组件可以打包成静态库加快编译速度.

但也需要知道, 组件化会带来一系列缺点, 而这些缺点你在网上一般找不到:

  1. 学习成本, 使用 Pod 与 Git 来管理组件可能会遇到一般使用 Pod 没有遇到的各种问题, 这种采坑成本是不能忽略的.
  2. 使用 Pod 管理组件无疑会拉长每个开发人员的开发流程, 提高开发成本.
  3. 当组件的边界不清晰或者组件还没有非常稳定的时候, 反复修改真的很浪费时间.
  4. 组件化依赖很好的 App 架构, 开发人员也需要有一定的架构思想, 什么时候需要通过路由转发消息, 什么时候做成独立SDK, 层级之间的依赖, 都是需要思考的问题.
  5. 组件化之后, 每次合并代码冲突是乱七八糟, 往往一个 pod install 便带来几百个冲突, 适应并解决这种问题也是一种成本.
  6. 开发的组件一定要足够封装足够聚合, 否则 Pod 与主工程中各种强依赖耦合是灾难性的.

虽然组件化有种种不是, 但就像一个公司大了, 必须要有各种规范流程一样, App大了, 开发人员多了, 组件化就如同 Git Flow 流程一样, 麻烦但免去了很多问题.

一些文件

组件化涉及到的东西还真不少, 以下会提到一些文件, 可能你已经很熟悉, 但使用 Cocoapod 管理组件之后, 你将于他们打交道的更多, 下面记录一些与之相关的细节.

podfile:

都知道这个文件的作用, 如果你只用 pod 管理第三方库 , 你可以直接使用一个普通模板 podfile, 添加第三方库, 安装即可, 但管理组件则需要对这个更熟悉, 这是管理组件的根本, 以下说说一些注意点:

  1. use_frameworks!: 通个关键词生成的是 framework 而不是静态库, 很直观的就是 podfile 中加上这个, 在主工程中使用<>引用就要使用路径, 不加则可以直接引用头文件.
  2. inhibit_all_warnings!: 隐藏所有 pod 中的告警, 这个挺有用的, 加快编译速度.
  3. 所有的 pod 都须指向 tag, 可以避免很多问题.
  4. source: 指定源, 第一个源应该是私有源, 后面才是官方源, 这样若出现同名的 pod 会优先加载私有源中的, 方便镜像第三方库.
  5. def end语法: 用法很简单, 就像宏命令一样, 但不支持驼峰标识.
  6. :configurations = 'Debug': 只在 debug 环境加载, 对应的关键词是 'Release'.
  7. 每个组件一定要写好注释, 否则你同事看到的时候一定是懵逼的.
podfile.lock:

当我们运行 pod install 命令时, 工程中的 pod 就会更新到 podfile.lock 中的版本, 这个是让我们在多人协作中避免第三方库的版本不同的文件, 但是不可避免的我们组件化之后会运行 pod update, 而每次 pod update 都会更新这个文件, 所以这个文件的作用便显得有些鸡肋了, 也正是因为这样, podfile 中的各个 pod 应该指明 tag, 否则便是灾难. 而且某些特殊的需求, 我们可能会需要切换 pod 的 tag, 也因这个文件的存在, 使用 pod install 便会报错, 只能使用 pod update.

manifest.lock:

可以简单的理解为我们在本地执行一次 pod install 后生成的当前Podfile的状态的表征文件, 一般用来校验与 podfile.lock 是否一致.

xcconfig:

保存每一个 pod 的工程配置文件, 这个文件很容易在合并代码时冲突, 一般可以忽略, pod install 即会重新生成.

project.pbxproj:

记录工程文件结构及位置的文件, 不论有新增、移动或者删除都会改变这个文件, 所以这个是必定会冲突的文件, 再配合上海量的 xcconfig 文件变动, 让合并代码变得更加困难, 一般的做法是以他人的版本解决问题, 对于主工程中的文件, 缺少的重新 add file, 对于 pod 中的文件, 直接 pod install, 再合并.

podspec:

每一个 pod 的配置文件, 也是组件化的核心文件, 我们创建的私有源或者官方源本质上就是一个个 pod 名字命名的文件夹, 子文件夹为各个版本号, 最内层就只有一个 podspec 文件, 这个也是最容易出问题的文件, 这个文件的配置方法就不说了, 下面说说这个文件中的注意点:

  1. version 问题, 一般来说, 这里的 version 要等于 git 上的 tag 值.
  2. source_files 为源文件.
  3. public_header_files 为开放的头文件.
  4. resources 为资源路径.
  5. frameworks 依赖的库, 一般为系统的库例如 AVFoundation、UIKit等.
  6. library 依赖的静态库, 比如 resolv、c++.
  7. vendored_frameworks pod 中 .framework 文件.
  8. vendored_libraries pod 中的.a 文件
  9. dependency 依赖的组件, 会从 podfile 中的 source 去寻找相关 pod, 建议在 podspec 中不要指定版本号, podfile 中统一指定.
  10. pod_target_xcconfig, 工程中配置的键值对.
  11. subspec, 子 pod, subspec 影响集成后的文件夹结构, 但不要层级太多, 也不要划分太细, 非常影响编译速度, 另外 subspec 之间的依赖不是文件夹依赖, 而是 superspec/subspec 这种形式.

一些操作

上面说了一些文件及其中的细节, 下面说一下常用的操作.

pod lib lint 与 pod spec lint

前者为验证远程仓库与本地仓库, 后者为仅验证本地仓库, 有时候会出现只有一个能通过, 那表明远程仓库与本地仓库没有完全对应. 常用的参数:

  1. 允许告警 --allow-warnings.
  2. 该 pod 有使用静态库 --use-libraries.
  3. 打印详细log --verbose.
  4. 自定义源 --source 源地址.
pod repo push 源的地址 podspec文件

将 podspec 文件 push 到私有源中. 过程中会经过 pod lib lint 验证, 后面可以接验证相同参数.

pod cache clean --all

清除 pod 相关缓存, 若遇到一些缓存相关的错误可以使用, 同时可以使用 pod repo remove 源名称, 删除相关本地仓库.

pod package podspec文件 --foce / pod package podspec文件 --library --force

利用 pod package 打包静态库. 前者为 .framework, 后者为 .a 文件.

tag 流程

打 tag 在组件化中是用的最多的流程, 虽然已经有 jinkins 这种工具让这一步自动实现, 但我们也不能忘了手动 tag 的流程.

首先更新 pod 中的文件, 及 podspec, 在示例程序中无错误后, podspec 中的 version 改为更大的版本号. 操作 git:

  1. git add .
  2. git commit -m '描述'
  3. git push
  4. git tag -a '版本号' -m '描述'
  5. git push --tags

再将 podspec 利用上面 repo push 命令推到私有源, podfile 修改对应版本号, pod update 对应pod, 完成了版本的升级. 值得注意的是 git 的 tag 不要删除, 否则会出现一些缓存问题.

待续....