Analyze dependencies of CocoaPods Project
在去年,我曾用 electron 写过一个分析使用 CocoaPods 项目依赖的工具,当时对 CocoaPods 还不怎么了解,用了一种「非正常」的操作解决了我当时的需求。不过现在,我找到了一种更好的解决方案
先回顾一下我们的需求
podspec
中列出的 dependecy 在某些情况下要远远比看起来的多得多,尤其是在大量使用 development pods 的情况下。而有些情况,需要确认一个 pod 的全部依赖(比如为这个 pod 创建 Example 工程的时候),这时就需要一个工具来分析了。最终的目标是在拥有一个 podfile 的情况下,把每个依赖的所有依赖都找出来上一个方案存在的问题
如果忘记了之前原理的同学可以快速地翻一下
目前看来,这个方案有几个问题,
Pods/Local Podspecs
里只会存在使用url
方式引用的 pod。换句话说,如果是以版本号的方式引用的 pod,那它的描述就不会出现在那个目录中。根据之前的分析逻辑,我们就假设它没有依赖了,这样分析完的依赖是不全的
- 分析依赖需要
pod install
一次,有些重
那怎样才能优雅而且正确地实现这个需求呢?答案就是使用 CocoaPods 本身 🤓
Analyzer
通过查看 CocoaPods 的源码,我发现了一个类叫做
Analyzer
,它有一个 analyze
方法 会返回一个 AnalysisResult
的结构,其中包含一个名字叫 specifications
的 Array。这就应该我们要找的答案# Initialize a new instance
# Analyzes the Podfile, the Lockfile, and the sandbox manifest to generate the information relative to a CocoaPods installation.
class Analyzer
# Parameters:
# sandbox (Sandbox) — @see sandbox
# podfile (Podfile) — @see podfile
# lockfile (Lockfile) (defaults to: nil) — @see lockfile
# plugin_sources (Array<Source>) (defaults to: nil) — @see plugin_sources
def initialize(sandbox, podfile, lockfile = nil, plugin_sources = nil) ⇒ Analyzer
# ...
end
# Performs the analysis.
#
# The Podfile and the Lockfile provide the information necessary to
# compute which specification should be installed. The manifest of the
# sandbox returns which specifications are installed.
#
# @param [Bool] allow_fetches
# whether external sources may be fetched
#
# @return [AnalysisResult]
#
def analyze(allow_fetches = true)
# ...
end
所以现在的任务就变成了,构造一个
Analyzer
然后调用它的 analyze
方法。不过在操作之前,有一些概念需要搞清。CocoaPods 中的几个基本概念
Pod::Config
用于配置 CocoaPods,比如每次
pod install
是否需要执行 pod repo update
;specs master repo 位置之类的。可以通过修改 ~/.cocoapods/config.yaml
文件来实现自定义的配置。Pod::Installer
最重要的一类,负责
pod install
的整个流程。负责读取 Podfile
和 Podfile.lock
中的依赖内容以及对应的版本信息,把依赖变成 Pods
目录中的一个个实体,然后对 project
文件进行修改,以便我们能直接在工程里用上这些依赖。Pod::Sandbox
可以理解为与
Podfile
同级的 Pod
目录的抽象[Pod::Podfile] && [Pod::Podfile.lock]
它们两个都在 cocoaPods-core 仓库中,分别代表 podfile 和 podfile.lock
搞事情
后来花一些时间好好把逻辑优化了一下,觉得其它人应该也能用得上,就把代码发到了 GitHub 上了 (点这里查看)
主要的代码在 analyze.rb 文件中,核心的逻辑如下,
- 通过
analyzer
找出所有的specifications
- 对于每一个
specification
,把它的name
作为 key,它的依赖(在当前项目中使用的subsbpec
和dependecies
的合)作为 value,生成一个map
- 再次遍历
specification
,根据它的依赖还有上一步生成的 map,递归地寻找它的全部依赖
优势
解决了上一个方案中出现的所有问题
- 能完整地列出整个 podfile 中的所有依赖(不光 podfile 中列出的,还有依赖的依赖)
- 很好地处理了 subspec 的问题,会根据 podfile 中依赖的 subspec 输出正确的结果。比如
pod 'Texture', '2.7'
和pod 'Texture', '2.7', subspecs: %w[PINRemoteImage IGListKit Yoga]
就会产生不同的输出
- 不需要
pod install
,非常轻量
限制
- 分析的项目中需要包含 Podfile 和对应的 xcodeproj 文件,不能只有 Podfile
- 用法还比较复杂,需要 clone 工程然后运行脚本指定路径,后续考虑做成一个 pod 插件的形式,参考这个 issue