我们对CocoaPods的感情真是又爱又恨的,爱的是用它来管理第三方库非常方便,恨的是每次需要更新一些第三方库的时候,速度像蜗牛一样慢。本篇文章分享几个小技巧加快CocoaPods更新第三方库的速度。
RubyGems换源
RubyGems是什么呢?下面是官网给出的一段介绍:
The RubyGems software allows you to easily download, install, and use ruby software packages on your system. The software package is called a “gem” and contains a package Ruby application or library.
Gems can be used to extend or modify functionality in Ruby applications. Commonly they’re used to distribute reusable functionality that is shared with other Rubyists for use in their applications and libraries. Some gems provide command line utilities to help automate tasks and speed up your work.
通俗地来讲RubyGems就像是一个仓库,里面包含了各种软件的包(如Cocoapods、MySql),可以通过命令行的方式来安装这些软件包,最为方便的是自动帮你配置好软件依赖的环境,整个安装过程仅仅只需要几行命令行。
我们在安装CocoaPods的时候,就是通过rubygems来安装的,由于在国内访问rubygems非常慢,所以替换rubygems镜像源就显得十分必要了。在替换rubygems镜像源的时候,先检查一下rubygems的版本,建议在2.6.x以上,如果没有的话,建议先升级一下,升级命令行如下:
$ gem update --system # 这里请翻墙一下 $ gem -v 2.6.7
升级完成之后,可以用gem -v查看下现在的版本号,比如我现在的版本是2.6.7。之前很多人用的都是淘宝的镜像源,现在淘宝的rubygems镜像源交给Ruby China来维护了,替换rubygems镜像源的命令行如下:
$ gem sources --add https://gems.ruby-china.org/ --remove https://rubygems.org/ $ gem sources -l https://gems.ruby-china.org # 确保只有 gems.ruby-china.org
这里做一下说明,remove后面的镜像源地址填写你当前的镜像源地址。比如你当前的镜像源地址是淘宝的,命令行如下:
$ gem sources --add https://gems.ruby-china.org/ --remove http://ruby.taobao.org/
总结:替换rubygems的镜像源,带给我们的好处有两点:
安装、更新CocoaPods的时候,速度更快,解决半天无反应的情况。
安装其他软件也可以更加迅速,比如mysql等。
repo换源
使用CocoaPods的时候,经常要和这几个命令行打交道:
pod install pod update pod repo update
每次运行这几个命令的时候,真是一件痛苦的事情,等个半小时、一小时或者更长时间才能运行完,为什么会出现这种现象呢?我们先来补充一些基础知识:
当CocoaPods安装成功以后,它默认的镜像源地址是github(https://github.com/CocoaPods/Specs.git),打开命令行进入到下面的文件:
$ cd ~/.cocoapods/repos $ ls DDNPrivatePods taobao-baichuansdk-alibcspecs master taobao-baichuansdk-alibcspecsmirror
会看到有一个master的文件,这就是CocoaPods在本地建立了一个master的repo,master里面包含了所有第三方库的地址列表,每一个库的详细信息记录在podspec文件里面。以为YTKNetwork例,我们看下podspec里面包含的信息:
{ "name": "YTKNetwork", "version": "2.0.3", "summary": "YTKNetwork is a high level request util based on AFNetworking.", "homepage": "https://github.com/yuantiku/YTKNetwork", "license": "MIT", "authors": { "tangqiao": "tangqiao@fenbi.com", "lancy": "lancy@fenbi.com", "maojj": "maojj@fenbi.com", "liujl": "liujl@fenbi.com" }, "source": { "git": "https://github.com/yuantiku/YTKNetwork.git", "tag": "2.0.3" }, "source_files": "YTKNetwork/*.{h,m}", "requires_arc": true, "private_header_files": "YTKNetwork/YTKNetworkPrivate.h", "platforms": { "ios": "7.0", "osx": "10.9", "watchos": "2.0", "tvos": "9.0" }, "frameworks": "CFNetwork", "dependencies": { "AFNetworking": [ "~> 3.0" ] } }
上面我们可以看出其指定了tag标签、源码的下载地址,另外在YTKNetwork下有好多tag标签,如下:
0.1.0 0.2.0 0.3.0 0.4.0 0.5.0 0.6.0 1.0.0 1.1.0 1.2.0 1.3.0 2.0.0 2.0.1 2.0.2 2.0.3
至此我们了解master下面的一个库大概包含哪些信息,第一:指定了tag标签、源码下载地址;第二:库文件目录下包含了许多tag标签,一个版本对应一个tag标签。
了解完这些基础知识以后,我们来分下一下pod update、pod install、pod repo update背后发生了什么,导致其速度巨慢。分析问题的先决条件是你本地已经有一个master的repo。当你运行上面的命令行时,它们会把本地的repo所有地址列表更新一次,在这个过程中实际使用的是git fetch来执行的。为什么是使用git fetch来执行的?下面一段话给出了解释:
Git fetch is used because git clone will only download the history of the default branch (some info about the default branch of a bare repo is available here). As we can't know whether a given tag will be on the default branch or not, we need to fetch the whole repo (the cache) in our clone (the Pod checkout used for the installation).
简单来说就是我们不知道给定的tag标签是不是在默认的分支上面,所以不得不把全部repo给拉取下来做一下比较,才能确定给定的tag标签是在哪个分支上面。我们通过一个例子来说明一下,master repo下有一个A库,A库在更新前本地有10个tag标签,也就是有10个版本,CocoaPods要想检测一下A库有没有最新的版本,它就去github上的repo地址列表拷贝一份A库最新所有的tag标签,和本地的tag标签做一个比较,从而判断A库有没有最新版本,需要不需要更新。
而git clone仅仅下载默认分支且默认分支repo的大小要比全部分支repo的大小小许多,还有最重要的一点是git clone明确了tag标签是在默认分支上,这样就不要下载全部的repo进行大量的比较了。
总结:
git fetch下载的repo要比git clone下载的repo大许多。
给定一个tag标签,git clone明确了一个库的tag标签在默认分支上,而git fetch则不能。
git fetch为了确定库的标签在哪个分支上需要做大量的计算,而git clone则不需要。
我们可以看出git clone要比git fetch快许多,所以要在使用cocoapods时要尽量避免执行git fetch,看下下面几种解决方案:
方案一: 使用下面两个命令行
pod installl --no-repo-update --verbose pod update --no-repo-update --verbose
其中--verbose的作用就是打印出执行过程中详细的信息,--no-repo-update的作用就是禁止更新repo,这样就避免执行了git fetch,从而加快速度。但是如果repo本身就很老(第三方库版本比较低)的时候,仍然是需要更新repo的,这种情况下如何处理呢?请看方案二和方案三。
方案二: 进入到repos目录下,通过git clone直接添加master库,命令行如下:
$ cd ~/.cocoapods/repos $ pod repo remove master $ git clone https://github.com/CocoaPods/Specs.git master
首先要把本地老的master分支给移除掉,然后使用git clone从github镜像源上clone一份且设置本地master库。这样本地的repo就是最新的了,此时在进入到当前工程目录下,执行方案一提供的命令行。这样就解决了工程依赖的第三方库版本过低需要更新的问题。但是我们在clone github镜像源的时候,发现速度还是比较慢的,这是因为国内访问github的速度不给力,没办法的事情,这个时候可以考虑挂一个VPN或者使用国内一些网站提供的镜像源。
方案三:repo换源
方案三就是为了解决方案二出现clone github镜像源比较慢的问题,可以换成coding提供的一个镜像源,命令行如下:
$ cd ~/.cocoapods/repos $ pod repo remove master $ git clone https://git.coding.net/hging/Specs.git master
这样在clone的时候会发现速度很快哈。另外,在自己工程中的Podfile文件加入下面一行描述:
source 'https://git.coding.net/hging/Specs.git'
如果不加这一句话,它默认还是从github镜像源地址去下载的,这个不要给忘记了。
注意点:
master repo里面存放的是所有第三方库的地址列表,下载第三方库对应的源码还是要到指定的源码存放地址(podspecs中有指定)去下载。更换repo源只是加快了repo的下载速度,并不会加快第三方库源码的下载速度,两者是没有任何关系的。
在工程中尽量避免直接使用pod update、pod install,在后面添加--no-repo-update后使用。
工程中依赖第三方库版本过低,可以先到repos目录下,使用git clone更新master repo,然后在工程中使用pod update --no-repo-update命令。
上面提到的三种方案从一定程度上加快了CocoaPods的执行速度,但是仍然避免不了要更新全部repo的情况,而实际情况是我们项目当中用到的第三方库大部分只需要十几个,大量的时间被浪费在我们不需要的库上面了。因为CocoaPods是使用中心化的方式来进行管理的,所以当第三方库多起来的时候,就会出现刚才的情况,这个时候可以选择使用Carthage来管理第三方库,它比CocoaPods最大的优势就在于去中心化的方式来管理,不过Carthage的缺点是里面的库还不是很丰富,不过随着时间的推移就不是问题了。
总结
在第一次安装CocoaPods的时候,替换成rubychina提供的rubygems镜像仓库。在实际工程中尽量避免让CocoaPods执行git fetch命令,比如执行pod update、pod install、pod repo udpate等命令都会引起CocoaPods执行git fetch命令。
参考文章: