-
依赖组件多,User 工程复杂度,导致 Pod Install 后 Xcode 工程索引慢,卡顿严重
-
依赖组件多,工程构建出现不符合预期的失败问题,比如 Arguments Too Long
-
研发流程上,有部分研发同学本地误清理了 CocoaPods 缓存,导致工程编译或者链接失败
-
组件拆分后,新添加文件必须 Pod Install 后才可以被其他组件访问,这拖慢了研发效率
我们开始尝试在 0 侵入、不影响现有研发流程的前提下,改造 CocoaPods 做来解决我们遇到的问题,并且取得了一些收益。在介绍我们的优化前,我们会先对 CocoaPods 做一些介绍, 我们以 CocoaPods 1.7.5 为例来做说明依赖管理的核心流程「Pod Install」
Pod Install
我们以一个 MVP 工程「iOSPlayground」为例子来说明,iOSPlayground 工程是怎么组织的:
| iOSPlayground.xcodeproj | 壳工程,包含 App Target:iOSPlayground |
| — | — |
| iOSPlayground | 壳工程文件目录,包含资源、代码、Info.plist |
| Podfile | 声明 User Target 的依赖 |
| Gemfile | 声明 CocoaPods 的版本,这里是 1.7.5 |
我们在 Podfile 中为 Target「iOSPlayground」引入 SDWebImage 以及 SDWebImage 的两个 Coder,并声明这些组件的版本约束
platform :ios, ‘11.0’
project ‘iOSPlayground.xcodeproj’
target ‘iOSPlayground’ do
pod ‘SDWebImage’, ‘~> 5.6.0’
pod ‘SDWebImageLottieCoder’, ‘~> 0.1.0’
pod ‘SDWebImageWebPCoder’, ‘~> 0.6.1’
end
然后执行 Pod install 命令 bundle exec pod install
,CocoaPods 开始为你构建多依赖的开发环境;整个 Pod Install 流程最核心的就是 ::Pod::Installer
类,Pod Install 命令会初始化并配置 Installer,然后执行 install! 流程,install! 流程主要包括 6 个环节
def install!
prepare
resolve_dependencies # 依赖决议
download_dependencies # 依赖下载
validate_targets # Pods 校验
generate_pods_project # Pods Project 生成
if installation_options.integrate_targets?
integrate_user_project # User Project 整合
else
UI.p ‘Skipping User Project Integration’
end
perform_post_install_actions # 收尾
end
下面会对这 5 个流程做一些简单分析,为了简单起见,我们会忽略一些细节。
准备阶段
这个流程主要是在 Pod Install 前做一些环境检查,并且初始化 Pod Install 的执行环境。
依赖分析
这个流程的主要目标是分析决议出所有依赖的版本,这里的依赖包括 Podfile 中引入的依赖,以及依赖本身引入的依赖,为 Downloader 和 Generator 流程做准备。
这个过程的核心是构建 Molinillo 决议的环境:准备好 Specs 仓库,分析 Podfile 和 Podfile.lock,然后进行 Molinillo 决议,决议过程是基于 DAG(有向无环图)的,可以参考下图,按照最优顺序依次进行决议直到最后决议出所有节点上依赖的版本和来源。
iOSPlayground 工程最后决议出的依赖列表是:
基于最后决议的结果我们就可以获取 Specifications、生成 Aggregate Targets 和 Pod Targets。
Aggregate Targets:
Pod Targets:
| Version | 一般是用点分割的可以比较的序列,组件会以版本的形式对外发布 |
| — | — |
| Requirement | 一个或者多个版本限制的组合 |
| Source | Specs 仓库,组件发版的位置,用于管理多个组件多个版本的一组描述文件 |
| Dependency | User Target 的依赖或者依赖的依赖,由依赖名称、版本、约束、来源构成 |
| Podfile | Ruby DSL 文件,用于描述 Xcode 工程中 Targets 的依赖列表 |
| Podfile.lock | YAML 文件,Pod Install 后生成的依赖决议结果文件 |
| Podspec | Ruby DSL 文件,用于描述 Pod,包括名称、版本、子组件、依赖列表等 |