CocoaPods 是一个用于管理 iOS 项目中第三方开源库的工具。它能够让 iOS 开发人员通过一些简单的指令就可以下载第三方开源库,并可以管理所下载的第三方框架。这些年一直在使用 CocoaPods,但是也遇到了一些问题,这里记录下一些问题及解决方案。

关于 CocoaPods 源码调试
可以参考 VSCode搭建CocoaPods调试环境,方便快捷定位到实现源码的位置并进行自定义的验证。
CocoaPods 自定义缓存目录
CocoaPods 中可以在 Podfile 中配置从指定的仓库指定的分支下载对应的 Pod 库。如:
pod 'Xxx', :git => 'https://xxx.com/xxx/Xxx.git', :branch => 'feature/dev-v1.0'
下载的 Pod 库会存放在 ~/Library/Caches/CocoaPods/Pods 目录下缓存起来 (对应放在 External 下面),目录结构如下:
Pods
├── External
│   └── Xxx
│       └── 7a2ddd624b9f4e3ad7df801a11bad5a0
│           ├── README.md
│           └── Xxx
├── Release
│   ├── AFNetworking
│   │   └── 4.0.1-7864c
│   │       ├── AFNetworking
│   │       ├── LICENSE
│   │       ├── README.md
│   │       └── UIKit+AFNetworking
├── Specs
│   ├── External
│   │   └── Xxx
│   │       └── 7a2ddd624b9f4e3ad7df801a11bad5a0.podspec.json
│   └── Release
│       ├── AFNetworking
│       │   └── 4.0.1-7864c.podspec.json
└── VERSION
因为有缓存,在某些场景下,同时打包相关项目,但是分别指定不同的分支,可能出现代码对应不上的问题。如果使用 Jenkins 打包,可以设置节点同时只能运行一个任务,在执行之前可以先清理掉 External 目录下的内容。
rm -rf ~/Library/Caches/CocoaPods/Pods/External/*
rm -rf ~/Library/Caches/CocoaPods/Pods/Specs/External/*
但是这样打包效率太低了,着急的时候就出现任务等待的情况。其实只需要想办法让不同的项目能够自定义的指定不同的缓存目录,这样就可以避免同时打包的问题。其实 CocoaPods 已经提供了 CP_CACHE_DIR 环境变量,可以设置不同的缓存目录。但是这个设置的是整个CocoaPods 的缓存目录,如果仅需要将 External 针对不同的项目设置不同的缓存目录就需要修改 CocoaPods 源码了。
通过断点调试,改动的文件为 CocoaPods/lib/cocoapods/downloader/cache.rb, 仓库地址: https://github.com/CocoaPods/CocoaPods.git 。设计一个环境变量 CP_EXT_CACHE_DIR,通过设置当前项目扩展缓存路径可以实现不同项目自定义缓存目录。
改动代码如下:
# @return [Pathname] The ext root directory where this cache store its
#         downloads.
#
attr_reader :ext_root
# Initialize a new instance
#
# @param  [Pathname,String] root
#         see {#root}
#
def initialize(root)
    @root = Pathname(root)
    unless ENV['CP_EXT_CACHE_DIR'].nil?
        ext_path = Pathname.new(ENV['CP_EXT_CACHE_DIR']).expand_path
        ext_path.mkpath unless ext_path.exist?
        @ext_root = ext_path
    else
        @ext_root = Pathname(root)
    end
    ensure_matching_version
end
# @param  [Request] request
#         the request to be downloaded.
#
# @param  [Hash<Symbol,String>] slug_opts
#         the download options that should be used in constructing the
#         cache slug for this request.
#
# @return [Pathname] The path for the Pod downloaded from the given
#         `request`.
#
def path_for_pod(request, slug_opts = {})
    cache_dir = request.released_pod? ? root : ext_root
    pod_path = cache_dir + request.slug(**slug_opts)
    pod_path
end
# @param  [Request] request
#         the request to be downloaded.
#
# @param  [Hash<Symbol,String>] slug_opts
#         the download options that should be used in constructing the
#         cache slug for this request.
#
# @return [Pathname] The path for the podspec downloaded from the given
#         `request`.
#
def path_for_spec(request, slug_opts = {})
    cache_dir = request.released_pod? ? root : ext_root
    spec_path = cache_dir + 'Specs' + request.slug(**slug_opts)
    spec_path = spec_path.sub_ext('.podspec.json')
    spec_path
end
CocoaPods 优化 Git 下载超时的问题
随着版本迭代,或者是提交了比较大的文件, GIT 仓库会变得越来越大,在下载的时候,会出现如下错误:
Cloning into '/var/folders/q4/0m_l9t6j3s38pjwfyg8v2s2mwh2j_d/T/d20250303-79709-yhqu0o'...
error: RPC failed; HTTP 504 curl 22 The requested URL returned error: 504
fatal: expected 'packfile'
以往类似场景一般调整一下 GIT 参数基本上能解决:
git config --global http.postBuffer 10000000000
git config --global http.maxRequestBuffer 500M
git config --global http.lowSpeedLimit 0
git config --global http.lowSpeedTime 999999
但其实并没能解决根本问题,从网上搜索到相关资料,可以通过在 clone 的时候指定 --depth 1 来解决,但是 CocoaPods 并没有提供类似参数。可以参考 cocoapods install加速,通过修改 CocoaPods 源码的方式解决了超时的问题。
修改 cocoapods-downloader/lib/cocoapods-downloader/git.rb, 仓库地址:https://github.com/CocoaPods/cocoapods-downloader.git 。改动代码如下:
def self.preprocess_options(options)
    return options unless options[:branch]
    input = [options[:git], options[:commit]].map(&:to_s)
    invalid = input.compact.any? { |value| value.start_with?('--') || value.include?(' --') }
    raise DownloaderError, "Provided unsafe input for git #{options}." if invalid
    command = ['ls-remote',
                '--',
                options[:git],
                options[:branch]]
    output = Git.execute_command('git', command)
    match = commit_from_ls_remote output, options[:branch]
    return options if match.nil?
    options[:commit] = match
    # options.delete(:branch)
    options
end
# The arguments to pass to `git` to clone the repo.
#
# @param  [Bool] force_head
#         If any specific option should be ignored and the HEAD of the
#         repo should be cloned.
#
# @param  [Bool] shallow_clone
#         Whether a shallow clone of the repo should be attempted, if
#         possible given the specified {#options}.
#
# @return [Array<String>] arguments to pass to `git` to clone the repo.
#
def clone_arguments(force_head, shallow_clone)
    command = ['clone', url, target_path]
    if branch = options[:branch]
        command += ['--branch', branch, '--depth', 1]
    else
        command += ['--template=']
        if shallow_clone && !options[:commit]
            command += %w(--single-branch --depth 1)
        end
  
        unless force_head
            if tag_or_branch = options[:tag] || options[:branch]
              command += ['--branch', tag_or_branch]
            end
        end
    end
    command
end
说明
- 
    
(1) 下载慢的问题,主要是因为 GIT 仓库太大导致的。如果仓库里面的大文件比较多,可以考虑将大文件移除仓库,或者将大文件放到其他地方。
 - 
    
(2) 如果有条件可以将仓库转换为zip的方式使用http下载,或者是产物化之后下载。