# iOS基础 # CocoaPods使用说明书

1、什么是CocoaPods

CocoaPods 是开发 OS X 和 iOS 应用程序的一个第三方库的依赖管理工具。利用它可以定义自己的依赖关系 (称作 pods),并且随着时间的变化,以及在整个开发环境中对第三方库的版本管理非常方便。这里整理了从基本安装到使用的操作流程和期间容易出现的问题以及解决办法。

2、CocoaPods都做了什么

简单查看一下cocoapods源代码ruby语言),了解一下install和update过程都干了什么。 参考:cocoapods都做了什么

CocoaPods/lib/cocoapods/command/install.rb

def run
    verify_podfile_exists!
    installer = installer_for_config //Podfile的内容解析
    installer.repo_update = repo_update?(:default => false)
    installer.update = false //和update的区别
    installer.install!
 end

CocoaPods/lib/cocoapods/command/update.rb

def run
    verify_podfile_exists!

    installer = installer_for_config
    installer.repo_update = repo_update?(:default => true)
    if @pods
      verify_lockfile_exists!
      verify_pods_are_installed!
      installer.update = { :pods => @pods }
    else
      UI.puts 'Update all pods'.yellow
      installer.update = true
    end
    installer.install!
end

CocoaPods/lib/cocoapods/installer.rb

def install!
  prepare
  resolve_dependencies //处理依赖关系、比如是根据本地specs文件呢还是远端git地址等
  download_dependencies//跟进依赖关系下载对应依赖包
  validate_targets
  generate_pods_project //生成pods.xcodeproj工程,将依赖中的文件、Library加入工程,设置target dependencies、生成workspace//
  if installation_options.integrate_targets?
    integrate_user_project
  else
    UI.section 'Skipping User Project Integration'
  end
  perform_post_install_actions
end

总结

Podfile的内容解析

repo的更新检查

处理Podfile中的依赖关系

下载依赖资源

生成pods.xcodeproj工程

将依赖中的文件、Library加入工程

设置target dependencies

生成workspace

3、CocoaPods的安装

1.安装过程

安装方式异常简单 , Mac 下都自带 ruby,使用 ruby 的 gem 命令即可下载安装:

$ sudo gem install cocoa pods

$ pod setup

2.安装过程可能出现的错误

gem版本需要更新

首先确认软件源地址是正确的,然后如果你的 gem 太老,可能也会有问题,可以尝试用如下命令升级 gem。

$ sudo gem update –system  //sudo 执行 不然会报无权限错误

更新完成 gem 后 :

$ gem update cocoapod //更新cocoapod

$ pod setup pod //更新完成后初始化

$ pod repo update —verbose //更新repo

如果报错,先移除原来的缓存文件:

$ rm -rf ~/.cocoapods/repos/master //然后再 pod setup。

pod setup 卡住在 Setting up CocoaPods master repo

这步其实是 Cocoapods 在将它的信息下载到 ~/.cocoapods 目录下,如果你等太久,可以试着 cd 到那个目录,用 du -sh * 来查看下载进度。

如果还是慢,更新一下软件源:

ruby 的软件源 https://rubygems.org 因为使用的是亚马逊的云服务,所以被墙了,需要更新一下 ruby 的源。并且由于淘宝源已经不再进行更新维护,改成由 ruby-china 管理维护 所以源改成 https://gems.ruby-china.org/

gem sources –remove https://rubygems.org // 移除默认源

gem sources -a https://gems.ruby-china.org // 添加新的源

gem sources -l //查看sources源 看是否已经更换

4、CocoaPods基础应用

1.项目中的使用方法

使用时需要新建一个名为 Podfile 的文件,以如下格式,将依赖的库名字依次列在文件中即可:

source 'https://github.com/CocoaPods/Specs.git' //可以在这里按这种格式配置其他仓库
target 'MyApp' do 
platform :ios, '6.0' //IOS 系统、版本要求
pod 'MJExtension', '~> 2.5.12' //引入的pod项目对应的项目名称 和版本号
platform :ios,'7.0' 
pod 'FMDB','~> 2.6.0'//~>符号指的是 2.6 级别版本获取最新的版本'
end

然后你将编辑好的 Podfile 文件放到你的项目根目录中,执行如下命令即可:

cd “你的podfile所在目录”

pod install

现在,你的所有第三方库都已经下载完成并且设置好了编译参数和依赖,你只需要记住如下:

使用 CocoaPods 生成的 .xcworkspace 文件来打开工程,而不是以前的 .xcodeproj 文件。

每次更改了 Podfile 文件,你需要重新执行一次 pod update 命令。

当不知道某款第三方库的引入方法时可以直接在终端查找第三方库 或者 你如果不知道 CocoaPods 管理的库中,是否有你想要的库,那么你可以通过 pod search xxx 命令进行查找

2.CocoaPods使用中的tips

1.关于 Podfile.lock

当你执行 pod install 之后,除了 Podfile 外,CocoaPods 还会生成一个名为 Podfile.lock 的文件,Podfile.lock 应该加入到版本控制里面,不应该把这个文件加入到 .gitignore 中。

因为 Podfile.lock 会锁定当前各依赖库的版本,之后如果多次执行 pod install 不会更改版本,要pod update 才会改 Podfile.lock 了。

这样多人协作的时候,可以防止第三方库升级时造成大家各自的第三方库版本不一致。

后面的CocoaPods私人仓库创建会讲到 podspec 文件的问题

2.–-no-repo-update

CocoaPods 在执行 pod install 和 pod update 时,会默认先更新一次 podspec 索引,会去更新 repo。

使用 --no-repo-update 参数可以禁止其做索引更新操作。如下所示:

pod install –-no-repo-update

pod update –-no-repo-update

3.移除tag0.0.1,再重现提交新的tag0.0.1

git add . 
git commit -m"cover tag 0.0.1" 
git push 
git tag -d 0.0.1 
git push origin :refs/tags/0.0.1 
git tag 0.0.1 
git push origin 0.0.1

4.CocoaPods原理

大概研究了一下 CocoaPods 的原理,它是将所有的依赖库都放到另一个名为 Pods 项目中,然后让主项目依赖 Pods 项目,这样,源码管理工作都从主项目移到了 Pods 项目中。发现的一些技术细节有:

1.Pods 项目最终会编译成一个名为 libPods.a 的文件,主项目只需要依赖这个 .a 文件即可。

2.对于资源文件,CocoaPods 提供了一个名为 Pods-resources.sh 的 bash 脚本,该脚本在每次项目编译的时候都会执行,将第三方库的各种资源文件复制到目标目录中。

3.CocoaPods 通过一个名为 Pods.xcconfig 的文件来在编译时设置所有的依赖和参数。

3.创建私有仓库

使用pod的时候 我们会遇到需要将自己的代码封装出去 单独管理的情况,这种情况下 我们就需要一个私有的仓库来管理这些单独的部件。

1.创建一个支持pod引入的项目

cocoapods提供了一个快捷的项目模板创建命令:

$ pod lib create 你要创建的项目的项目名称

执行命令会有如下选择过程:

//pod lib create 你要创建的项目的项目名称  命令执行后会询问基本信息
//1.是否需要一个例子工程;2.选择一个测试框架;3.是否基于View测试;4.类的前缀;

What language do you want to use?? [ Swift / ObjC ]
 > ObjC

Would you like to include a demo application with your library? [ Yes / No ]
 > yes

Which testing frameworks will you use? [ Specta / Kiwi / None ]
 > none

Would you like to do view based testing? [ Yes / No ]
 > no

What is your class prefix?
 > YG

依次按需要执行完成就会生成一个有格式的项目。

生成项目分为 Example 和 Pods 两个主要的目录。

Pods 
|- Assets 文件夹,//用来存放本地资源,比如图片、Assets.xcassets等
|- Classes 文件夹,//存放pod的.m.h.swift.xib文件等
| 
Example 文件夹,//就是一个demo项目方便pod代码开发
|   |- demoProject.xcodeproj
|   |- demoProject.xcworkspace
|   |- Podfile   //就是一个demoPod项目的 第三方库依赖描述文件
|   |- Podfile.lock
|   |- demoProject
|   |- Pods      //其他第三方库依赖描述文件存放文件夹
|   |- Tests
LICENSE //开源协议文件
| 
demoProject.podspec  //这个pod文件的说明书,下面会详细说

项目在xcode中的结构如下:

png

其中重要的两个部分是 *.podspec 文件 和 pods下面的 Development Pods 目录其实就是上面提到的Pod目录。.podspec 就像一个说明书,描述当前这份pod项目 需要提交到私有库中,才能让其他项目通过私有库引用到当前这份pod项目。

*.podspec 内容格式基本如下:

Pod::Spec.new do |s| 
s.name = “demoProject” //项目名 
s.version = “1.0.2” //版本号 要和在git上的tag对应 
s.summary = “demo” 
s.description = <<-DESC 
this is a demo 
DESC 
s.homepage = “git@gitlab.jfz.net:xxxx/demoProject” //项目主页 
s.license = ‘MIT’ 
s.author = { “young” => “young.huang@jfz.com” } //用户信息 
s.source = { :git => “git@gitlab.jfz.net:xxx/demoProject.git”, :tag => s.version.to_s }//git地址 
s.platform = :ios, ‘6.0’ //支持系统、最低版本 
s.requires_arc = true  //是否使用ARC,如果指定具体文件,则具体的问题使用ARC
s.source_files = ‘Pod/Classes/*/.{h,m}’ //项目核心部分的文件 class下面的所有.h/.m文件

#s.source_files = 'Pod/Classes/**/*'//代码源文件地址,**/* 表示Classes目录及其子目录下所有文件,如果有多个目录下则用逗号分开,如果需要在项目中分组显示,这里也要做相应的设置

# s.public_header_files = ‘Pod/Classes/*/.h’ //公开头文件地址
# s.frameworks = ‘UIKit’, ‘MapKit’ //此pod项目使用到得框架 
# s.dependency ‘AFNetworking’, ‘~> 2.3’ //此pod项目依赖的其他pod项目

end

subspec语法参考

修改pod项目并提交到指定地址 给项目打上tag 这里的tag需要和podspec中配置的tag一样。

$ git tag 1.0.0

$ git push origin v1.0.0

特别注意 :

1.每次往Pod里面添加文件、图片、等任何非代码级别的改动的时候,都需要在Example目录下面进行一次pod install 或者 pod update一次。

2.版本管理忽略掉pods文件夹 保留 podfile podfile.lock 跟着版本同步

2.创建私有仓库

首先创建放私有库(repo) git地址 :

git@gitlab.xxx.net:xxxxx/demoRepo.git

然后在添加一个叫 demoRepo 的本地repo,并指向之前创建好的git地址,控制台命令:

$ pod repo add demoRepo git@gitlab.xxx.net:xxxxx/demoRepo.git
$ pod repo //查看本地所有repo

私有库创建好了后,回到之前创建的pod项目下,一般修改好podspec后会进行校验必须是无错误、无警告才能提交。校验命令:

pod lib lint //只是本地格式校验

pod spec lint YoungEwm.podspec //这个命令除开校验格式  还需要校验远程地址,链接的项目地址等

将修改好的podspec文件push到我们刚刚创建的demoRepo上。加上 –-verbose命令会打印操作日志

$ pod repo push demoRepo demoProject.podspec –-verbose

到最后如果是因为警告原因(warn)无法通过则在push命令后如上 --allow-warnings 即可。成功提交后在我们的demoRepo对应的git remote端就可以看到一个对应版本的 pod spec 文件。

├─ LICENSE
├─ demoProject
│   └─ 1.0.2
│       └─ demoProject.podspec
└─ README.md

3.获取私有仓库中的pod项目

上面已经将我们自己创建的项目注册到了我们自己的私有repo中,在我们的主项目中需要引入这些pod部件的时候。首先在项目的 .xcodeproj 文件同级 创建一个 podfile 文件 文件内容如下:

source ‘https://github.com/CocoaPods/Specs.git’ 引用的源 cocoapods的公用源 
source ‘git@gitlab.jfz.net:huangyang/demoRepo.git’ 我们自己的私有源

platform :ios, ‘6.0’ 
target ‘demoWebView’ do 
pod ‘JFZPodsDemo’, ‘~> 1.0.1’ //我们需要引入的pod项目 ~> 表示是 1.0.X 版本级别的更新 前两位不改变

end

这里面的 platform 版本要和 podspec 里面设置的不能冲突,否则无法引用pod项目

然后重新 pod install 一下就好了

4.删除repo

如何删除一个私有Spec Repo,只需要执行一条命令即可:

pod repo remove demoRepo

这样这个Spec Repo就在本地删除了,我们还可以通过

pod repo add demoRepo git@coding.net:wtlucky/WTSpecs.git

再把它给加回来。

如果我们要删除私有Spec Repo下的某一个podspec怎么操作呢,此时无需借助Cocoapods,只需要cd到~/.cocoapods/repos/demoRepo 目录下,删掉库目录。

~/.cocoapods/repos/demoRepo$ rm -Rf demoRepoXXX

然后在将Git的变动push到远端仓库即可。

5.可能遇见的问题

spec文件无法校验通过

发生原因:

当spec本身格式有错误的时候

当引用多个私有repo中得pod项目,直接指向cocoapods查询不到对应的pod所属的私有repo

解决办法 :

在pod repo push 后跟上对repo的地址指向 -- source=。已经添加到本地的repo 可以直接用repo名称,没有的使用git地址。

--sources=https://github.com/artsy/Specs,master  

6.开发pod项目的其他问题

1.怎么在开发中调试程序

开发过程中,可以修改Podfile文件的,将pod版本指向本地。对应pod的代码会被引入Development Pods中:

#pod 'Stock', :path => '/Users/xxxx/desktop/workplace/Stock'

2.模块之间的命名问题

最好以模块为单位添加不同的前缀。

3.Pod之间的引用

4.tag缓存问题

添加pod的某个tag如0.0.1 到repo后,需要修改代码但又不想提升tag版本时,注意修改完后清理CocoaPods的本地缓存

$ rm -rf “${HOME}/Library/Caches/CocoaPods”

5.第三方库的修改,尽量fork再通过pod引用

6.ignore 文件忽略问题

有时候突然想要忽略某个文件,但是跟新 .gitignore 以后,remote 端并没有马上删除这个文件,原因是ignore文件只能忽略没有加入版本管理的文件,已经被纳入了版本管理的文件是无效的

git rm -r --cached .
git add .
git commit -m 'update .gitignore'

7.使用ssh协议(见git使用中得ssh描述)

8.解决ArgumentError - invalid byte sequence in US-ASCII错误
修改终端语言、地区等国际化环境变量

export LANG=en_US.UTF-8
export LANGUAGE=en_US.UTF-8
export LC_ALL=en_US.UTF-8

9.CI-SSH 问题

#解决ci远程slave访问git时,要求验证私钥密码问题
#即,pod install 时,跟新pod的访问权限问题
#$SSH_PARIVATE_KEY_PASS变量为私钥密码
#为了安全在jenkins的环境变量里面设置这个常量
eval $(ssh-agent)
expect << EOF
spawn ssh-add $1
expect "Enter passphrase"
send "$SSH_PRIVATE_KEY_PASS\r"
expect eof
EOF

10.其他知识点

pod 在多人协作的时候 如何保证 发布版本不会跟着开发走动 :

我们从开发过程可以看到 当我们pod install的时候 会出现下面代码:

Pre-downloading: `Category` from `git@gitlab.xxx.net:xxx_iOS/Category.git`, commit `e244ac83e027b8f6247e702603ecf0209c9d4878`

这里说明 Category这个库 更新了 pod去拉取Category库最新的代码

cocoapods是根据 podfile文件中得 配置去指向指定库 同时 也有一个pod.lock文件 这个文件用于锁定 pod拉取代码的 commit 节点。如下是Category在pod.lock文件中生成的,commit 就是指向对应commit节点。

Category:
:commit: 03c7a540b5c24eda6cea048048adef887cbbc77a
:git: git@gitlab.jfz.net:gxq_iOS/JFZReportModule.git

当然 如果是已经打了tag的不存在这个问题 因为它是按tag去拉取,这里针对的时尚未打tag的库。

5、CocoaPods高级应用

podfile文件的更多应用

1、pod引用参数

1、Build configurations(编译配置)

pod 'PonyDebugger', :configurations => ['Debug', 'Beta']

2、Subspecs(子模块)

pod 'QueryKit', :subspecs => ['Attribute', 'QuerySet']
pod 'QueryKit/Attribute'

3、branch、tag、commit

pod 'AFNetworking', :git => 'https://github.com/gowalla/AFNetworking.git', :branch => 'dev'
pod 'AFNetworking', :git => 'https://github.com/gowalla/AFNetworking.git', :tag => '0.7.0'
pod 'AFNetworking', :git => 'https://github.com/gowalla/AFNetworking.git', :commit => '082f8319af'

4、指定podspec

pod 'JSONKit', :podspec => 'https://example.com/JSONKit.podspec'

2、target

一个工程多个taget需要不同pod配置项的时候

workspace 'xxx.xcworkspace' 指定对应xcworkspace
target :ZipApp do
  project 'FastGPS' 指定对应project

  pod 'SSZipArchive'
end

使用自定义构建配置
project 'TestProject', 'Mac App Store' => :release, 'Test' => :debug

3、inhibit_all_warnings!

屏蔽cocoapods库里面的所有警告

inhibit_all_warnings!
or
pod 'SSZipArchive', :inhibit_warnings => true

4、pre_install

这个钩子允许你在Pods被下载后但是还未安装前对Pods做一些改变

pre_install do |installer|
  # Do something fancy!
end

5、post_install

这个钩子允许你在生成的Xcode project写入硬盘或者其他你想执行的操作前做最后的改动

给所有target自定义编译配置

post_install do |installer|
  installer.pods_project.targets.each do |target|
    target.build_configurations.each do |config|
      config.build_settings['GCC_ENABLE_OBJC_GC'] = 'supported' //配置环境变量等
    end
  end
end

6、abstract_target

抽象target、当多个target的工程并且工程中各个target之间有很大一部分依赖是相同的时候,我们可以抽象出一个抽象target

抽象target中的所有target都自动继承抽象target定义的所有依赖

abstract_target 'Shows' do
  pod 'ShowsKit'

  # The target ShowsiOS has its own copy of ShowsKit (inherited) + ShowWebAuth (added here)
  target 'ShowsiOS' do
    pod 'ShowWebAuth'
  end

  # The target ShowsTV has its own copy of ShowsKit (inherited) + ShowTVAuth (added here)
  target 'ShowsTV' do
    pod 'ShowTVAuth'
  end

  # Our tests target has its own copy of
  # our testing frameworks, and has access
  # to ShowsKit as well because it is
  # a child of the abstract target 'Shows'

  target 'ShowsTests' do
    inherit! :search_paths
    pod 'Specta'
    pod 'Expecta'
  end
end

7、其他参数 swift_version、platform、use_frameworks、inherit

swift_version:指定swift版本号
swift_version = '4.0'

platform:指定系统、版本 

platform :ios, '4.0'
platform :ios

use_frameworks:使用动态库
use_frameworks!

inherit! :search_paths
明确指定继承于父层的所有pod,默认就是继承的

6、参考文献

cocoapods官网

cocoapods都做了什么

cocoapods——dqk

https://kemchenj.github.io/2019-05-31/#more

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

推荐阅读更多精彩内容