CocoaPod 与 Git 组件化相关细节
前言
随着项目的发展, 组件化几乎是一个必然的过程, 而使用 Git + CocoaPod 来管理组件是目前业界主流方式.
使用 Pod 来管理组件的优势是非常明显的, 网络上一些文章说的非常清楚, 个人最看重的是以下三点:
- 从根本上解决混乱引用导致的强耦合问题.
- 每个 Pod 可以独立维护, 独立单元测试, 单独走 Git Flow 流程.
- 稳定的组件可以打包成静态库加快编译速度.
但也需要知道, 组件化会带来一系列缺点, 而这些缺点你在网上一般找不到:
- 学习成本, 使用 Pod 与 Git 来管理组件可能会遇到一般使用 Pod 没有遇到的各种问题, 这种采坑成本是不能忽略的.
- 使用 Pod 管理组件无疑会拉长每个开发人员的开发流程, 提高开发成本.
- 当组件的边界不清晰或者组件还没有非常稳定的时候, 反复修改真的很浪费时间.
- 组件化依赖很好的 App 架构, 开发人员也需要有一定的架构思想, 什么时候需要通过路由转发消息, 什么时候做成独立SDK, 层级之间的依赖, 都是需要思考的问题.
- 组件化之后, 每次合并代码冲突是乱七八糟, 往往一个 pod install 便带来几百个冲突, 适应并解决这种问题也是一种成本.
- 开发的组件一定要足够封装足够聚合, 否则 Pod 与主工程中各种强依赖耦合是灾难性的.
虽然组件化有种种不是, 但就像一个公司大了, 必须要有各种规范流程一样, App大了, 开发人员多了, 组件化就如同 Git Flow 流程一样, 麻烦但免去了很多问题.
一些文件
组件化涉及到的东西还真不少, 以下会提到一些文件, 可能你已经很熟悉, 但使用 Cocoapod 管理组件之后, 你将于他们打交道的更多, 下面记录一些与之相关的细节.
podfile:
都知道这个文件的作用, 如果你只用 pod 管理第三方库 , 你可以直接使用一个普通模板 podfile, 添加第三方库, 安装即可, 但管理组件则需要对这个更熟悉, 这是管理组件的根本, 以下说说一些注意点:
- use_frameworks!: 通个关键词生成的是 framework 而不是静态库, 很直观的就是 podfile 中加上这个, 在主工程中使用<>引用就要使用路径, 不加则可以直接引用头文件.
- inhibit_all_warnings!: 隐藏所有 pod 中的告警, 这个挺有用的, 加快编译速度.
- 所有的 pod 都须指向 tag, 可以避免很多问题.
- source: 指定源, 第一个源应该是私有源, 后面才是官方源, 这样若出现同名的 pod 会优先加载私有源中的, 方便镜像第三方库.
- def end语法: 用法很简单, 就像宏命令一样, 但不支持驼峰标识.
- :configurations = 'Debug': 只在 debug 环境加载, 对应的关键词是 'Release'.
- 每个组件一定要写好注释, 否则你同事看到的时候一定是懵逼的.
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 文件, 这个也是最容易出问题的文件, 这个文件的配置方法就不说了, 下面说说这个文件中的注意点:
- version 问题, 一般来说, 这里的 version 要等于 git 上的 tag 值.
- source_files 为源文件.
- public_header_files 为开放的头文件.
- resources 为资源路径.
- frameworks 依赖的库, 一般为系统的库例如 AVFoundation、UIKit等.
- library 依赖的静态库, 比如 resolv、c++.
- vendored_frameworks pod 中 .framework 文件.
- vendored_libraries pod 中的.a 文件
- dependency 依赖的组件, 会从 podfile 中的 source 去寻找相关 pod, 建议在 podspec 中不要指定版本号, podfile 中统一指定.
- pod_target_xcconfig, 工程中配置的键值对.
- subspec, 子 pod, subspec 影响集成后的文件夹结构, 但不要层级太多, 也不要划分太细, 非常影响编译速度, 另外 subspec 之间的依赖不是文件夹依赖, 而是 superspec/subspec 这种形式.
一些操作
上面说了一些文件及其中的细节, 下面说一下常用的操作.
pod lib lint 与 pod spec lint
前者为验证远程仓库与本地仓库, 后者为仅验证本地仓库, 有时候会出现只有一个能通过, 那表明远程仓库与本地仓库没有完全对应. 常用的参数:
- 允许告警 --allow-warnings.
- 该 pod 有使用静态库 --use-libraries.
- 打印详细log --verbose.
- 自定义源 --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:
- git add .
- git commit -m '描述'
- git push
- git tag -a '版本号' -m '描述'
- git push --tags
再将 podspec 利用上面 repo push 命令推到私有源, podfile 修改对应版本号, pod update 对应pod, 完成了版本的升级. 值得注意的是 git 的 tag 不要删除, 否则会出现一些缓存问题.
待续....