Cocoapods使用详解
前言
为什么需要cocoapods?
在进行ios开发的时候,总免不了使用第三方的开源库,比如SSZipArchive、AFNetworking、Reachability等等。使用这些库的时候通常需要:
- 下载开源库的源代码并引入工程
- 向工程中添加开源库使用到的framework
- 解决开源库和开源库以及开源库和工程之间的依赖关系、检查重复添加的framework等问题
- 如果开源库有更新的时候,还需要将工程中使用的开源库删除,重新执行前面的三个步骤
自从有了cocoapods以后,这些繁杂的工作就不再需要我们亲力亲为了,只需要我们做好少量的配置工作,cocoapods会为我们做好一切!
什么是cocoapods?
cocoapods是一个用来帮助我们管理第三方依赖库的工具。它可以解决库与库之间的依赖关系,下载库的源代码,同时通过创建一个xcode的workspace来将这些第三方库和我们的工程连接起来,供我们开发使用。
使用cocoapods的目的是让我们能自动化的、集中的、直观的管理第三方开源库。
1、Cocoapods的安装
cocoapods是用ruby实现的,要想使用它首先需要有ruby的环境。幸运的是OS X系统默认的已经可以运行ruby了,因此我们只需要执行以下命令:
$ sudo gem install cocoapods
&
$ sudo gem install -n /usr/local/bin cocoapods(macOS10.11之后使用)
在安装进程结束的时候,执行命令:
$ pod setup
如果没有报错,就说明一切安装就成功了!
2、使用cocoapods
如果之前做的一切顺利,接下来就可以体验体验cocoapods的神奇之处了!
2.1 pod命令的使用
$ pod --help
| 选项 | 说明 |
|---|---|
| + cache | Manipulate the CocoaPods cache |
| + deintegrate | Deintegrate CocoaPods from your project |
| + dependencies | Show project's dependency graph. |
| + env | Display pod environment |
| + init | Generate a Podfile for the current directory |
| + install | Install project dependencies according to versions from Podfile.lock |
| + ipc | Inter-process communication |
| + lib | Develop pods |
| + list | List pods |
| + outdated | Show outdated project dependencies |
| + package | Package a podspec into a static library. |
| + plugins | Show available CocoaPods plugins |
| + repo | Manage spec-repositories |
| + search | Search for pods |
| + setup | Setup the CocoaPods environment |
| + spec | Manage pod specs |
| + trunk | Interact with the CocoaPods API (e.g. publishing new specs) |
| + try | Try a Pod! |
| + update | Update outdated project dependencies and create new Podfile.lock |
2.1.1 cache(缓存)
操作 CocoaPods 缓存,比如打印缓存内容,或者清理pods缓存
$ pod cache COMMAND
| 选项 | 说明 |
|---|---|
| + clean | 清理pods缓存 |
| + list | 打印缓存信息 |
选项:
| 选项 | 说明 |
|---|---|
| --allow-root | root权限运行cocoapods |
| --silent | 不显示任何信息 |
| --verbose | 显示调试信息 |
| --no-ansi | 显示内容不包含ANSI码 |
| --help | 显示帮助信息 |
2.1.2 deintegrate (分离)
从您的项目中分离 CocoaPods,从工程中移除所有的Cocoapods记录,如何xcodeproj没有被指定,会在当前目录搜索Xcode工程,并默认使用它。
$ pod deintegrate [XCODE_PROJECT]
比如:
$ pod deintegrate Masonry.xcodeproj
选项:
| 选项 | 说明 |
|---|---|
| --project-directory=/project/dir/ | 工程的根目录路径 |
| --allow-root | root权限运行cocoapods |
| --silent | 不显示任何信息 |
| --verbose | 显示调试信息 |
| --no-ansi | 显示内容不包含ANSI码 |
| --help | 显示帮助信息 |
2.1.3 env(环境)
显示Cocoapods环境参数。
$ pod env
选项:
| 选项 | 说明 |
|---|---|
| --allow-root | root权限运行cocoapods |
| --verbose | 显示调试信息 |
| --no-ansi | 显示内容不包含ANSI码 |
| --help | 显示帮助信息 |
2.1.4 init(初始化)
首先当前目录要存在.xcodeproj文件,如何当前目录不存在Podfile文件,则会创建一个Podfile文件,如果指定了xcodeproj文件名或者当前目录只存在单个工程,targe将会根据工程自动生成。
$ pod init XCODEPROJ
比如:
$ pod init
or
$ pod init test.xcodeproj
选项:
| 选项 | 说明 |
|---|---|
| --allow-root | root权限运行cocoapods |
| --silent | 不显示任何信息 |
| --verbose | 显示调试信息 |
| --no-ansi | 显示内容不包含ANSI码 |
| --help | 显示帮助信息 |
2.1.5 install(安装)
下载Podfile文件中声明的所有Pods,并且在工程的./Pods文件夹下创建各个库。
$ pod install
选项:
| 选项 | 说明 |
|---|---|
| --repo-update | 安装之前强制执行pod repo update |
| --deployment | 不允许在安装期间对 Podfile 或 Podfile.lock 进行任何更改 |
| --clean-install | install之前clean |
| --project-directory=/project/dir/ | 工程所在的根路径 |
| --allow-root | root权限运行cocoapods |
| --silent | 不显示任何信息 |
| --verbose | 显示调试信息 |
| --no-ansi | 显示内容不包含ANSI码 |
| --help | 显示帮助信息 |
2.1.6 ipc(内部进程通信)
内部进程通信
$ pod ipc COMMAND
| 选项 | 说明 |
|---|---|
| + list | 显示所有的Cocoapods规则 |
| + podfile | 转换 Podfile 为 YAML |
| + podfile-json | 转换 Podfile 为 JSON |
| + repl | 监听输入 |
| + spec | 转换 podspec 为 JSON |
| + update-search-index | 更新search索引 |
选项:
| 选项 | 说明 |
|---|---|
| --allow-root | root权限运行cocoapods |
| --silent | 不显示任何信息 |
| --verbose | 显示调试信息 |
| --no-ansi | 显示内容不包含ANSI码 |
| --help | 显示帮助信息 |
2.1.7 lib(库)
开发一个库
$ pod lib COMMAND
| 选项 | 说明 |
|---|---|
| + create | 创建一个pod库 |
| + lint | 验证pod库 |
选项:
| 选项 | 说明 |
|---|---|
| --allow-root | root权限运行cocoapods |
| --silent | 不显示任何信息 |
| --verbose | 显示调试信息 |
| --no-ansi | 显示内容不包含ANSI码 |
| --help | 显示帮助信息 |
2.1.8 list(列表)
展示所有的可用库
$ pod list
选项:
| 选项 | 说明 |
|---|---|
| --update | install之前pod repo update |
| --stats | 展示状态 |
| --allow-root | root权限运行cocoapods |
| --silent | 不显示任何信息 |
| --verbose | 显示调试信息 |
| --no-ansi | 显示内容不包含ANSI码 |
| --help | 显示帮助信息 |
2.1.9 outdated(过期)
显示当前 Podfile.lock 中过时的 pod,但仅显示来自规范的那些存储库,而不是来自本地/外部来源的存储库。
$ pod outdated
选项:
| 选项 | 说明 |
|---|---|
| --ignore-prerelease | 忽略预发布版本 |
| --no-repo-update | 不更新repo仓库 |
| --project-directory=/project/dir/ | 工程的根目录路径 |
| --allow-root | root权限运行cocoapods |
| --silent | 不显示任何信息 |
| --verbose | 显示调试信息 |
| --no-ansi | 显示内容不包含ANSI码 |
| --help | 显示帮助信息 |
2.1.10 package(包)
将 podspec 打包到静态库中。
$ pod package NAME
pod package 是 cocoapods 的一个插件,如果没有的话使用以下命令安装:
$ sudo gem install cocoapods-packager
pod package 是根据 .podspec 描述文件来生成二进制库
$ pod package Masonry.podspec --force --embedded
| 选项 | 说明 | |
|---|---|---|
| --force | 强制覆盖之前已经生成过的二进制库 | |
| --embedded | 生成静态.framework | |
| --library | 生成静态.a | |
| --dynamic | 生成动态.framework | |
| --bundle-identifier | 动态.framework是需要签名的,所以只有生成动态库的时候需要这个BundleId | |
| --exclude-deps | 不包含依赖的符号表,生成动态库的时候不能包含这个命令,动态库一定需要包含依赖的符号表。 | |
| --configuration | 表示生成的库是debug还是release,默认是release。 | --configuration=Debug |
| --no-mangle | 表示不使用name mangling技术,pod package默认是使用这个技术的。我们能在用pod package生成二进制库的时候会看到终端有输出Mangling symbols和Building mangled framework。表示使用了这个技术。如果你的pod库没有其他依赖的话,那么不使用这个命令也不会报错。但是如果有其他依赖,不使用--no-mangle这个命令的话,那么你在工程里使用生成的二进制库的时候就会报错:Undefined symbols for architecture x86_64。 | |
| --subspecs | 如果你的pod库有subspec,那么加上这个命名表示只给某个或几个subspec生成二进制库,--subspecs=subspec1,subspec2。生成的库的名字就是你podspec的名字,如果你想生成的库的名字跟subspec的名字一样,那么就需要修改podspec的名字。 这个脚本就是批量生成subspec的二进制库,每一个subspec的库名就是podspecName+subspecName。 | |
| --spec-sources | 一些依赖的source,如果你有依赖是来自于私有库的,那就需要加上那个私有库的source,默认是cocoapods的Specs仓库。--spec-sources=private,github.com/CocoaPods/S… |
2.1.11 plugins(插件)
- 列出或搜索可用的 CocoaPods 插件并显示您是否拥有它们安装与否。
- 还允许您使用提供的模板快速创建新的Cocoapods插件。
$ pod plugins [COMMAND]
| 选项 | 说明 |
|---|---|
| + create | 创建Cocoapods插件 |
| + installed | 列出你安装的插件在本机上 |
| > list | 列出所有已知的插件 |
| + publish | 请求添加到官方插件列表中 |
| + search | 搜索已知的插件 |
选项:
| 选项 | 说明 |
|---|---|
| --allow-root | root权限运行cocoapods |
| --silent | 不显示任何信息 |
| --verbose | 显示调试信息 |
| --no-ansi | 显示内容不包含ANSI码 |
| --help | 显示帮助信息 |
2.1.12 repo(仓库)
管理规范存储库
$ pod repo [COMMAND]
| 选项 | 说明 |
|---|---|
| + add | 添加一个规范仓库 |
| + add-cdn | 通过CDN方式添加一个规范仓库 |
| + lint | 验证仓库中所有的规范 |
| > list | 展示所有的仓库 |
| + push | 推送新的规范到规范仓库 |
| + remove | 移除一个规范仓库 |
| + update | 更新一个规范仓库 |
选项:
| 选项 | 说明 |
|---|---|
| --allow-root | root权限运行cocoapods |
| --silent | 不显示任何信息 |
| --verbose | 显示调试信息 |
| --no-ansi | 显示内容不包含ANSI码 |
| --help | 显示帮助信息 |
2.1.13 search(搜索)
搜索 pod,忽略大小写,其名称、摘要、描述或作者与“QUERY”匹配。 如果指定了
--simple选项,则只会搜索 pod 的名称。
$ pod search QUERY
选项:
| 选项 | 说明 |
|---|---|
| --regex | 将“QUERY”解释为正则表达式 |
| --simple | 仅按名称搜索 |
| --stats | 显示其他统计信息(如 GitHub 观察者和分叉) |
| --web | 在 cocoapods.org 上搜索 |
| --ios | 将搜索限制在 iOS 上支持的 Pod |
| --osx | 将搜索限制在 macOS 上支持的 Pod |
| --watchos | 将搜索限制为 watchOS 支持的 Pod |
| --tvos | 将搜索限制在 tvOS 上支持的 Pod |
| --allow-root | root权限运行cocoapods |
| --verbose | 显示调试信息 |
| --no-ansi | 显示内容不包含ANSI码 |
| --help | 显示帮助信息 |
2.1.14 setup(启动)
设置 CocoaPods 环境
$ pod setup
选项:
| 选项 | 说明 |
|---|---|
| --allow-root | root权限运行cocoapods |
| --silent | 不显示任何信息 |
| --verbose | 显示调试信息 |
| --no-ansi | 显示内容不包含ANSI码 |
| --help | 显示帮助信息 |
2.1.15 spec(规则)
管理pod规范
$ pod spec COMMAND
选项:
| 选项 | 说明 |
|---|---|
| + cat | 打印规范文件内容 |
| + create | 创建规范文件 |
| + edit | 编辑规范文件 |
| + lint | 验证规范文件 |
| + which | 打印规范文件路径 |
选项:
| 选项 | 说明 |
|---|---|
| --allow-root | root权限运行cocoapods |
| --silent | 不显示任何信息 |
| --verbose | 显示调试信息 |
| --no-ansi | 显示内容不包含ANSI码 |
| --help | 显示帮助信息 |
2.1.16 trunk(主干)
与 CocoaPods API 交互(例如发布新规范)
$ pod trunk COMMAND
| 选项 | 说明 |
|---|---|
| + add-owner | 添加所有者到 pod |
| + delete | 删除 pod 的版本 |
| + deprecate | 弃用 pod |
| + info | 返回有关 Pod 的信息 |
| + me | 显示有关您的会话的信息 |
| + push | 发布一个 podspec |
| + register | 管理会话 |
| + remove-owner | 从 pod 中删除所有者 |
选项:
| 选项 | 说明 |
|---|---|
| --allow-root | root权限运行cocoapods |
| --silent | 不显示任何信息 |
| --verbose | 显示调试信息 |
| --no-ansi | 显示内容不包含ANSI码 |
| --help | 显示帮助信息 |
2.1.17 try
- 使用给定的
NAME(或 GitURL)下载 Pod,安装其依赖项,如果需要并打开其演示项目。- 如果提供了 Git URL, podspec由于某种原因,名称与 git repo 不同,还需要提供 --podspec_name。
$ pod try NAME|URL
选项:
| 选项 | 说明 |
|---|---|
| --no-repo-update | 在安装前跳过运行 pod repo update |
| --podspec_name=[name] | Git 存储库中 podspec 文件的名称 |
| --allow-root | root权限运行cocoapods |
| --silent | 不显示任何信息 |
| --verbose | 显示调试信息 |
| --no-ansi | 显示内容不包含ANSI码 |
| --help | 显示帮助信息 |
2.1.18 update(更新)
更新由指定的
POD_NAMES标识的 Pod,这是一个以空格分隔的 Pod 名称列表。 如果没有指定POD_NAMES,它会更新所有 Pod,忽略 Podfile.lock 的内容。 该命令保留用于更新依赖项; pod install 应该用于安装对 Podfile 的更改。
$ pod update [POD_NAMES ...]
选项:
| 选项 | 说明 |
|---|---|
| --sources=cdn.cocoapods.org/ | 更新依赖 pod 的来源。 多个来源必须用逗号分隔 |
| --exclude-pods=podName | 更新期间要排除的 Pod。 多个 pod 必须用逗号分隔 |
| --clean-install | 忽略项目缓存的内容并强制安装完整的 pod。 这仅适用于已启用的项目增量安装 |
| --project-directory=/project/dir/ | 项目目录根目录的路径 |
| --no-repo-update | 在安装前跳过运行 pod repo update |
| --allow-root | root权限运行cocoapods |
| --silent | 不显示任何信息 |
| --verbose | 显示调试信息 |
| --no-ansi | 显示内容不包含ANSI码 |
| --help | 显示帮助信息 |
2.1.19 dependencies(依赖)
显示工程依赖
$ pod dependencies [PODSPEC]
3 Podfile的使用
3.1 什么是Podfile?
Podfile是一个规范,描述了一个或多个一套工程目标的依赖项
3.2 各种参数配置含义
3.2.1 Root Options(根选项)
3.2.1.1 install!(安装)
适用于整个podfile文件
- 1、指定 CocoaPods 安装此 Podfile 时要使用的安装方法和选项。
- 2、第一个参数表示要使用的安装方式; 后面的参数表示安装选项。
- 3、目前唯一接受的安装方法是'cocoapods',所以你总是使用这个值作为第一个参数; 但在未来的版本中可能会提供更多的安装方法。
Examples
install! 'cocoapods'
:deterministic_uuids => false,
:integrate_targets => false
| 选项 | 说明 | 备注 |
|---|---|---|
| :clean | 安装过程中是否清理pod的来源,清理将删除pod没有使用的所有文件,这些文件由podspec和项目支持的平台指定 | 此选项默认为 true |
| :deduplicate_targets | 标记是否删除相同的pod target,当一个pod包含在多个具有不同需求的target中时,target重复数据删除会向pod target添加后缀。 | 此选项默认为 true, 下面有详细介绍 |
| :deterministic_uuids | 在创建Pods项目时是否生成确定的uuid。 | 此选项默认为 true |
| :integrate_targets | 标记是否将pods添加到项目中,如果设置为false,则只会下载到Pods/文件夹下 | 此选项默认为 true |
| :lock_pod_sources | 标记是否对pod库中文件内容加锁,默认是加锁的,所以当我们在修改pod库中的文件时,经常会有提示是否解锁的弹窗 | 此选项默认为 true |
| :warn_for_multiple_pod_sources | 标记当多个源包含相同名称和版本的Pod时,是否发出警告⚠️。如果发现了这个警告,我们需要手动指定这个pod使用的源。 | 此选项默认为 true |
| :warn_for_unused_master_specs_repo | 如果项目没有明确指定基于git的master分支的spec repo,就使用默认的CDN代替,这种情况下是否发出警告 | 此选项默认为 true |
| :share_schemes_for_development_pods | 标记对于DevelopmentPods是否共享Xcode的schemes,默认是不会共享的,DevelopmentPods的schemes会自动创建。 | 此选项默认为 false |
| :disable_input_output_paths | 标记是否禁用CocoaPods脚本阶段的输入和输出路径 (Copy Frameworks & Copy Resources) 为Xcode配置-》Build Phases -》[cp]Copy Pods Resources下面的Input Files & Output Files | 此选项默认为 false |
| :preserve_pod_file_structure | 标记是否保留所有pod的文件夹结构,包括外部的pod。默认情况下,Pod库的文件结构只保留给开发Pod使用,我们在项目中查看三方pod库时,都是放在一个文件夹中,但是在开发时是有文件夹结构的。 | 此选项默认为 false |
| :generate_multiple_pod_projects | 标记是否为每个pod库生成一个project,而不是只创建1个Pods.xcodeproj。如果设置为true,此选项将为每个将嵌套在Pods.xcodeproj下的pod库生成一个对应的project,并且有文章还说,设置为true后,会提升项目的解析速度 | 此选项默认为 false |
| :incremental_installation | 当执行 pod install 时,CocoaPods 现在支持仅重新生成自上次 install 以来发生更改的 pod 库,而不是像之前那样重新生成整个 workspace。设置incremental_installation 为 true 选项开启此功能,但是incremental_installation 选项需要启用 generate_multiple_pod_projects 安装选项才能使其正常运行。 | 此选项默认为 false |
| :skip_pods_project_generation | 标记是否跳过生成Pods.Xcodeproj,只执行依赖关系解析和下载,设置为true,会影响使用呀 | 此选项默认为 false |
两个target都依赖了同一个pod库,如下所示:
target 'MyTargetA' do
pod 'MyPod/SubA'
pod 'OtherPod'
end
target 'MyTargetB' do
pod 'MyPod'
pod 'OtherPod'
end
如果将deduplicate_targets设置为false,则会生成带后缀的两个OtherPod,一个供MyTargetA使用,一个供MyTargetB使用,但是实际上是一个东西呀,所以就需要干掉一个,让两个Target使用同一个OtherPod,就需要将deduplicate_targets设置为true。 但是不会影响MyPod,因为MyTargetA使用的是子库,MyTargetB 使用的是主库,所以对应会有两个MyPod的target。
3.2.1.2 ensure_bundler!(Bundler版本)
使用Global Gemset运行CocoaPods时引发警告。如果bundler版本与所需版本不匹配,可以提供语义版本来发出警告。许多项目在与 CocoaPods 一起使用时都在后台使用Bundler。这是因为 Bundler 确保了一致的环境,这对于开发同一项目的团队很有用。在1.10.0版本之后,提供了一个新的 ensure_bundler! DSL,可以添加到 Podfile 中,以指定 Bundler 版本的版本要求。
| 选项 | 说明 | 备注 |
|---|---|---|
| ensure_bundler! | 使用 Global Gemset 运行 CocoaPods 时发出警告。 如果bundler版本与所需版本不匹配,可以提供语义版本以发出警告。 | 一般不需指定 |
如下:
ensure_bundler!
or
ensure_bundler! '~> 1.17.3'
这里拓展一下Bundler在cocoapods中的使用
前置知识
- gem是一个软件库管理工具,提供了像Cocoapods、Fastlane等常用软件
- Bundler就是gem提供的一个用于统一gem软件版本的工具
Bundler工作原理
作为iOS开发,对Podfile和Podfile.lock肯定是有些了解的。其实Bundler也是基于同样的思想,而且Podfile的思路其实是有借鉴Bundler的。
Bundler需要两个文件的支持,分别是Gemfile和Gemfile.lock
- Gemfile中用于指定所使用的的gem软件的版本信息和软件下载源
- Gemfile.lock则用于锁定当前使用的软件版本信息,需要提交到代码仓库,用于不同开发者不同电脑上使用gem软件对项目工程操作时进行统一版本协同
使用方法
iOS项目A,需要使用1.11.2版本的Cocoapods进行库依赖管理,但开发者a电脑上用的1.4.3的Cocoapods,而开发者b电脑上用的是高版本1.8.0的Cocoapods 不同版本的Cocoapods在执行依赖安装或更新时,很容易出现冲突情况。最好的版本肯定是大家统一Cocoapods版本。但Bundler则给了更好的解决方案,我们新创建一个Gemfile文件,写入
source 'https://rubygems.org' do
gem 'cocoapods', '1.11.2'
end
然后执行bundle install,bundler会根据Gemfile内容创建Gemfile.lock文件,此文件要放入git等版本控制中;同时会下载安装Gemfile中指定版本的软件。
最后执行bundle exec pod install命令,bundler会检查按需下载安装相应版本的Cocoapods并进行pod install操作
官方建议最好用bundle exec pod xx形式,虽然有时候直接pod install也可以work,但在不同机器不同环境下直接执行pod install是没办法保证Cocoapods版本的
3.2.2 Dependencies (依赖)
Podfile指定每个target的依赖项。
- Pod是一种声明特定依赖的方式。
- podspec为创建podspec提供了一个简单的API。
- target是你在Xcode项目中的target。
3.2.2.1 pod
3.2.2.1.1 pod
pod 用于指定项目的依赖项,依赖项必须指定名称,版本是可选的。
- 没有指定版本号,则会默认使用最新的版本:
$ pod 'SSZipArchive'
- 可以指定使用固定的版本
$ pod 'Objection', '0.9'
-
除了没有版本或特定版本外,还可以使用操作符:
-
= 0.1 版本号=0.1
-
> 0.1 版本号>0.1
-
>= 0.1 版本号>=0.1
-
< 0.1 版本号<0.1
-
<= 0.1 版本号<=0.1
-
~> 0.1.2 版本号 >= 0.1.2 && 版本号 < 0.2.0
-
~> 0 版本号 >= 0 && 版本号 < 1
-
~> 0.1.3-beta.0 Beta和发布版本为0.1.3,发布版本 >= 0.1.3 && 发布版本<0.2.0。用破折号(-)分隔的组件将不考虑版本要求。
3.2.2.1.2 Build configurations(构建配置中)
默认情况下,依赖项安装在目标的所有构建配置中。如果出于调试目的或其他原因,需要只在Debug模式下启用,可以如下配置:
pod 'PonyDebugger', :configurations => ['Debug', 'Beta']
or
pod 'PonyDebugger', :configuration => 'Debug'
3.2.2.1.3 Modular Headers (模块化头文件)
- 如果你想使用模块头每个Pod你可以使用以下语法:
$ pod 'SSZipArchive', :modular_headers => true
导入时可以使用 @import SSZipArchive; 进行导入。
- 当你使用use_modular_headers!属性,你可以使用以下方法从模块头文件中排除一个特定的Pod:
$ pod 'SSZipArchive', :modular_headers => false
拓展一下#include、#import和@import的区别
- #include
熟悉 C 或者 C++ 的童鞋可能会知道,在 C 和 C++ 里,#include 是非常常见的,用来包含头文件。#include 做的事情其实就是简单的复制粘贴,将目标 .h 文件中的内容一字不落地拷贝到当前文件中,并替换掉这句 include。
注意点:在使用#include的时候要注意处理重复引用(这也是objc中#include与#import的区别)
- #import
#import 大部分功能和 #include 是一样的,但是他处理了重复引用的问题,我们在引用文件的时候不用再去自己进行重复引用处理,这使你在递归包含中不会出现问题。总的来说,#import 比起 #include 的好处就是不会引起交叉编译。
- @import
@import 是 iOS 7 之后的新特性语法,这种方式叫 Modules(模块导入) 或者 “semantic import(语义导入)” ,是一种更好的头部预处理的执行方式,这 iOS 7 之后你能通过 @import 语法来导入任何的framework,Modules 是一种将所有可执行的 framework 打包在一起,只有在需要时才能导入到源代码中,这种方式比起传统的 #import 更安全和更高效。
举个例子:
#import <SSZipArchive/SSZipArchive.h>
要将此库作为模块导入,代码将改为:
@import SSZipArchive;
这有助于将代码将 SSZipArchive 框架自动链接到项目中。模块还允许您仅将您真正需要的组件包含在项目中。例如,如果要在 SSZipArchive 框架中使用 SSZipCommon 组件,通常您必须导入所有内容才能使用一个。但是,使用模块可以导入要使用的特定对象:
@import SSZipArchive.SSZipCommon;
实际开发中上可能并不需要使用 @import 关键字。如果你选择使用”modules”(Xcode5 以后中默认开启),所有的 #import 和 #include 指令都会自动映射使用 @import。尤其对于没有善用 .pch 头文件的开发者或者你的项目中有许多零碎小的源文件时, 使用 @import 导入指定框架下需要的头文件时,Xcode 的编译表现会有提高。
3.2.2.1.4 Source(指定源)
默认情况下,在全局级别指定的源将按照依赖项匹配指定的顺序进行搜索。对于特定的依赖,可以单独指定依赖源:
pod 'PonyDebugger', :source => 'https://github.com/CocoaPods/Specs.git'
3.2.2.1.5 Subspecs (使用子库)
当通过Pod的名称安装Pod时,它将安装podspec文件中定义的所有默认subspecs。
可以使用下面的方式导入特定的subspec:
pod 'AFNetworking/UIKit'
or
pod 'AFNetworking', :subspecs => ['NSURLSession', 'Reachability']
3.2.2.1.6 Test Specs(测试子库)
Test Specs可以通过:testspecs选项包含。默认情况下,Test Specs都不包括在内。
可以使用下面的方式进行导入:
pod 'AFNetworking', :testspecs => ['UnitTests', 'SomeOtherTests']
注意: 提供给 :testspecs 的值对应于提供给 Podspec 中 test_spec DSL 属性的名称。
3.2.2.1.7 Using the files from a local path (使用本地路径)
如果和项目一样在本地开发Pod,可以使用path选项,如下:
pod 'ttPodfile', :path => '../ttPodfile/ttPodfile.podspec'
or
pod 'ttPodfile', :path => '../ttPodfile'
注意,Pod文件的podspec必须在该文件夹中。
3.2.2.1.8 指定分支或者commit
- 指定源,默认是master分支
pod 'AFNetworking', :git => 'https://github.com/gowalla/AFNetworking.git'
- 使用其它分支
pod 'AFNetworking', :git => 'https://github.com/gowalla/AFNetworking.git', :branch => 'dev'
- 使用tag
pod 'AFNetworking', :git => 'https://github.com/gowalla/AFNetworking.git', :tag => '0.7.0'
- 特殊的commit
pod 'AFNetworking', :git => 'https://github.com/gowalla/AFNetworking.git', :commit => '082f8319af'
podspec文件应该位于存储库的根目录中,如果这个库的存储库中还没有podspec文件,可以从另一个源库的地址引入:
pod 'JSONKit', :podspec => 'https://example.com/JSONKit.podspec'
3.2.2.2 podspec
使用给定podspec文件中定义的代码库的依赖关系。如果没有传入任何参数,podspec优先使用根目录,如果是其它情况必须在后面指明。(一般使用默认设置即可)例如:
# 不指定表示使用根目录下的podspec,默认一般都会放在根目录下
podspec
# 如果podspec的名字与库名不一样,可以通过这样来指定
podspec :name => 'QuickDialog'
# 如果podspec不是在根目录下,那么可以通过:path来指定路径
podspec :path => '/Documents/PrettyKit/PrettyKit.podspec'
3.2.2.3 target(目标)
在给定的块内定义pod的target(Xcode工程中的target)和指定依赖的范围。一个target应该与Xcode工程的target有关联。默认情况下,target会包含定义在块外的依赖,除非指定不使用inherit!来继承(说的是嵌套的块里的继承问题)。
- 定义一个简单target ZipApp引入SSZipArchive库
target 'ZipApp' do
pod 'SSZipArchive'
end
- 定义一个ZipApp target仅引入SSZipArchive库,定义ZipAppTests target 引入Nimble的同时也会继承ZipApp target里面的SSZipArchive库
target 'ZipApp' do
pod 'SSZipArchive'
target 'ZipAppTests' do
inherit! :search_paths
pod 'Nimble'
end
end
- target块中嵌套多个子块
target 'ShowsApp' do
# ShowsApp 仅仅引入ShowsKit
pod 'ShowKit'
# 引入 ShowsKit 和 ShowTVAuth
target 'ShowsTV' do
pod 'ShowTVAuth'
end
# 引入了Specta和Expecta以及ShowsKit
target 'ShowsTests' do
inherit! :search_paths
pod 'Specta'
pod 'Expecta'
end
end
3.2.2.4 script_phase(脚本)
使用这个命令给target添加shell脚本
- :name 脚本显示名称
- :script 脚本内容
- :execution_position 执行位置如:before_compile/:after_compile(编译前还是编译后)
- :shell_path 脚本可执行文件路径
- :input_files/:output_files/show_env_vars_in_log 对应自定义脚本的选项
target ‘A’ do
script_phase :name => 'HelloWorldScript', :script => 'echo "Hello World”'
script_phase :name => 'HelloWorldScript', :script => 'puts "Hello World"', :shell_path => '/usr/bin/ruby', :execution_position => :after_compile
end
3.2.2.5 abstract_target(抽象目标)
定义一个新的抽象目标target,可用于方便的目标依赖项继承。
# 注意:这是个抽象的target也就是说在工程中并没有这个target引入ShowsKit
abstract_target 'Shows' do
pod 'ShowsKit'
# ShowsiOS target会引入ShowWebAuth库以及继承自Shows的ShowsKit库
target 'ShowsiOS' do
pod 'ShowWebAuth'
end
# ShowsTV target会引入ShowTVAuth库以及继承自Shows的ShowsKit库
target 'ShowsTV' do
pod 'ShowTVAuth'
end
# ShowsTests target引入了Specta和Expecta库,并且指明继承Shows,所以也会引入ShowsKit
target 'ShowsTests' do
inherit! :search_paths
pod 'Specta'
pod 'Expecta'
end
end
3.2.2.6 abstract!(抽象)
abstract! 指示当前的target是抽象的,因此不会直接链接Xcode target。
target 'target' do
abstract!
end
3.2.2.7 inherit!(继承)
设置当前目标的继承模式。
- inherit! :complete 继承了父对象的所有行为
- inherit! :none 目标不会从父对象继承任何行为
- inherit! :search_paths 目标只继承父节点的搜索路径
target 'App' do
target 'AppTests' do
inherit! :search_paths
end
end
3.2.3 Target configuration (目标项配置)
使用target 配置来控制的cocoapods生成project。开始时详细说明您正在使用什么平台上。工程文件里允许您具体说明哪些项目的链接。
3.2.3.1 platform(平台)
platform用于指定应建立的静态库的平台。CocoaPods提供了默认的平台版本配置: iOS->4.3 OS X->10.6 tvOS->9.0 watchOS->2.0 如果部署目标需要iOS < 4.3,armv6体系结构将被添加到ARCHS。
#指定具体平台和版本
platform :ios, '4.0'
platform :ios
platform :osx
platform :tvos
platform :watchos
3.2.3.2 project(工程)
如果没有显示的project被指定,那么会默认使用target的父target指定的project作为目标。如果如果没有任何一个target指定目标,那么就会使用和Podefile在同一目录下的project。同样也能够指定是否这些设置在release或者debug模式下生效。为了做到这一点,你必须指定一个名字和:release:debuge关联起来。
# testabc这个target引入的库只能在test工程中引用
target 'testabc' do
project 'test'
...
end
3.2.3.3 inhibit_all_warnings!(屏蔽广告)
inhibit_all_warnings! 屏蔽所有来自于cocoapods依赖库的警告。你可以全局定义,也能在子target里面定义,也可以指定某一个库:
# 隐藏SSZipArchive的警告而不隐藏ShowTVAuth的警告
pod 'SSZipArchive', :inhibit_warnings => true
3.2.3.4 use_modular_headers!(使用模块化头文件)
该特性是 Cocoapods 1.5.0 引入的配置,目的是为了满足 Xcode 9 以后支持的 Swift Static Libraries ,将 Swift Pods 构建成为静态库
-
如果你的 Swift Pod 依赖于 Objective-C,那么你需要为这个 Objective-C 库启用 modular_headers
-
对于 pod 开发者可以在 pod target xcconfig 内添加 ’DEFINES_MODULE’=>‘YES’,对于使用者在 podfile 内添加 use_modular_headers!
为所有CocoaPods静态库使用模块化头文件。也可以针对单个pod特殊指定:
pod 'SSZipArchive', :modular_headers => true
苹果为 Swift 设计了 SwiftModule。SwiftModule 可以将 Swift 解析后生成对应的 modulemap 和 umbrella.h 文件,SwiftModule 增加对编译器版本的依赖,编译产物与编译器 和 Swift 版本有关。如果想要实现 Swift 和 Objective-C 的互相访问,需要 Objective-C 库,以及对应的 umbrella.h 和 modulemap 支持。其中动态库 framework 是 Xcode 支持配置并生成 header,静态库 .a 需要自己编写对应的 umbrella.h 和 modulemap。即库之间无论何种语言实现,均需要封装为 LLVM Module 来相互访问。
LLVM Module 作为苹果公司提出的特性,已经被 Swift 完全采用,在其基础上建立自己的模块系统,当我们结合 Cocoapods 的 use_modular_headers! 配置将三方库构建成静态库,或者 use_frameworks! 配置将三方库构建成动态库时,在编译产物中都会生成一个 modulemap 和 module umbrella.h 文件
3.2.3.5 user_frameworks!(使用动态库)
使用frameworks而不是静态库。当使用frameworks时,你也可以指定:linkage样式来使用,比如:static或:dynamic。
- 如果使用use_frameworks!命令会在Pods工程下的Frameworks目录下生成依赖库的framework
- 如果不使用use_frameworks!命令会在Pods工程下的Products目录下生成.a的静态库
此属性可以由子目标target定义继承。
target 'MyApp' do
use_frameworks!
pod 'AFNetworking', '~> 1.0'
end
target 'MyApp' do
use_frameworks! :linkage => :dynamic
pod 'AFNetworking', '~> 1.0'
end
target 'ZipApp' do
use_frameworks! :linkage => :static
pod 'SSZipArchive'
end
3.2.3.6 support_siwft_versions(支持swift版本)
指定此目标定义支持的Swift版本要求。注意:这些需求可以从父级继承的,如果没有指定,那么所有的版本都被认为是支持的。
target 'MyApp' do
supports_swift_versions '>= 3.0', '< 4.0'
pod 'AFNetworking', '~> 1.0'
end
supports_swift_versions '>= 3.0', '< 4.0'
target 'MyApp' do
pod 'AFNetworking', '~> 1.0'
end
target 'ZipApp' do
pod 'SSZipArchive'
end
3.2.4 Workspace(工作区)
指定包含所有项目的Xcode工作区。
workspace 'MyWorkspace'
如果没有明确指定Xcode工作空间,并且只有一个项目存在于与Podfile相同的目录中,那么这个项目的名称将被用作工作空间的名称。
3.2.5 Sources(源)
Podfile从给定的源代码(存储库)列表中检索规范,源是全局的,它们不是按目标定义存储的。一般都是写到podfile文件最顶部:
source 'https://github.com/artsy/Specs.git'
source 'https://github.com/CocoaPods/Specs.git'
注意事项:
- 使用此方法会依赖于来源的顺序。CocoaPods将使用包含Pod的第一个来源的Pod的最高版本(无论其他来源是否有更高的版本)。
- 如果指定了别的源,也需要将官方的源写一下
3.2.6 Hooks(钩子)
Podfile提供将在install过程中调用的钩子。钩子是全局的,不是按目标定义存储的。
3.2.6.1 Plugin(插件)
使用这个方法可以指定在安装过程中应该使用的插件,以及在调用插件时应该传递给插件的选项。
plugin 'cocoapods-keys', :keyring => 'Eidolon'
plugin 'slather'
3.2.6.2 pre_install
这个钩子允许你对pod在下载完成之后,但是在install之前做一些操作。
pre_install do |installer|
# 做一些安装之前的更改
end
3.2.6.3 pre_integrate
该钩子允许您在将项目写入磁盘之前进行更改。
pre_integrate do |installer|
# perform some changes on dependencies
end
3.2.6.4 post_install
这个钩子允许你在生成的Xcode项目被写入磁盘之前对它做任何最后的修改,或者任何你想要执行的任务。
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
3.2.6.5 post_integrate
这个钩子允许您在项目被写入磁盘后进行更改。
post_integrate do |installer|
# some change after project write to disk
end
3.2.7 def
我们还可以通过def命令来声明一个pod集:
def 'CustomPods'
pod 'IQKeyboardManagerSwift'
end
然后,我们就可以在需要引入的target处引入:
target 'MyTarget' do
CustomPods
end
这么写的好处是:如果有多个target,而不同target之间并不全包含,那么可以通过这种方式来分开引入。
3.2.8 project_name Podfile DSL
CocoaPods 1.7 引入了 generate_multiple_pod_projects 选项,该选项将每个 pod 安装到自己的 Xcode 项目中。CocoaPods 1.8 通过引入 project_name DSL 做了进一步扩展,允许 pod 使用者指定项目名称以集成给定的 pod。
这为使用者开辟了许多新的可能性,可以将某些 pods 分组在一起,这是很有意义的。请考虑以下示例:
install! 'cocoapods', :generate_multiple_pod_projects => true
target 'MyApp' do
use_frameworks!
pod 'Moya', :project_name => 'Networking'
pod 'Alamofire', :project_name => 'Networking'
pod 'Result', :project_name => 'Networking'
target 'MyAppTests' do
inherit! :search_paths
pod 'OCMock', :project_name => 'Testing'
end
end
这会产生以下结果:
使用者可以选择自己的分组,并在其 Podfile 中提供自动使用项目名称的辅助方法。例如,另一个分组想法是通过其平台(如iOS或macOS)对 pod 进行分组。
注意:project_name 选项当前还需要启用 generate_multiple_pod_projects 安装选项才能正常工作。增量安装也已更新,以考虑为每个 pod 使用的项目名称,并将继续按预期工作。
4、podpsec文件的使用
Podspec 是用于 描述一个 Pod 库的源代码和资源将如何被打包编译成链接库或 framework 的文件 ,而 Podspec 中的这些描述内容最终将映会映射到 Specification 类中(以下简称 Spec)。
4.1 Specification(规范)
规范描述了Pod库的版本。它包括从何处获取源、使用哪些文件、应用的构建设置以及其他常规元数据(例如:名称、版本和说明)等详细信息。
可以通过pod spec create命令生成存根规范文件(podspec文件)。
DSL规范提供了极大的灵活性和动态性。此外,DSL采用了按约定编程。因此他可以非常的简单:
Pod::Spec.new do |spec|
spec.name = 'Reachability'
spec.version = '3.1.0'
spec.license = { :type => 'BSD' }
spec.homepage = 'https://github.com/tonymillion/Reachability'
spec.authors = { 'Tony Million' => 'tonymillion@gmail.com' }
spec.summary = 'ARC and GCD Compatible Reachability Class for iOS and OS X.'
spec.source = { :git => 'https://github.com/tonymillion/Reachability.git', :tag => 'v3.1.0' }
spec.source_files = 'Reachability.{h,m}'
spec.framework = 'SystemConfiguration'
end
或者更详细一些:
Pod::Spec.new do |spec|
spec.name = 'Reachability'
spec.version = '3.1.0'
spec.license = { :type => 'BSD' }
spec.homepage = 'https://github.com/tonymillion/Reachability'
spec.authors = { 'Tony Million' => 'tonymillion@gmail.com' }
spec.summary = 'ARC and GCD Compatible Reachability Class for iOS and OS X.'
spec.source = { :git => 'https://github.com/tonymillion/Reachability.git', :tag => 'v3.1.0' }
spec.module_name = 'Rich'
spec.swift_version = '4.0'
spec.ios.deployment_target = '9.0'
spec.osx.deployment_target = '10.10'
spec.source_files = 'Reachability/common/*.swift'
spec.ios.source_files = 'Reachability/ios/*.swift', 'Reachability/extensions/*.swift'
spec.osx.source_files = 'Reachability/osx/*.swift'
spec.framework = 'SystemConfiguration'
spec.ios.framework = 'UIKit'
spec.osx.framework = 'AppKit'
spec.dependency 'SomeOtherPod'
end
约定优于配置(convention over configuration),也称为按约定编程,是一种软件设计范式,旨在减少软件开发人脸需要做决定的数量,获得简单的好处,而又不失灵活性。
4.2 Root specification (根规范)
- “根”规范存储有关库的特定版本的信息。
- 此组中的属性只能写入“根”规范,而不能写入“子规范”。
- 此组中列出的属性是podspec所需的唯一属性。
4.2.1 name(名字)
必须设置! pod的名字。
spec.name = 'AFNetworking'
4.2.2 version(版本)
必须设置! pod的版本。CocoaPods遵循语义版本控制。
spec.version = '0.0.1'
4.2.3 swift_versions(swift版本)
规范支持的Swift版本。“4”的版本将被CocoaPods视为“4.0”,而不是“4.1”或“4.2”。
请注意,Swift编译器主要接受高级版本,有时也支持低级版本。虽然CocoaPods允许指定低级版本或修补程序版本,但Swift编译器可能不会完全遵循它。
spec.swift_versions = ['3.0']
or
spec.swift_versions = ['3.0', '4.0', '4.2']
or
spec.swift_version = '3.0'
or
spec.swift_version = '3.0', '4.0'
4.2.4 cocoapods_version(cocoapods版本)
规范支持的CocoaPods版本。
spec.cocoapods_version = '>= 1.11.2'
4.2.5 authors(作者)
必须设置! 库维护人员的姓名和电子邮件地址,而不是Podspec维护人员的姓名和电子邮件地址。
spec.author = 'Darth Vader'
or
spec.authors = 'Darth Vader', 'Wookiee'
or
spec.authors = { 'Darth Vader' => 'darthvader@darkside.com',
'Wookiee' => 'wookiee@aggrrttaaggrrt.com' }
4.2.6 social_media_url
pod的社交媒体联系人的URL,CocoaPods web 服务可以使用这个。
spec.social_media_url = '你的博客地址'
4.2.7 license(许可证)
如果指定了许可证文件,则它必须没有文件扩展名,或者是txt、md或markdown之一。
CocoaPods使用此信息生成确认文件(markdown和plit),这些文件可用于最终应用程序的确认部分。
spec.license = 'MIT'
or
spec.license = { :type => 'MIT', :file => 'MIT-LICENSE.txt' }
or
spec.license = { :type => 'MIT', :text => <<-LICENSE
Copyright 2012
Permission is granted to...
LICENSE
}
4.2.8 homepage(主页)
必须设置! pod主页的URL
spec.homepage = 'http://www.example.com'
4.2.9 source(代码地址)
必须设置! 可以从中检索库的位置。
-
指定带有标签(tag)的git源。这就是大多数OSS podspec的工作原理。
spec.source = { :git => 'https://github.com/AFNetworking/AFNetworking.git', :tag => spec.version.to_s }
-
使用前缀为“v”和子模块的标签(tag)。
spec.source = { :git => 'https://github.com/typhoon-framework/Typhoon.git', :tag => "v#{spec.version}", :submodules => true }
-
使用带标签(tag)的Subversion.
spec.source = { :svn => 'http://svn.code.sf.net/p/polyclipping/code', :tag => spec.version.to_s }
-
使用与规范的语义版本字符串具有相同版本的Mercurial。
spec.source = { :hg => 'https://bitbucket.org/dcutting/hyperbek', :revision => "#{s.version}" }
-
使用HTTP下载压缩文件的代码。它支持zip、tgz、bz2、txz和tar。
spec.source = { :http => 'http://dev.wechatapp.com/download/sdk/WeChat_SDK_iOS_en.zip' }
-
使用HTTP下载文件,使用哈希验证下载。它支持sha1和sha256。
spec.source = { :http => 'http://dev.wechatapp.com/download/sdk/WeChat_SDK_iOS_en.zip', :sha1 => '7e21857fe11a511f472cfd7cfa2d979bd7ab7d96' }
-
支持Keys:
:git => :tag, :branch, :commit, :submodules
:svn => :folder, :tag, :revision
:hg => :revision
:http => :flatten, :type, :sha256, :sha1, :headers
4.2.10 summary(总结)
必须设置! 对pod的简短描述(最多140个字符)。
摘要应该简短,但内容丰富。它代表pod的标签,无需指定它是一个库(虽然它是),该摘要首字母应大写并包含正确的标点符号。
spec.summary = 'Computes the meaning of life.'
4.2.11 description(详细描述)
对Pod的描述比摘要更详细
spec.description = <<-DESC
Computes the meaning of life.
Features:
1. Is self aware
...
42. Likes candies.
DESC
4.2.12 screenshots(截图)
显示pod图片的url列表。面向用户界面的库。CocoaPods建议使用gif格式.
spec.screenshot = 'http://dl.dropbox.com/u/378729/MBProgressHUD/1.png'
or
spec.screenshots = [ 'http://dl.dropbox.com/u/378729/MBProgressHUD/1.png',
'http://dl.dropbox.com/u/378729/MBProgressHUD/2.png' ]
4.2.13 documentation_url(文档地址)
CocaoPods web properties 将提供pod文档的可选URL。将其留空将默认为库的cocoadocs生成的URL。
spec.documentation_url = 'http://www.example.com/docs.html'
4.2.14 prepare_command(命令)
下载Pod后将执行bash脚本。此命令可用于创建、删除和修改下载的任何文件,并将在收集规范的其他文件属性的任何路径之前运行。
此命令在清理Pod和创建Pod项目之前运行。工作目录是Pod的根目录。
如果pod设置了:path选项,则不会执行此命令。
spec.prepare_command = 'ruby build_files.rb'
or
spec.prepare_command = <<-CMD
sed -i 's/MyNameSpacedHeader/Header/g' ./**/*.h
sed -i 's/MyNameOtherSpacedHeader/OtherHeader/g' ./**/*.h
CMD
4.2.15 static_framework(静态库)
代表,如果使用use_frameworks!指定时,pod应包含静态库框架。
spec.static_framework = true
4.2.16 deprecated(弃用)
是否已弃用该库。
spec.deprecated = true
4.2.17 deprecated_in_favor_of(不赞成)
不赞成使用的Pod的名称。
spec.deprecated_in_favor_of = 'NewMoreAwesomePod'
4.2.18 readme
自描文件,markdown文件格式
spec.readme = 'https://www.example.com/Pod-1.5-README.md'
4.2.19 changelog
更新日志文件,markdown文件格式
spec.changelog = 'https://www.example.com/Pod-1.5-CHANGELOG.md'
4.3 Platform(平台)
主要是指明支持当前库的平台和相应的部署target。
4.3.1 Platform
spec.platform = :osx, '10.8'
spec.platform = :ios
spec.platform = :osx
支持此Pod的平台。保留此空白表示Pod在所有平台上都支持。当支持多个平台时,应改为使用以下deployment_target。
4.3.2 deployment_target
spec.ios.deployment_target = '6.0'
spec.osx.deployment_target = '10.8'
支持平台的最低部署target。 与platform属性相反,deployment_target 属性允许指定支持该Pod的多个平台-为每个平台指定不同的部署目标。
4.4 Build settings(构建配置)
构建环境的配置相关设置
4.4.1 dependency(依赖)
spec.dependency 'AFNetworking', '~> 1.0'
spec.dependency 'AFNetworking', '~> 1.0', :configurations => ['Debug']
spec.dependency 'AFNetworking', '~> 1.0', :configurations => :debug
spec.dependency 'RestKit/CoreData', '~> 0.20.0'
spec.ios.dependency 'MBProgressHUD', '~> 0.5'
对其他Pod或“sub-spec”的依赖。依赖关系可以指定版本要求。
4.4.2 info_plist
spec.info_plist = {
'CFBundleIdentifier' => 'com.myorg.MyLib',
'MY_VAR' => 'SOME_VALUE'
}
添加到生成的键值对Info.plist。
这些值将与CocoaPods生成的默认值合并,从而覆盖所有重复项。
对于库规范,值将合并到为使用框架集成的库生成的Info.plist中。它对静态库无效。
4.4.3 requires_arc
# 默认
spec.requires_arc = true
# 设置
spec.requires_arc = false
spec.requires_arc = 'Classes/Arc'
spec.requires_arc = ['Classes/*ARC.m', 'Classes/ARC.mm']
允许您指定使用ARC的source_files。它可以是支持ARC的文件,也可以是true,以表示所有source_files都使用ARC。
不使用ARC的文件将带有-fno-objc-arc编译器标志。
此属性的默认值为true。
4.4.4 frameworks
spec.ios.framework = 'CFNetwork'
spec.frameworks = 'QuartzCore', 'CoreData'
当前target所需系统framework列表
4.4.5 weak_frameworks
如果在高版本的OS中调用新增的功能,还要保持低版本OS能够运行,就要使用weak_framwoks如果引用的某些类或者接口在低版本中并不支持,可以再运行时判断。
spec.weak_framework = 'Twitter'
spec.weak_frameworks = 'Twitter', 'SafariServices'
当前target所需“弱引用”的framework列表
4.4.6 libraries
spec.ios.library = 'xml2'
spec.libraries = 'xml2', 'z'
当前target所需系统library列表
4.4.7 compiler_flags
spec.compiler_flags = '-DOS_OBJECT_USE_OBJC=0', '-Wno-format'
传递给编译器的flag
4.4.8 pod_target_xcconfig
flag添加到私有库的target Xcconfig文件中,只会配置当前私有库
spec.pod_target_xcconfig = { 'OTHER_LDFLAGS' => '-lObjC' }
不推荐使用
4.4.9 user_target_xcconfig
指定要添加到最终聚合目标xcconfig文件的标志,该文件将非重写并将生成设置继承到集成用户目标。
spec.user_target_xcconfig = { 'MY_SUBSPEC' => 'YES' }
4.4.10 prefix_header_contents
要注入到pod项目前缀头中的任何内容。
不建议使用此属性,因为Pods不应该污染其他库或用户项目的前缀头。
spec.prefix_header_contents = '#import <UIKit/UIKit.h>'
spec.prefix_header_contents = '#import <UIKit/UIKit.h>', '#import <Foundation/Foundation.h>'
4.4.11 prefix_header_file
要注入pod项目前缀头的前缀头文件的路径。false表示不应生成默认CocoaPods前缀头。true是默认值,指示应生成默认CocoaPods前缀头。
不建议使用文件路径选项,因为Pods不应污染其他库或用户项目的前缀头。
spec.prefix_header_file = 'iphone/include/prefix.pch'
spec.prefix_header_file = false
4.4.12 module_name
将为此规范而不是默认规范生成的framework/clang模块使用的名称(如果设置了header_dir,则为规范名称)。
spec.module_name = 'Three20'
4.4.13 header_dir
头文件的存储目录。
头文件的存储目录。
4.4.14 header_mappings_dir
用于保留头文件的文件夹结构的目录。如果未提供,则将头文件展平。
spec.header_mappings_dir = 'src/include'
4.4.15 script_phases
spec.script_phase = { :name => 'Hello World', :script => 'echo "Hello World"' }
spec.script_phase = { :name => 'Hello World', :script => 'echo "Hello World"', :execution_position => :before_compile }
spec.script_phase = { :name => 'Hello World', :script => 'puts "Hello World"', :shell_path => '/usr/bin/ruby' }
spec.script_phase = { :name => 'Hello World', :script => 'echo "Hello World"',
:input_files => ['/path/to/input_file.txt'], :output_files => ['/path/to/output_file.txt']
}
spec.script_phase = { :name => 'Hello World', :script => 'echo "Hello World"',
:input_file_lists => ['/path/to/input_files.xcfilelist'], :output_file_lists => ['/path/to/output_files.xcfilelist']
}
spec.script_phases = [
{ :name => 'Hello World', :script => 'echo "Hello World"' },
{ :name => 'Hello Ruby World', :script => 'puts "Hello World"', :shell_path => '/usr/bin/ruby' },
]
此属性允许定义脚本,以作为Pod编译的一部分执行。与prepare命令不同,脚本作为xcodebuild的一部分执行,也可以利用在编译期间设置的所有环境变量。
Pod可以提供要执行的多个脚本,并且将按照声明的顺序添加它们,并考虑它们的执行位置设置。
注意: 为了提供对所有脚本内容的可见性和意识,如果安装了Pod包含任何脚本,则会在安装时向用户显示警告。
4.5 File patterns
Pattern: * * 匹配所有文件 c* 匹配以c开头的文件 *c 匹配以c结尾的文件 c匹配包含c的文件
Pattern: ** 目录递归地匹配
Pattern: ? 匹配任意一个字符。相当于 正则表达式中的/.{1}/。
Pattern: [set] 匹配集合中的任意一个字符。 行为与正则表达式中的字符集完全一样,包括反集([^a-z])。
Pattern: {p,q} 匹配字面值p或字面值q。等价于正则表达式中的模式变换。
Pattern: \ 转义下一个元字符。
"JSONKit.?" #=> ["JSONKit.h", "JSONKit.m"]
"*.[a-z][a-z]" #=> ["CHANGELOG.md", "README.md"]
"*.[^m]*" #=> ["JSONKit.h"]
"*.{h,m}" #=> ["JSONKit.h", "JSONKit.m"]
"*" #=> ["CHANGELOG.md", "JSONKit.h", "JSONKit.m", "README.md"]
4.5.1 source_files
spec.source_files = 'Classes/**/*.{h,m}'
spec.source_files = 'Classes/**/*.{h,m}', 'More_Classes/**/*.{h,m}'
需要包含的源文件
4.5.2 public_header_files
spec.public_header_files = 'Classes/**/*.h'
用作公共头的文件模式列表。 这些模式与源文件匹配,以包含将公开给用户项目并从中生成文档的标头。构建库时,这些头将出现在构建目录中。如果未指定公共头,则将source_files中的所有头视为公共。
4.5.3 private_header_files
spec.private_header_files = 'Classes/**/*.h'
用来标记私有文件模式列表。 这些模式与公共标头(如果未指定公共标头,则与所有标头)匹配,以排除那些不应暴露给用户项目并且不应用于生成文档的标头。构建库时,这些头将出现在构建目录中。 没有列出为公共和私有的头文件将被视为私有,但除此之外根本不会出现在构建目录中。
4.5.4 vendored_frameworks
spec.ios.vendored_frameworks = 'Frameworks/MyFramework.framework'
spec.vendored_frameworks = 'MyFramework.framework', 'TheirFramework.framework'
源文件相关联的framework
4.5.5 vendored_libraries
spec.ios.vendored_library = 'Libraries/libProj4.a'
spec.vendored_libraries = 'libProj4.a', 'libJavaScriptCore.a'
源文件相关联的libraries
4.5.6 resource_bundles
spec.ios.resource_bundle = { 'MapBox' => 'MapView/Map/Resources/*.png' }
spec.resource_bundles = {
'MapBox' => ['MapView/Map/Resources/*.png'],
'MapBoxOtherResources' => ['MapView/Map/OtherResources/*.png']
}
为了将Pod构建为静态库,官方强烈建议使用此属性来管理资源文件,因为使用resources属性可能会发生名称冲突。
资源文件bundle的名称至少应包括Pod的名称,以最大程度地减少名称冲突的可能性。
4.5.7 resources
spec.resource = 'Resources/HockeySDK.bundle'
spec.resources = ['Images/*.png', 'Sounds/*']
复制到target中的资源列表。
为了将Pod构建为静态库,官方建议是使用resource_bundle,因为使用resources属性可能会发生名称冲突。此外,使用此属性指定的资源将直接复制到客户端目标,因此Xcode不会对其进行优化。
关于资源打包可以参考iOS组件化之pod加载资源文件
4.5.8 exclude_files
spec.ios.exclude_files = 'Classes/osx'
spec.exclude_files = 'Classes/**/unused.{h,m}'
从其他文件模式中排除的文件模式列表。
比如在设置某个子模块的时候,不需要包括其中的一些文件,就可以通过这个属性来进行设置。
4.5.9 preserve_path
spec.preserve_path = 'IMPORTANT.txt'
spec.preserve_paths = 'Frameworks/*.framework'
任何被下载的文件之后是不会被移除。
默认情况下,CocoaPods会移除所有与其他任何文件模式都不匹配的文件。
4.5.10 module_map
spec.module_map = 'source/module.modulemap'
将此Pod集成为框架时应使用的模块映射文件。
默认情况下,CocoaPods基于规范中的公共头创建模块映射文件。
4.5.11 project_header_files
作为项目头的文件模式列表。
这些文件模式将与public headers进行匹配,以排除那些不应公开给用户项目和不应用于生成文档的headers。当构建库时,这些头文件将不会出现在构建目录中。
spec.project_header_files = 'ttPodfile/Classes/*.h'
4.5.12 on_demand_resources
简单来说,“按需资源” 允许开发人员通过按需下载资产,而不是预先全部下载,来实现交付更小的 App 包。
应复制到目标target中的随需应变资源的哈希值。这里指定的资源将自动成为集成此pod的target的资源构建阶段的一部分。
由pods指定的tag是由CocoaPods管理的。如果一个标签被重命名、更改或删除,那么CocoaPods也会在工程target中进行更新。
在 1.11 中,pod 作者可以指定一组资源作为给定应用程序的按需资源集合。
如果category没有指定,默认是 :download_on_demand
s.on_demand_resources = {
'Tag1' => 'file1.png'
}
s.on_demand_resources = {
'Tag1' => ['file1.png', 'file2.png']
}
s.on_demand_resources = {
'Tag1' => { :paths => ['file1.png', 'file2.png'], :category => :download_on_demand }
}
s.on_demand_resources = {
'Tag1' => { :paths => ['file1.png', 'file2.png'], :category => :initial_install }
}
4.6 Subspecs
库可以指定对另一个库、另一个库的子库或其自身的子库的依赖关系。
4.6.1 subspec
表示库模块的规范。
子空间参与双重层次。
一方面,规范自动继承所有它的子“子规范”(除非指定了默认子规范)作为依赖项。
另一方面,“子规范”继承父级属性的值,以便可以在祖先中指定属性的公共值。
虽然在实践中听起来很复杂,但这意味着子空间通常会做您所期望的事情:
pod 'ShareKit', '2.0'
将ShareKit与ShareKit/Evernote、ShareKit/Facebook等所有共享者一起安装,因为它们被定义为子空间。
pod 'ShareKit/Twitter', '2.0'
pod 'ShareKit/Pinboard', '2.0'
仅使用ShareKit/Twitter、ShareKit/Pinboard的源文件安装ShareKit。注意,在这种情况下,要编译的“子规范”需要源文件、依赖项和根规范定义的其他属性。CocoaPods足够聪明,可以处理由重复属性引起的任何问题。
带有不同源文件的子规范。
subspec 'Twitter' do |sp|
sp.source_files = 'Classes/Twitter'
end
subspec 'Pinboard' do |sp|
sp.source_files = 'Classes/Pinboard'
end
子空间引用对其他子空间的依赖关系。
Pod::Spec.new do |s|
s.name = 'RestKit'
s.subspec 'Core' do |cs|
cs.dependency 'RestKit/ObjectMapping'
cs.dependency 'RestKit/Network'
cs.dependency 'RestKit/CoreData'
end
s.subspec 'ObjectMapping' do |os|
end
end
嵌套subspecs。
Pod::Spec.new do |s|
s.name = 'Root'
s.subspec 'Level_1' do |sp|
sp.subspec 'Level_2' do |ssp|
end
end
end
4.6.2 requires_app_host
测试规范是否要求应用程序主机运行测试。这仅适用于测试规范。
s.requires_app_host = true
4.6.3 app_host_name
必要时用作应用程序宿主的应用程序规范。
4.6.4 scheme
CocoaPods 在 1.7 版中首次引入了配置为 Podspecs 生成的 Xcode 方案的功能。此版本通过在 scheme DSL 中指定 code_coverage 选项,增加了对启用代码覆盖率的支持:
spec.scheme = { :launch_arguments => ['Arg1'] }
spec.scheme = { :launch_arguments => ['Arg1', 'Arg2'], :environment_variables => { 'Key1' => 'Val1'}, :code_coverage => true }
支持的Keys:
:launch_arguments
:environment_variables
:code_coverage
Pod::Spec.new do |s|
s.name = 'Networking'
s.version = '1.0.0'
# ...rest of attributes here
s.test_spec 'Tests' do |test_spec|
test_spec.scheme = {
:code_coverage => true, :environment_variables => {'FOO' => 'BAR' }
}
end
end
4.6.5 test_spec
表示库的测试规范。在这里,您可以放置podspec的所有测试以及测试依赖项。test spec 已成为 CocoaPods 的一个组成部分,并添加了一些新功能。
UI Test Bundle 支持
现在可以支持“UI Test Bundles”,您现在可以指定要用于给定 test_spec 的 test_type。默认值为 :unit,用于创建单元测试包。来看看我们常用的 pod CannonPodder 的示例:
Pod::Spec.new do |s|
s.name = 'CannonPodder'
s.version = '1.0.0'
# ...rest of attributes here
s.test_spec 'UITests' do |test_spec|
test_spec.requires_app_host = true
test_spec.test_type = :ui
test_spec.source_files = 'UITests/**/*.swift'
end
end
这将在安装时集成了 CannonPodder-UI-UITests UI 测试包,并将自动创建要用于它的 app host。
注意:UI test bundles 需要 app host 才能运行,因此如果您选择将 test spec 集成为 UI test bundle,则必须始终指定 requires_app_host。
对于大多数情况,为 test spec 生成的 app host 应可以在其中执行测试。但是,有些情况下 pod 作者可能希望进一步自定义用于 test_spec 的 app host。
例如,pod 作者可能希望为其 app host 或资源包指定其他依赖项,以便在测试期间使用。app spec 是一个很好的候选者,因为它们提供了大多数脚手架,而现在在 1.8 中,可以通过 app_host_name DSL 将 app_spec 设置为 test_spec 的 app host。
以下是一个例子:
Pod::Spec.new do |s|
s.name = 'CannonPodder'
s.version = '1.0.0'
# ...rest of attributes here
s.app_spec 'DemoApp' do |app_spec|
app_spec.source_files = 'DemoApp/**/*.swift'
# Dependency used only by this app spec.
app_spec.dependency 'Alamofire'
end
s.test_spec 'Tests' do |test_spec|
test_spec.requires_app_host = true
# Use 'DemoApp' as the app host.
test_spec.app_host_name = 'CannonPodder/DemoApp'
# ...rest of attributes here
# This is required since 'DemoApp' is specified as the app host.
test_spec.dependency 'CannonPodder/DemoApp'
end
end
在你的Podfile你可以带来这样的测试规范:
target 'MyApp' do
use_frameworks!
pod 'CoconutLib', '~> 1.0', :testspecs => ['Tests']
end
4.6.6 app_spec
表示库的应用程序规范。在这里,你可以放置你的podspec的所有应用源文件以及应用依赖项。对于大多数情况,为 test spec 生成的 app host 应可以在其中执行测试。但是,有些情况下 pod 作者可能希望进一步自定义用于 test_spec 的 app host。
例如,pod 作者可能希望为其 app host 或资源包指定其他依赖项,以便在测试期间使用。app spec 是一个很好的候选者,因为它们提供了大多数脚手架,而现在在 1.8 中,可以通过 app_host_name DSL 将 app_spec 设置为 test_spec 的 app host。
以下是一个例子:
Pod::Spec.new do |spec|
spec.name = 'NSAttributedString+CCLFormat'
spec.app_spec do |app_spec|
app_spec.source_files = 'NSAttributedString+CCLFormat.m'
app_spec.dependency 'AFNetworking'
end
end
Pod::Spec.new do |s|
s.name = 'CannonPodder'
s.version = '1.0.0'
# ...rest of attributes here
s.app_spec 'DemoApp' do |app_spec|
app_spec.source_files = 'DemoApp/**/*.swift'
# Dependency used only by this app spec.
app_spec.dependency 'Alamofire'
end
s.test_spec 'Tests' do |test_spec|
test_spec.requires_app_host = true
# Use 'DemoApp' as the app host.
test_spec.app_host_name = 'CannonPodder/DemoApp'
# ...rest of attributes here
# This is required since 'DemoApp' is specified as the app host.
test_spec.dependency 'CannonPodder/DemoApp'
end
end
这将产生以下结果:
这一强大的新功能为 pod 作者提供了新的可能性,以用于对 test spec 的 app host 进行更精细的控制。
4.6.7 default_subspecs
应该用作首选依赖项的子依赖名称数组。如果未指定,则规范要求其所有子依赖作为依赖项。您可以使用值:none来指定编译此pod不需要任何子依赖,并且所有子依赖都是可选的。定义了一个二级的依赖。意思就是说,一级pod在引入的时候执行"pod ‘AFNetwork’", 定义了二级依赖之后就可以这个样写了"AFNetwork/Core"。
spec.default_subspec = 'Core'
or
spec.default_subspecs = 'Core', 'UI'
or
spec.default_subspecs = :none
4.7 Multi-Platform support (多平台支持)
规范可以存储仅特定于一个平台的值。
例如,可能需要存储仅特定于iOS项目的资源。
spec.resources = 'Resources/**/*.png'
spec.ios.resources = 'Resources_ios/**/*.png'
4.7.1 iOS
提供指定iOS属性的支持。
spec.ios.source_files = 'Classes/ios/**/*.{h,m}'
4.7.2 osx
提供对指定OSX属性的支持。
spec.osx.source_files = 'Classes/osx/**/*.{h,m}'
4.7.3 macos
提供对指定OSX属性的支持。
spec.osx.source_files = 'Classes/osx/**/*.{h,m}'
4.7.4 tvos
提供指定tvOS属性的支持。
spec.tvos.source_files = 'Classes/tvos/**/*.{h,m}'
4.7.5 watchos
提供指定watchOS属性的支持。
spec.watchos.source_files = 'Classes/watchos/**/*.{h,m}'
5、自定义仓库
5.1 创建pod库并发布到远程仓库
- 创建pod库
$ pod lib create XMTest
按照提示创建pod库
- 修改代码后提交,并打tag
$ git add .
$ git commit -m "feat: xx"
$ git push origin master
$ git tag 0.1.0
$ git push origin 0.1.0
- 查看个人信息用于验证是否可以发布
$ pod trunk me
如何显示如下信息则表示还没有注册个人信息
[!] Authentication token is invalid or unverified. Either verify it with the email that was sent or register a new session.
- 注册个人信息
$ pod trunk register name.user@xxxx.com peng --description='hello'
再次运行命令
$ pod trunk me
打印如下信息,说明注册成功:
- Name: name
- Email: name.user@xxxx.com
- Since: March 7th, 03:29
- Pods: None
- Sessions:
- March 7th, 03:29 - July 13th, 03:32. IP: 94.177.118.99 Description: hello
- 验证podspec文件是否有效
$ pod lib lint XMTest.podspec --allow-warnings
or
$ pod spec lint XMTest.podspec --allow-warnings
- 发布pod库到远程仓库
$ pod trunk push XMTest.podspec --allow-warnings
输出错误日志,愿意是这个库名已经被人使用了,我们可以修改库名:
[!] You (name.user@xxxx.com) are not allowed to push new versions for this pod. The owners of this pod are 1179102890@qq.com.
- 修改podspec里面pod库的名字为XMLYTest和版本号
- 修改podspec文件名为XMLYTest.podspec
- pod install
- 验证podspec文件
- 提交代码,打tag
- 重新提交
$ pod trunk push XMLYTest.podspec --allow-warnings
- 发布成功
Updating spec repo `trunk`
Validating podspec
-> XMLYTest (0.2.0)
- WARN | summary: The summary is not meaningful.
- NOTE | xcodebuild: note: Using new build system
- NOTE | xcodebuild: note: Using codesigning identity override: -
- NOTE | xcodebuild: note: Build preparation complete
- NOTE | [iOS] xcodebuild: note: Planning
- NOTE | [iOS] xcodebuild: note: Building targets in dependency order
Updating spec repo `trunk`
--------------------------------------------------------------------------------
🎉 Congrats
🚀 XMLYTest (0.2.0) successfully published
📅 March 7th, 03:56
🌎 https://cocoapods.org/pods/XMLYTest
👍 Tell your friends!
--------------------------------------------------------------------------------
并会发送给注册的邮箱通知结果。
- 搜索发布的库
$ pod repo update
$ pod search XMLYTest
如果搜索不到库
$ pod ipc update-search-index
打印了缓存文件等路径search_index.json,可以删除此文件重新搜索,打印如下信息,说明发布成功:
-> XMLYTest (0.2.0)
A short description of XMTest.
pod 'XMLYTest', '~> 0.2.0'
- Homepage: https://github.com/xxxx/XMTest
- Source: https://github.com/xxxx/XMTest.git
- Versions: 0.2.0 [master repo]
至此发布库结束
5.2 搭建私有仓库
- 新建仓库
可以在一下平台建立仓库
- git仓库
- gitLab
- gitee
- gitHub
- 等等
我们以gitLab为例,来严重如何搭建私有仓库;
在gitLab上创建一个仓库,然后通过pod命令将仓库添加到本地, 我么命名为dcspecs,地址(git@gitlab.xxxx.com:username/dcspecs.git)
$ pod repo add xxxx git@gitlab.xxxx.com:username/dcspecs.git
展示本地已经添加成功的仓库:
$ pod repo list
- 自定义私有库创建模版
之前使用命令创建的pod库
$ pod lib create XMLYTest
默认使用的是官方提供的库模版,我们可以通过后面指定自定义的模版进行创建pod库,官方的模版是开源的,我们可以将官方的源码下载后做一些自定义的操作。可以在github上下载pod-template查看,地址(github.com/CocoaPods/p…
我们修改模版一些自定义的配置然后上传到gitLab上提供给自己使用,仓库地址为git@gitlab.xxxx.com:username/pod-template.git。
--template-url=URL可以指定自定义的模板,URL就是模板的地址
$ pod lib create testlib --template-url="git@gitlab.xxxx.com:username/pod-template.git"
5.3 发布pod库到私有仓库
发布pod库到私有仓库和上面发布pod库到远程仓库的步骤基本上是一样的,大概的步骤如下:
- 使用命令和自定义模版创建私有库
- 修改代码,提交代码,打tag
- 使用命令验证podspec文件是否合法,不合法发布会失败
- 推送到原创仓库,这里使用的是pod repo push 命令 和上面的 pod trunk命令稍有不同
$ pod repo push xxxx testlib.podspec --verbose --allow-warnings
注意:如果私有库中使用了静态库,需要添加选项 --use-libraries
5.4 脚本配置和发布pod库到私有仓库
上面创建私有库和维护私有库,发布私有库的步骤比较繁琐,我们可以通过脚步,将步骤精简
- 自动生成pod工程
#!/bin/sh
# 自动生成pod工程
# 执行方式 sh PodPrjectMaker.sh 工程名
projectName="$1"
if [ "${projectName}" == "" ]; then
echo "工程名未命名"
exit
fi
pod lib create ${projectName} --template-url="git@gitlab.xxxx.com:username/pod-template.git"
#进入目录同步服务器数据
cd ${projectName}
#echo "4.0" > .swift-version
cd Example
pod install
open ${projectName}.xcworkspace
- 将库文件提交到git服务器
#!/bin/sh
# 将库文件提交到git服务器
# 执行方式 sh PodAddRemoteOrigin.sh 工程名 提交信息
repoName="$1"
commit="$2"
if [ "${repoName}" == "" ]; then
echo "输入工程名"
exit
fi
#if [ "${origin}" == "" ]; then
# echo "输入远程仓库地址"
# exit
#fi
cd ${repoName}
git add .
git commit -m "${commit}"
git remote add origin "git@gitlab.xxxx.com:username/${repoName}.git"
git push -u origin master
- 将库推送到远程仓库
#!/bin/sh
# 将库文件发布到索引仓库
# 执行方式 sh PodPushShell.sh 工程名 标签号
repoName="$1"
tag="$2"
if [ "${repoName}" == "" ]; then
echo "工程名为空"
exit
fi
if [ "${tag}" == "" ]; then
echo "标签号为空"
exit
fi
cd ${repoName}
git tag -a ${tag} -m "${tag}"
git push --tags
#pod spec lint ${repoName}.podspec
pod repo push xxxx ${repoName}.podspec --verbose --allow-warnings
#pod repo push xxxx ${repoName}.podspec --verbose --allow-warnings --use-libraries
6、Cocoapods插件开发
6.1 插件开发准备
6.1.1 rvm
RVM 能在系统中安装和管理多个 Ruby 版本。同时还能管理不同的 gem 集。支持 OS X、Linux 和其它类 UNIX 操作系统。
- 安装 RVM
$ curl -sSL https://get.rvm.io | bash -s stable
安装完成后,会列出一些安装信息,其中有一行要注意:
* To start using RVM you need to run `source /Users/xmly/.rvm/scripts/rvm`
in all your open shell windows, in rare cases you need to reopen all shell windows.
$ source /Users/xmly/.rvm/scripts/rvm
检查一下是否安装正确
$ rvm -v
打印
rvm 1.29.12 (latest) by Michal Papis, Piotr Kuczynski, Wayne E. Seguin [https://rvm.io]
6.1.2 ruby
Ruby 是一种开源的面向对象程序设计的服务器端脚本语言,在 20 世纪 90 年代中期由日本的松本行弘(まつもとゆきひろ/Yukihiro Matsumoto)设计并开发。在 Ruby 社区,松本也被称为马茨(Matz)。Ruby 可运行于多种平台,如 Windows、MAC OS 和 UNIX 的各种版本。Mac 自带 ruby。
6.1.3 gem
gem是管理这些基于ruby程序的程序,Mac 自带 gem,可以使用gem安装Cocoapods等ruby工具包。
比如安装源增删改查,工具包的安装卸载。
$ gem source -l
$ gem source -a "https://gems.ruby-china.org"
$ gem source -r "https://gems.ruby-china.org"
注意:使用如下源可用 rubygems.org/
6.1.4 bundler
Bundler使用Ruby语言写的,通过跟踪和安装运行Ruby项目所需要的确切的gem和版本,为Ruby项目提供了完整的可运行环境。上面介绍过
安装bundler
$ sudo gem install bundler
6.1.5 Rake
Rake 是用 Ruby 编写的,并使用 Ruby 作为它的语法,因此学习曲线很短。Rake 使用 Ruby 的元编程功能来扩展语言,使之更利落地适应自动化任务。
6.2 插件开发
运行下面的命令就可以生成一个插件模板工程
$ pod plugins create module
创建了cocoapods-gmodule工程
-> Creating `cocoapods-module` plugin
[!] using template 'https://github.com/CocoaPods/cocoapods-plugin-template.git'
-> Configuring template
Configuring cocoapods-module
user name:username
user email:name.user@xxxx.com
year:2022
hint: Using 'master' as the name for the initial branch. This default branch name
hint: is subject to change. To configure the initial branch name to use in all
hint: of your new repositories, which will suppress this warning, call:
hint:
hint: git config --global init.defaultBranch <name>
hint:
hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and
hint: 'development'. The just-created branch can be renamed via this command:
hint:
hint: git branch -m <name>
[!] Don't forget to create a Pull Request on https://github.com/CocoaPods/cocoapods-plugins
to add your plugin to the plugins.json file once it is released!
工程目录是这样的
├── Gemfile
├── LICENSE.txt
├── README.md
├── Rakefile
├── cocoapods-module.gemspec
├── lib
│ ├── cocoapods-module
│ │ ├── command
│ │ │ └── module.rb
│ │ ├── command.rb
│ │ └── gem_version.rb
│ ├── cocoapods-module.rb
│ └── cocoapods_plugin.rb
└── spec
├── command
│ └── module_spec.rb
└── spec_helper.rb
.gemspec文件是插件的主要配置文件。所有的spec字段都是自描述的(你可以查看我们的gemspec)
如果命令下有个多子选项文件,需要替换spec.files这一行 spec.files = Dir['lib/**/*.rb'] + %w( README.md LICENSE.txt )
Gemfile会包含所需的全部gem依赖。查看Bundle Doc 以获得更多信息 Rakefile包含测试所需要的引用,spec文件夹包含测试用例。有关Rake的更多信息,请访问官方Rake repo。 我们现在还不需要更改Gemfile和Rakefile,所以保持其原样。 lib是我们要使用的主文件夹。它包含构建.gem的所有ruby文件。 为了确保一切设置正确,运行下面的的命令:
$ gem build cocoapods-module.gemspec
你将看到'Successfully built RubyGem'的成功消息,同时Cocoapods-module-0.0.1.gem 也将会出现在目录之下
$ gem install Cocoapods-module-0.0.1.gem
显示已经安装的插件
$ pod plugins installed
移除插件
$ sudo gem uninstall Cocoapods-module
6.3 实现插件
6.3.1 安装依赖
$ bundle install
如果安装出错,更新ruby
$ rvm install 2.6.6
- 新加三个命令
- create 创建库和同步到仓库
- push 推送文件到服务器
- publish 推送库到私有仓库
文件目录如下:
├── Gemfile
├── LICENSE.txt
├── README.md
├── Rakefile
├── cocoapods-module.gemspec
├── lib
│ ├── cocoapods-module
│ │ ├── command
│ │ │ └── module.rb
│ │ │ └── module
│ │ │ └── create.rb
│ │ │ └── push.rb
│ │ │ └── publish.rb
│ │ ├── command.rb
│ │ └── gem_version.rb
│ ├── cocoapods-module.rb
│ └── cocoapods_plugin.rb
└── spec
├── command
│ └── module_spec.rb
│ └── module
│ └── create_spec.rb
│ └── push_spec.rb
│ └── publish_spec.rb
└── spec_helper.rb
6.4 插件调试
6.4.1 CocoaPods - 如何调试
- CocoaPods 源码
Cocoapods 的代码并不全都在 Cocoapods/Cocoapods 项目中,而是拆分为了多个 Repo。在 Cocoapods README 的最后,对这些项目进行了简述:
- CocoaPods-Plugins: Cocoapods 插件管理
cocoapods-plugins 插件管理功能,其中有 pod plugin 全套命令,支持对于 CocoaPods 插件的列表一览(list)、搜索(search)、创建(create)功能。 当然,上面还有很多组件这里就不一一介绍了。
- CocoaPods Core: 处理 space 与 podfile,比如 Podfile DSL 的定义就在这个项目中
CocoaPods-Core 用于 CocoaPods 中模板文件的解析,包括 Podfile、.podspec,以及所有的 .lock 文件中特殊的 YAML 文件。
- CocoaPods Downloader: 下载模块
Cocoapods-Downloader 是用于下载源码的小工具,它支持各种类型的版本管理工具,包括 HTTP / SVN / Git / Mercurial。它可以提供 tags、commites,revisions,branches 以及 zips 文件的下载和解压缩操作。
- Xcodeproj: 解析 .xcodeproj 文件解析
Xcodeproj 可通过 Ruby 来操作 Xcode 项目的创建和编辑等。可友好的支持 Xcode 项目的脚本管理和 libraries 构建,以及 Xcode 工作空间 (.xcworkspace) 和配置文件 .xcconfig 的管理。
- CLAide: 命令行参数解析器
CLAide 虽然是一个简单的命令行解释器,但它提供了功能齐全的命令行界面和 API。它不仅负责解析我们使用到的 Pods 命令,如:pod install, pod update 等,还可用于封装常用的一些脚本,将其打包成简单的命令行小工具。
- Molinillo: 依赖仲裁算法
Molinillo 是 CocoaPods 对于依赖仲裁算法的封装,它是一个具有前向检察的回溯算法。不仅在 Pods 中,Bundler 和 RubyGems 也是使用的这一套仲裁算法。
$ git clone https://github.com/CocoaPods/CocoaPods.git
CocoaPods/Gemfile 需要新增两个 debug 的依赖
# 用于debug的gem
gem "ruby-debug-ide"
gem "debase"
SKIP_UNRELEASED_VERSIONS = false
# Declares a dependency to the git repo of CocoaPods gem. This declaration is
# compatible with the local git repos feature of Bundler.
#
def cp_gem(name, repo_name, branch = 'master', path: false)
return gem name if SKIP_UNRELEASED_VERSIONS
opts = if path
{ :path => "../#{repo_name}" }
else
url = "https://github.com/CocoaPods/#{repo_name}.git"
{ :git => url, :branch => branch }
end
gem name, opts
end
source 'https://rubygems.org'
gemspec
group :development do
cp_gem 'claide', 'CLAide'
cp_gem 'cocoapods-core', 'Core'
cp_gem 'cocoapods-deintegrate', 'cocoapods-deintegrate'
cp_gem 'cocoapods-downloader', 'cocoapods-downloader'
cp_gem 'cocoapods-plugins', 'cocoapods-plugins'
cp_gem 'cocoapods-search', 'cocoapods-search'
cp_gem 'cocoapods-trunk', 'cocoapods-trunk'
cp_gem 'cocoapods-try', 'cocoapods-try'
cp_gem 'molinillo', 'Molinillo'
cp_gem 'nanaimo', 'Nanaimo'
cp_gem 'xcodeproj', 'Xcodeproj'
gem 'cocoapods-dependencies', '~> 1.0.beta.1'
gem 'activesupport', '> 5', '< 6' # Pinned < 6 because 6 requires Ruby 2.5.0
gem 'bacon', :git => 'https://github.com/leahneukirchen/bacon.git'
gem 'mocha', '< 1.5'
gem 'mocha-on-bacon'
gem 'netrc'
gem 'prettybacon'
gem 'typhoeus'
gem 'webmock'
# 用于debug的gem
gem "ruby-debug-ide"
gem "debase"
gem 'bigdecimal', '~> 1.3.0'
gem 'public_suffix'
gem 'ruby-graphviz', '< 1.2.5'
# Integration tests
gem 'diffy'
gem 'clintegracon', :git => 'https://github.com/mrackwitz/CLIntegracon.git'
# Code Quality
# Revert to released gem once https://github.com/segiddins/inch_by_inch/pull/5 lands and a new version is published
gem 'inch_by_inch', :git => 'https://github.com/CocoaPods/inch_by_inch.git', branch: 'loosen-dependency'
gem 'rubocop', '0.50.0'
gem 'simplecov', '< 0.18'
gem 'danger', '~> 5.3'
end
group :debugging do
gem 'cocoapods_debug'
gem 'rb-fsevent'
gem 'kicker'
gem 'awesome_print'
gem 'ruby-prof', :platforms => [:ruby]
end
在Cocoapods目录下执行命令安装依赖 因为我们是调试某个gem库,为了不影响我们已经安装的,安装依赖的时候,最好是安装到当前文件夹下的执行目录中去 ruby的依赖包管理工具bundle,会把依赖安装到./vender/bundle目录下
$ bundle config set --local path 'vendor/bundle'
$ bundle install
这个时候可以调试cocoapods。
- 断点时机
在 CocoaPods/examples 下面已经包含一些 Example 工程,可以直接用来进行调试。按运行的逻辑,首先是进入某个 Example,然后 pod install,所以步骤是:
pod 命令的入口大多在 CocoaPods/lib/cocoapods/command/ 目录下。比如 pod install 对应着 install.rb 中的 run 方法。
- VSCode 调试
安装ruby插件,重启VSCode
新增 launch.json,并写入 debug 配置:
{
"version": "0.2.0",
"configurations": [
{
"name": "AFNetworking",
"type": "Ruby",
"request": "launch",
"useBundler": true,
"showDebuggerOutput": true,
"cwd": "${workspaceRoot}/examples/AFNetworking Example",
"program": "${workspaceRoot}/bin/pod",
"args": ["install"]
}
]
}
- ${workspaceFolder}:表示.vscode文件夹所在的目录(.vscode/launch.json),
- cwd:表示执行命令所在的目录(这里表示我们的iOS示例工程)
- program:表示将要执行的命令
- args:命令对应的参数
- useBundler:使用bundle安装的ruby环境,相当于bundle exec
下面介绍RubyMine。
- RubyMine 调试
》Add Configurations -》新建Gem Command -》配置如下:
!!!然后点击调试按钮,记住不是运行按钮,否则无法进去断点。!!!
!!! - 遇到问题重启VSCode
如果运行报错,按下面方法解决
- open Terminal
- type open ~/.zshrc (or .profile if you don't use zsh)
- add export LC_ALL=en_US.UTF-8, and save the file
- go back to Terminal
- type source ~/.zshrc
- type locale
6.4.2 调试自己编写的插件
将自己开发的插件cocoapods-module拷贝到cocoapods目录 在Gemfile文件中添加本地开发的插件
# 需要调试的自己写的插件
gem 'cocoapods-module', path: './cocoapods-module'
SKIP_UNRELEASED_VERSIONS = false
# Declares a dependency to the git repo of CocoaPods gem. This declaration is
# compatible with the local git repos feature of Bundler.
#
def cp_gem(name, repo_name, branch = 'master', path: false)
return gem name if SKIP_UNRELEASED_VERSIONS
opts = if path
{ :path => "../#{repo_name}" }
else
url = "https://github.com/CocoaPods/#{repo_name}.git"
{ :git => url, :branch => branch }
end
gem name, opts
end
source 'https://rubygems.org'
gemspec
group :development do
cp_gem 'claide', 'CLAide'
cp_gem 'cocoapods-core', 'Core'
cp_gem 'cocoapods-deintegrate', 'cocoapods-deintegrate'
cp_gem 'cocoapods-downloader', 'cocoapods-downloader'
cp_gem 'cocoapods-plugins', 'cocoapods-plugins'
cp_gem 'cocoapods-search', 'cocoapods-search'
cp_gem 'cocoapods-trunk', 'cocoapods-trunk'
cp_gem 'cocoapods-try', 'cocoapods-try'
cp_gem 'molinillo', 'Molinillo'
cp_gem 'nanaimo', 'Nanaimo'
cp_gem 'xcodeproj', 'Xcodeproj'
gem 'cocoapods-dependencies', '~> 1.0.beta.1'
gem 'activesupport', '> 5', '< 6' # Pinned < 6 because 6 requires Ruby 2.5.0
gem 'bacon', :git => 'https://github.com/leahneukirchen/bacon.git'
gem 'mocha', '< 1.5'
gem 'mocha-on-bacon'
gem 'netrc'
gem 'prettybacon'
gem 'typhoeus'
gem 'webmock'
# 需要调试的自己写的插件
gem 'cocoapods-module', path: './cocoapods-module'
# 用于debug的gem
gem "ruby-debug-ide"
gem "debase"
gem 'bigdecimal', '~> 1.3.0'
gem 'public_suffix'
gem 'ruby-graphviz', '< 1.2.5'
# Integration tests
gem 'diffy'
gem 'clintegracon', :git => 'https://github.com/mrackwitz/CLIntegracon.git'
# Code Quality
# Revert to released gem once https://github.com/segiddins/inch_by_inch/pull/5 lands and a new version is published
gem 'inch_by_inch', :git => 'https://github.com/CocoaPods/inch_by_inch.git', branch: 'loosen-dependency'
gem 'rubocop', '0.50.0'
gem 'simplecov', '< 0.18'
gem 'danger', '~> 5.3'
end
group :debugging do
gem 'cocoapods_debug'
gem 'rb-fsevent'
gem 'kicker'
gem 'awesome_print'
gem 'ruby-prof', :platforms => [:ruby]
end
$ bundle install
修改launch.json文件,就可以调试插件代码了
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "AFNetworking",
"type": "Ruby",
"request": "launch",
"useBundler": true,
"showDebuggerOutput": true,
"cwd": "${workspaceRoot}/examples/AFNetworking Example",
"program": "${workspaceRoot}/bin/pod",
"args": ["module", "create"]
}
]
}
这样就可以调试 pod module create xx 命令
参考:
6.5 发布插件
如果你想让你的插件被列在官方cocoapods插件列表中,运行:
$ pod plugins publish
它将在cocoapods-plugins库中创建一个issue并要求将您的插件添加到官方列表中。为了加速这个过程,您可以fork cocoapods-plugins,将生成的json对象添加为plugins.json文件中plugins数组中的最后一个对象,并创建一个pull请求。