Cocoapods 工作原理和源码分析

前言

本文描述 Cocoapods 的工作原理和源码分析,阅读完本文后可以更好的理解在使用 Cocoapods 中遇到的问题并找到解决方法,并且有新的开发语言出现时也可以开发一款自己的包管理工具。

Cocoapods 的安装

Cocoapods 的安装非常简单,只需一行命令即可(需对系统的网络请求进行翻墙)

$ sudo gem install cocoapods

安装完后可在终端输入 pod ,会有如下输出:

pod.png

显示了 pod 的所有可用的命令和命令选项。

Cocoapods 的使用

打开终端,切换到你的工程目录,输入下面的命令

pod init

终端输入 ls 可以看到已经多了个 Podfile 文件,使用 vi 打开,内容如下

# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'

target 'SwiftDemo' do
  # Comment the next line if you're not using Swift and don't want to use dynamic frameworks
  use_frameworks!

  # Pods for SwiftDemo

  target 'SwiftDemoTests' do
    inherit! :search_paths
    # Pods for testing
  end

  target 'SwiftDemoUITests' do
    inherit! :search_paths
    # Pods for testing
  end

end

Podfile 的注释已经很清楚的告诉我们应该如何编写 Podfile 文件。Podfile 的具体编写规则请参考官方文档

编写好 Podfile 后执行以下命令:

pod install

终端会输出 Setting up CocoaPods Master repo 并会停顿很久。因为第一次使用 pod 会从 GitHub 拉取包含所有可用三方库信息的 repo,该代码仓库会随着可用三方库的增多逐渐变大,2014 年 2 月该 repo 仅有 129MB,2016 年 8 月该 repo 已经增加到 841 MB,2016 年 11 月该 repo 已达到 1.07GB(具体请参考链接)。后面会在使用小技巧中介绍如何避免在这一步"卡死"。

Cocoapods 的工作流程

pod install 执行流程可分为如下五个步骤

  • 查看 ~/.cocoapods/repo/master/Specs 是否存在
  • 存在,从这个本地三方库信息库中获取 Podfile 中对应三方库的 git 地址
  • 不存在,输出 Setting up CocoaPods Master repo,并拉取三方库信息库到 ~/.cocoapods/repo/中
  • 使用 git 命令从 GitHub 上拉取 Podfile 中对应的三方库源码

在终端中输入如下命令

cd ~/.cocoapods/repo/master/Specs
ls
repos.png

可以看到很多文件夹,其中就包含我们平常使用的三方库的文件夹。
随便选进入一个文件夹,这里我 cd 进了 Alamofire 文件夹。

versions.png

这里全是 Alamofire 的 release 版本号,当我们使用 pod search Alamofire 命令时会将这里的所有版本号输出出来。
cd 进最新版本的文件夹中,里面是一个 Alamofire.podspec.json 文件,使用 vi 打开,内容如下

{
"name": "Alamofire",
  "version": "4.0.0",
  "license": "MIT",
  "summary": "Elegant HTTP Networking in Swift",
  "homepage": "https://github.com/Alamofire/Alamofire",
  "social_media_url": "http://twitter.com/AlamofireSF",
  "authors": {
    "Alamofire Software Foundation": "info@alamofire.org"
  },
  "source": {
    "git": "https://github.com/Alamofire/Alamofire.git",
    "tag": "4.0.0"
  },
  "platforms": {
    "ios": "8.0",
    "osx": "10.9",
    "tvos": "9.0",
    "watchos": "2.0"
  },
  "source_files": "Source/*.swift"
}

可以看到这里包含了所有的三方库的相关信息,包括名字,协议,描述,Github 地址,支持平台等。

这些信息由三方库作者提交到该信息仓库中。比如你要发布自己的三方库到 Cocoapods 上,你需要 fork 该repo,然后按照 Cocoapods 规定的格式把自己三方库的信息填写上,再 push 到主分支上。
不过这个过程 Cocoapods 也提供的相应的命令来完成,具体请参考官方文档

在查找到对应文件夹后,进行 json 数据解析,获得三方库的 repo 地址,调用本地 git 命令拉取源码,拉取完成后调用本地 xcodebuild 命令把三方库编译为 Framework。

源码分析

我们使用的 cocoapods 命令的 GitHub 路径
https://github.com/CocoaPods/CocoaPods/tree/master/lib/cocoapods/command

commands.png

其中 setup 命令用于第一次使用 cocoapods 时对使用环境进行设置,下面对 setup 命令的源码进行分析。

git 的详细使用教程请参考文档

require 'fileutils'

module Pod
  class Command
    class Setup < Command
      self.summary = 'Setup the CocoaPods environment'

      self.description = <<-DESC
        Creates a directory at `~/.cocoapods/repos` which will hold your spec-repos.
        This is where it will create a clone of the public `master` spec-repo from:
            https://github.com/CocoaPods/Specs
        If the clone already exists, it will ensure that it is up-to-date.
      DESC

      extend Executable
      executable :git

      def run
        UI.section 'Setting up CocoaPods master repo' do
          if master_repo_dir.exist?
            set_master_repo_url
            set_master_repo_branch
            update_master_repo
          else
            add_master_repo
          end
        end

        UI.puts 'Setup completed'.green
      end

      #--------------------------------------#

      # @!group Setup steps

      # Sets the url of the master repo according to whether it is push.
      #
      # @return [void]
      #
      def set_master_repo_url
        Dir.chdir(master_repo_dir) do
          git('remote', 'set-url', 'origin', url)
        end
      end

      # Adds the master repo from the remote.
      #
      # @return [void]
      #
      def add_master_repo
        cmd = ['master', url, 'master']
        Repo::Add.parse(cmd).run
      end

      # Updates the master repo against the remote.
      #
      # @return [void]
      #
      def update_master_repo
        show_output = !config.silent?
        config.sources_manager.update('master', show_output)
      end

      # Sets the repo to the master branch.
      #
      # @note   This is not needed anymore as it was used for CocoaPods 0.6
      #         release candidates.
      #
      # @return [void]
      #
      def set_master_repo_branch
        Dir.chdir(master_repo_dir) do
          git %w(checkout master)
        end
      end

      #--------------------------------------#

      # @!group Private helpers

      # @return [String] the url to use according to whether push mode should
      #         be enabled.
      #
      def url
        self.class.read_only_url
      end

      # @return [String] the read only url of the master repo.
      #
      def self.read_only_url
        'https://github.com/CocoaPods/Specs.git'
      end

      # @return [Pathname] the directory of the master repo.
      #
      def master_repo_dir
        config.sources_manager.master_repo_dir
      end
    end
  end
end

其执行流程可分为如下步骤

  • 判断 ~/.cocoapods/repo目录是否存在
  • 存在,依次调用 set_master_repo_url,set_master_repo_branch,update_master_repo 三个函数分别设置 repo 主分支地址,git checkout 到主分支,拉取主分支代码,更新repo
  • 不存在,添加主分支 repo

使用 Cocoapods 的小技巧

大家在使用 pod install 命令时一般会加上 --no-repo-update 选项。这使得 pod install 不进行本地三方库信息库 git pull 的更新操作。若 Podfile 中指定 Alamofire 的版本号为 4.2.0,但本地 ~/cocoapods/repo/master/Specs/Alamofire 中并没有此版本号,此时使用 pod install --no-repo-update 会出现如下错误,

pod install.png

若直接使用 pod install 便会先执行 pod repo update,由于 github 需要翻墙,并且更新的内容过大就会等待很久。
既然知道了 Cocoapods 的原理,我们便可以手动在 ~./cocoapods/repo/master/Specs 中添加我们需要的三方库版本信息,避免了把所有的并没有使用到的三方库信息更新到本地。
下面以添加 Alamofire 4.2.0 版本信息到本地为例子。
在终端输入如下命令

cd ~/.cocoapods/repo/master/Specs/Alamofire/
mkdir 4.2.0
cp ~/.cocoapods/repo/master/Specs/Alamofire/1.1.3/Alamofire.podspec.json ./4.2.0

上面的命令创建了名为 4.2.0 的文件夹,并复制了一个库信息的 json 文件到新创建的文件夹中,用 vi 打开该文件,内容如下

{
  "name": "Alamofire",
  "version": "1.1.3",
  "license": "MIT",
  "summary": "Elegant HTTP Networking in Swift",
  "homepage": "https://github.com/Alamofire/Alamofire",
  "social_media_url": "http://twitter.com/mattt",
  "authors": {
    "Mattt Thompson": "m@mattt.me"
  },
  "source": {
    "git": "https://github.com/Alamofire/Alamofire.git",
    "tag": "1.1.3"
  },
  "platforms": {
    "ios": "8.0"
  },
  "source_files": "Source/*.swift",
  "requires_arc": true
}

我们需要修改版本号,source 的 tag。那 source 的 tag 怎么知道是多少呢,这个可以从 GitHub 上找到。

release version.png

可以看到所有 release 版本信息。

总结

到此,你已经知道了 Cocoapods 是调用了本地的 git 命令来实现拉取源码。当出现一门新的语言,可以按照类似逻辑开发自己的三方库管理工具。


欢迎关注我的简书,我会定期做一些技术分享:)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,053评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,527评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,779评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,685评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,699评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,609评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,989评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,654评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,890评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,634评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,716评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,394评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,976评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,950评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,191评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,849评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,458评论 2 342

推荐阅读更多精彩内容