赞
踩
对于大多数软件开发团队来说,依赖管理工具必不可少,它能针对开源和私有依赖进行安装与管理,从而提升开发效率,降低维护成本。针对不同的语言与平台,其依赖管理工具也各有不同,例如 npm 管理 Javascript、Gradle 、Maven 管理 Jar 包、pip 管理 Python 包,Bundler、RubyGems 等等。本文聚焦于 iOS 方面,对 CocoaPods 的使用和部分原理进行阐述。
对于 iOSer 来说,CocoaPods 并不陌生,几乎所有的 iOS 工程都会有它的身影。CocoaPods 采用 Ruby 构建,它是 Swift 和 Objective-C Cocoa 项目的依赖管理工具。在 MacOS 上,推荐使用默认的 Ruby 进行安装 (以下操作均在 CocoaPods 1.10.1、Ruby 2.7.2 进行):
sudo gem install cocoapods
如果安装成功,便可以使用 pod 的相关命令了。针对一个简单的项目来说,只需三步便可引入其他的依赖:
创建 Podfile 文件( CocoaPods 提供了 pod init 命令创建)
对 Podfile 文件进行编写,添加依赖的库,版本等信息。
在命令行执行 pod install
命令
顺利的话,这时在项目目录下会出现以下文件:
pod install
时创建的 Podfile.lock 的副本,用于比较这两个文件。一般来说,Podfile.lock 会纳入版本控制管理,而 Pods 文件夹则不会纳入版本控制变更;这意味着 Podfile.lock 表示项目应该依赖的库版本信息,而 Manifest.lock 则代表本地 Pods 的依赖库版本信息。在 pod install 后会将脚本插入到 Build Phases,名为 [CP] Check Pods Manifest.lock
,从而保证开发者在运行 app 之前能够更新 Pods,以确保代码是最新的。pod install
:在每一次编辑 Podfile 以添加、更新或删除 pod 时使用。它会下载并安装新的 Pod,并将其版本信息写入 Podfile.lock 中。pod outdated
:列出所有比 Podfile.lock 中当前记录的版本 newer 版本的 pod。pod update [PODNAME]
:CocoaPods 会查找 newer 版本的 PODNAME,同时将 pod 更新到可能的最新版本(须符合 Podfile 限制)。若没有 PODNAME,则会将每一个 pod 更新到可能的最新版本。一般来说,每次编辑 Podfile 时使用 pod install
,仅在需要更新某个 pod 版本(所有版本)时才使用 pod update。同时,需提交 Podfile.lock 文件而不是 Pods 文件夹来达到同步所有 pod 版本的目的。
ps: newer 代表更加新的,若采用中文理解起来比较别扭。
Podfile 描述了一个或多个 Xcode 项目的 target 依赖关系,它是一种 DSL,了解它对我们使用好 CocoaPods 是一个必不可少的步骤。下面列出其相关的语法规范:
install!:指定 CocoaPods 安装 Podfile 时使用的安装方法和选项。如:
install! 'cocoapods',
:deterministic_uuids => false,
:integrate_targets => false
:clean
:根据 podspec 和项目支持平台的指定,清理所有不被 pod 使用的文件,默认为 true。:deduplicate_targets
:是否对 pod target 进行重复数据删除,默认为 true。:deterministic_uuids
:创建 pod project 是否产生确定性 UUID,默认为 true。:integrate_targets
:是否继承到用户项目中,为 false 会将 Pod 下载并安装到到 project_path/Pods 目录下,默认为 true。:lock_pos_sources
:是否锁定 pod 的源文件,当 Xcode 尝试修改时会提示解锁文件,默认为 true。:warn_for_multiple_pod_sources
:当多个 source 包含同名同版本 pod 时是否发出警告,默认为 true。:warn_for_unused_master_specs_repo
:如果没有明确指出 master specs repo 的 git 是否发出警告,默认为 true。:share_schemes_for_development_pods
:是否为开发中的 pod 分享 schemes,默认为 false。:disable_input_output_paths
:是否禁用 CocoaPods 脚本阶段的输入输出路径(Copy Frameworks 和 Copy Resources),默认为 false。:preserve_pod_file_structure
:是否保留所有 pod 的文件结构,默认为 false。:generate_multiple_pod_projects
:是否为每一个 pod target 生成 一个 project,生成与 Pods/Pods 文件夹中,默认为 false。:incremental_installation
:仅对自上次安装的 target 与其关联的 project 的变更部分进行重新生成,默认为 false。:skip_pods_project_generation
:是否跳过生成 Pods.xcodeproj 并仅进行依赖项解析与下载,默认为 false。 ensure_bundler!:当 bundler 版本不匹配时发出警告。ensure_bundler! '~> 2.0.0'
pod:指定项目的依赖项
# 依赖版本控制
pod 'Objection', '~> 0.9'
# Build configurations
pod 'PonyDebugger', :configurations => ['Debug', 'Beta']
# Modular Headers
pod 'SSZipArchive', :modular_headers => true
# Source
pod 'PonyDebugger', :source => 'https://github.com/CocoaPods/Specs.git'
# Subspecs
pod 'QueryKit', :subspecs => ['Attribute', 'QuerySet']
# Test Specs
pod 'AFNetworking', :testspecs => ['UnitTests', 'SomeOtherTests']
# Local path
pod 'AFNetworking', :path => '~/Documents/AFNetworking'
# 指定某个特殊或者更为先进的 Pod 版本
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'
# 指定某个 podspec
pod 'JSONKit', :podspec => 'https://example.com/JSONKit.podspec'
inherit:设置当前 target 的继承模式。
:complete
继承父级 target 的所有行为,:none
不继承父级 target 的任何行为,:search_paths
仅继承父级的搜索路径。target 'App' do
target 'AppTests' do
inherit! :search_paths
end
end
target:与 Xcode 中的 target 相对应,block 中是 target 的依赖项。
默认情况下,target 包含在父级 target 定义的依赖项,也即 inherit!
为 :complete
。关于 :complete
和 :search_paths
,:complete
会拷贝父级 target 的 pod 副本,而 :search_paths
则只进行 FRAMEWORK_SEARCH_PATHS
和 HEADER_SEARCH_PATHS
的相关拷贝,具体可通过比对 Pods/Target Support Files 的相关文件得以验证,一般在 UnitTests
中使用,以减少多余的 install_framework
过程。
target 'ShowsApp' do
pod 'ShowsKit'
# 拥有 ShowsKit 和 ShowTVAuth 的拷贝
target 'ShowsTV' do
pod 'ShowTVAuth'
end
# 拥有 Specta 和 Expecta 的拷贝
# 并且能够通过 ShowsApp 进行访问 ShowsKit, 相当于 ShowsApp 是 ShowsTests 的宿主APP
target 'ShowsTests' do
inherit! :search_paths
pod 'Specta'
pod 'Expecta'
end
end
abstract_target:定义 abstract_target
,方便 target 进行依赖继承,在 CocoaPods 1.0 版本之前为 link_with
。
abstract_target 'Networking' do
pod 'AlamoFire'
target 'Networking App 1'
target 'Networking App 2'
end
abstract:表示当前 target 是抽象的,不会链接到 Xcode 的 target 中。
script_phase:添加脚本阶段。
在执行完 pod install 之后 CocoaPods 会将脚本添加到对应的 target build phases。
target 'App' do
script_phase {
:name => 'scriptName' # 脚本名称,
:script => 'echo "nihao"' # 脚本内容,
:execution_position => :before_compile / :after_compile
:shell_path => '/usr/bin/ruby' # 脚本路径
:input_files => ['/input/filePath'], # 输入文件
:output_files => ['/outpput/filePath'] # 输出文件
}
end
platform:指定其构建平台。
默认值为 iOS 4.3、OSX 10.6、tvOS 9.0 和 watchOS 2.0。CocoaPods 1.0 之前的版本为 xcodeproj
platform :ios, '4.0'
project:指定包含 target 的 Xcode project。这一般在 workspace 存在多个 xcode project 中使用:
# 在 FastGPS Project 中可以找到一个名为 MyGPSApp 的 target
target 'MyGPSApp' do
project 'FastGPS'
...
end
inhibit_all_warnings!:禁止所有警告。如果针对单个 Pod,则可以采用:
pod 'SSZipArchive', :inhibit_warnings => true
pod 'SSZipArchive', :inhibit_warnings => true
user_modular_headers!:将所有 Pod 模块化。如果针对单个 Pod,则可以采用:
pod 'SSZipArchive', :modular_headers => true
pod 'SSZipArchive', :modular_headers => false
user_frameworks!:采用 framework 而不是 .a 文件的静态库。
可以通过 :linkage 指定使用静态库还是动态库:
use_frameworks!:linkage => :dynamic / :static
supports_swift_versions:指定 target definition 支持的 swift 版本要求
supports_swift_versions '>= 3.0', '< 4.0'
workspace:指定包含所有项目的 Xcode workspace。
workspace 'MyWorkspace'
sources:Podfile 从指定的源列表中进行检索。sources 默认存储在 ~/.cocoapods/repos 中,是全局的而非按 target definition 存储。当有多个相同的 Pod 时,优先采用检索到的 Pod 的第一个源,因此当指定另一个来源时,则需显示指定 CocoaPods 的源。
source 'https://github.com/artsy/Specs.git'
source 'https://github.com/CocoaPods/Specs.git'
plugin:指定在安装期间使用的插件。
plugin 'cocoapods-keys', :keyring => 'Eidolon'
plugin 'slather'
pre_install:在下载后和在安装 Pod 前进行更改。
pre_install do |installer|
# Do something fancy!
end
pre_integrate:在 project 写入磁盘前进行更改。
pre_integrate do |installer|
# perform some changes on dependencies
end
post_install:对生成 project 写入磁盘前进行最后的修改。
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
post_integrate:在 project 写入磁盘后进行最后更改。
post_integrate do |installer|
# some change after project write to disk
end
podspec = pod Specification,意为 pod 规范,它是一个 Ruby 文件。包含了 Pod 的库版本详细信息,例如应从何处获取源、使用哪些文件、要应用构建设置等信息;也可以看作该文件是整个仓库的索引文件,了解它对我们知道 Pod 库是如何组织、运作的提供了很大帮助。podspec 的 DSL 提供了极大的灵活性,文件可通过 pod spec create
创建。
名称 | 用途 | 必需 |
---|---|---|
name | pod 名称 | required |
version | pod 版本,遵循语义化版本控制 | required |
swift_version | 支持的 Swift 版本 | |
cocoapods_version | 支持的 CocoaPods 版本 | |
authors | pod 维护者的姓名和电子邮件,用“, ”进行分割 | required |
license | pod 的许可证 | required |
homepage | pod 主页的 URL | required |
source | 源地址,即源文件的存放地址,支持多种形式源 | required |
summary | pod 的简短描述 | required |
prepare_command | 下载 pod 后执行的 bash 脚本 | |
static_framework | 是否采用静态 framework 分发 | |
deprecated | 该库是否已被弃用 | |
deprecated_in_favor_of | 该库名称已被弃用,取而代之 |
Pod::Spec.new do |s|
s.name = 'CustomPod'
s.version = '0.1.0'
s.summary = 'A short description of CustomPod.'
s.swift_versions = ['3.0', '4.0', '4.2']
s.cocoapods_version = '>= 0.36'
s.author = { 'nihao' => 'XXXX@qq.com' }
s.license = { :type => 'MIT', :file => 'LICENSE' }
s.homepage = 'https://github.com/XXX/CustomPod'
# Supported Key
# :git=> :tag, :branch, :commit,:submodules
# :svn=> :folder, :tag,:revision
# :hg=>:revision
# :http=> :flatten, :type, :sha256, :sha1,:headers
s.source = { :git => 'https://github.com/XX/CustomPod.git', :tag => s.version.to_s }
s.prepare_command = 'ruby build_files.rb'
s.static_framework = true
s.deprecated = true
s.deprecated_in_favor_of = 'NewMoreAwesomePod'
end
platform:pod 支持的平台,留空意味着 pod 支持所有平台。当支持多平台时应该用 deployment_target
代替。
spec.platform = :osx, '10.8'
deployment_target:允许指定支持此 pod 的多个平台,为每个平台指定不同的部署目标。
spec.ios.deployment_target = '6.0'
spec.osx.deployment_target = '10.8'
dependency:基于其他 pods 或子规范的依赖
spec.dependency 'AFNetworking', '~> 1.0', :configurations => ['Debug']
info_plist:加入到生成的 Info.plist 的键值对,会对 CocoaPods 生成的默认值进行覆盖。仅对使用 framework 的框架有影响,对静态库无效。对于应用规范,这些值将合并到应用程序主机的 Info.plist
;对于测试规范,这些值将合并到测试包的 Info.plist。
spec.info_plist = {
'CFBundleIdentifier' => 'com.myorg.MyLib',
'MY_VAR' => 'SOME_VALUE'
}
requires_arc:允许指定哪些 source_files 采用 ARC,不使用 ARC 的文件将具有 -fno-objc-arc
编译器标志
spec.requires_arc = false
spec.requires_arc = 'Classes/Arc'
spec.requires_arc = ['Classes/*ARC.m', 'Classes/ARC.mm']
frameworks:使用者 target 需要链接的系统框架列表
spec.ios.framework = 'CFNetwork'
spec.frameworks = 'QuartzCore', 'CoreData'
weak_frameworks:使用者 target 需要弱链接的框架列表
spec.weak_framework = 'Twitter'
spec.weak_frameworks = 'Twitter', 'SafariServices'
libraries:使用者 target 需要链接的系统库列表
spec.ios.library = 'xml2'
spec.libraries = 'xml2', 'z'
compiler_flags:应传递给编译器的 flags
spec.compiler_flags = '-DOS_OBJECT_USE_OBJC=0', '-Wno-format'
pod_target_xcconfig:将指定 flag 添加到最终 pod 的 xcconfig 文件
spec.pod_target_xcconfig = { 'OTHER_LDFLAGS' => '-lObjC' }
user_target_xcconfig:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。