iOS组件化系列
使用Cocoapods创建私有podspec
学习了一下如何创建私有podspec,相应的案例可以参看 GitHub上的私有源 。
更新pod到最新稳定版本
1
2
3
4
5
6
7
8
9
10
11
12
13
➜ BitAutoPlus git:(develop) pod --version
1.5.3
➜ BitAutoPlus git:(develop) gem source -l
*** CURRENT SOURCES ***
http://gems.ruby-china.org/
➜ BitAutoPlus git:(develop) gem source -r http://gems.ruby-china.org/
http://gems.ruby-china.org/ removed from sources
➜ BitAutoPlus git:(develop) gem source -a https://gems.ruby-china.com/
https://gems.ruby-china.com/ added to sources
➜ BitAutoPlus git:(develop) sudo gem install cocoapods
➜ BitAutoPlus git:(develop) pod --version
1.7.5
创建并设置一个私有的Spec Repo
1
2
# pod repo add [Private Repo Name] [GitHub HTTPS clone URL]
$ pod repo add FDSpecs https://github.com/toolazytoname/Specs.git
创建Pod的所需要的项目工程文件
1
2
$ pod lib create podTestLibrary
#这里需要注意的是每当你向Pod中添加了新的文件或者以后更新了podspec的版本都需要重新执行一遍pod update命令。
设置tag
1
2
$ git tag -m "first release" 0.1.0
$ git push --tags #推送tag到远端仓库
编辑完podspec
文件后,需要验证一下这个文件是否可用,如果有任何WARNING
或者ERROR
都是不可以的,它就不能被添加到Spec Repo
中,不过xcode
的WARNING
是可以存在的,验证需要执行一下命令
1
2
3
$ pod lib lint
$ pod lib lint --sources='https://github.com/toolazytoname/Specs.git,https://github.com/CocoaPods/Specs.git' --allow-warnings
这里需要注意一下,如果podspec 有依赖私有源,需要--sources这个参数带上公有源和私有源,后面的push操作也一样
这里列几个自认为很有用的配置
- –allow-warnings
- –use-libraries
- –skip-import-validation
- –fail-fast
具体含义自己查一下官方文档吧
创建Pod所对应的podspec文件
$ pod spec create PodTestLibrary [email protected]:wtlucky/podTestLibrary.git
本地测试配置好的podspec文件是否可用。
1
2
3
4
platform :ios, '7.0'
pod 'PodTestLibrary', :path => '~/code/Cocoapods/podTest/PodTestLibrary' # 指定路径
pod 'PodTestLibrary', :podspec => '~/code/Cocoapods/podTest/PodTestLibrary/PodTestLibrary.podspec' # 指定podspec文件
向私有的Spec Repo中提交podspec
1
$ pod repo push FDSpecs PodTestLibrary.podspec #前面是本地Repo名字 后面是podspec名字
删除一个私有Spec Repo
1
$ pod repo remove FDSpecs
如果我们要删除私有Spec Repo
下的某一个podspec
只需要cd
到~/.cocoapods/repos/FDSpecs
目录下,删掉库目录,然后通过Git将变动 push到远端仓库。
Specification cheat sheet
source
The location from where the library should be retrieved.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#Specifying a Git source with a tag. This is how most OSS Podspecs work.
spec.source = { :git => 'https://github.com/AFNetworking/AFNetworking.git',
:tag => spec.version.to_s }
#Using a tag prefixed with 'v' and submodules.
spec.source = { :git => 'https://github.com/typhoon-framework/Typhoon.git',
:tag => "v#{spec.version}", :submodules => true }
#Using Subversion with a tag.
spec.source = { :svn => 'http://svn.code.sf.net/p/polyclipping/code', :tag => '4.8.8' }
#Using Mercurial with the same revision as the spec's semantic version string.
spec.source = { :hg => 'https://bitbucket.org/dcutting/hyperbek', :revision => "#{s.version}" }
#Using HTTP to download a compressed file of the code. It supports zip, tgz, bz2, txz and tar
spec.source = { :http => 'http://dev.wechatapp.com/download/sdk/WeChat_SDK_iOS_en.zip' }
#Using HTTP to download a file using a hash to verify the download. It supports sha1 and sha256.
spec.source = { :http => 'http://dev.wechatapp.com/download/sdk/WeChat_SDK_iOS_en.zip',
:sha1 => '7e21857fe11a511f472cfd7cfa2d979bd7ab7d96' }
frameworks
表示依赖系统的框架
1
s.frameworks = 'UIKit', 'MapKit'
libraries
表示依赖系统类库
1
s.libraries = 'sqlite3','c++.1','bz2.1.0','xml2.2','iconv.2','resolv.9','z.1’
vendored_libraries
表示依赖第三方的静态库, 依赖的第三方的或者自己的静态库文件必须以lib为前缀进行命名 ,否则会找不到
s.vendored_libraries = ‘Library/Classes/libWeChatSDK.a’
1
s.vendored_libraries = 'Library/Classes/libWeChatSDK.a'
vendored_frameworks
表示依赖第三方的framework
公开头文件
可以用这种方式隐藏内部类,保证封装性,让外部引用不到别的类。
1
s.public_header_files = 'Pod/Classes/**/*.h'
设置pch
1
s.prefix_header_file = 'BPNewsLib/Classes/BPNewsPrivate/BPNBaseHeader.pch'
一开始用的下面的这种,好low
1
s.prefix_header_contents = '#import "YCAdditions.h"','#import "MJExtension.h"','#import "Masonry.h"','#import "UIImageView+Async.h"','#import <ReactiveObjC/RACEXTScope.h>','#import "YCAppMacro.h"','#import "Constants.h"','#import "BPResponseModel.h"','#import "YCTopicMacros.h"','#import "UITableView+Layout.h"','#import "YCToolSet.h"','#import "M80AttributedLabel.h"'
subspec
看到这篇利用 podspec 的 subspec 来实现多个预处理宏的灵活配置,思路很好学习记录如下
这是普通青年的用法
[JSPatch startWithAppKey:@"YOU_GUESS"];
#ifdef DEBUG
[JSPatch setupDevelopment];
#endif
[JSPatch sync];
这是文艺青年的用法
Pod::Spec.new do |s|
#设置 podspec 的默认 subspec
s.default_subspec = 'core'
#主要 subspec
s.subspec 'core' do |c|
c.source_files = "*.{h,m}"
c.public_header_files = "*.h"
c.frameworks = 'UIKit',
c.libraries = 'icucore', 'sqlite3', 'z'
c.platform = :ios, "7.0"
end
#功能1,引入则开启
s.subspec 'IDFA' do |f|
f.dependency 'YOUR_SPEC/core'
f.pod_target_xcconfig = { 'GCC_PREPROCESSOR_DEFINITIONS' => 'ENABLE_IDFA=1'}
end
#功能2,引入则开启
s.subspec 'IDFB' do |f|
f.dependency 'YOUR_SPEC/core'
f.pod_target_xcconfig = { 'GCC_PREPROCESSOR_DEFINITIONS' => 'ENABLE_IDFB=1'}
end
end
这里面通过两个 subpec 来开关功能。当用户用的时候,则在 Podfile 里这么引入
1
pod 'YOUR_SPEC', :subspecs => ['IDFA', 'IDFB']
我觉得这是一种很优雅的做法。
在自己的项目中的应用如下:
随着组件化的铺开,当我们打算创建一个新App的时候,自然而然地就会复用指之前的模块和代码。当一个组件需要同时支持两个上层App, 两个App所需要的逻辑有所差异,我们会把一个库划分为两个子库。例如
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
s.default_subspec = 'Pay'
s.subspec 'Pay' do |pay|
pay.source_files = 'BitAutoPlusHomeLib/Classes/**/*'
pay.resource_bundles = {
'BitAutoPlusHomeLib' => ['BitAutoPlusHomeLib/Assets/**/*.{json,png}']
}
pay.dependency 'UMCShare/Social/QQ'
pay.dependency 'UMCShare/Social/Sina'
pay.dependency 'UMCShare/Social/WeChat'
end
s.subspec 'NoPay' do |nopay|
nopay.source_files = 'BitAutoPlusHomeLib/Classes/**/*'
nopay.resource_bundles = {
'BitAutoPlusHomeLib' => ['BitAutoPlusHomeLib/Assets/**/*.{json,png}']
}
nopay.dependency 'UMCShareNoPay/Social/QQ'
nopay.dependency 'UMCShareNoPay/Social/Sina'
nopay.dependency 'UMCShareNoPay/Social/WeChat'
end
两个子库的区别是pay 这个子库,引入的是一个完整的微信SDK的友盟,而另一个子库引入的是不带微信SDK的友盟。
如果不设置这一个属性,那么根据官方文档 的解释,外部引用BitAutoPlusHomeLib 的时候,会出现命名重复,冲突的错误。因为 If not specified a specifications requires all its subspecs as dependencies.所以我们需要设置这一个属性为其中一个子库,这个属性在两个子库不能共存的场景下分外实用。
另一个场景的场景是,组件二进制化。当一个库,需要同时对外暴露源码和二进制包的时候。两个子库也会有冲突,这时候也需要设置这个属性。
Podfile cheat sheet
pod
1
2
3
4
5
6
7
8
9
10
11
12
#you will want to use the latest version of a Pod. If this is the case, simply omit the version requirements.
pod 'SSZipArchive'
#you may want to freeze to a specific version of a Pod, in which case you can specify that version number
pod 'Objection', '0.9'
#Besides no version, or a specific one, it is also possible to use operators:
= 0.1 Version 0.1.
> 0.1 Any version higher than 0.1.
>= 0.1 Version 0.1 and any higher version.
< 0.1 Any version lower than 0.1.
<= 0.1 Version 0.1 and any lower version.
~> 0.1.2 Version 0.1.2 and the versions up to 0.2, not including 0.2. This operator works based on the last component that you specify in your version requirement. The example is equal to >= 0.1.2 combined with < 0.2.0 and will always match the latest known version matching your requirements.
Build configurations
1
2
pod 'PonyDebugger', :configurations => ['Debug', 'Beta']
pod 'PonyDebugger', :configuration => 'Debug'
Source
1
pod 'PonyDebugger', :source => 'https://github.com/CocoaPods/Specs.git'
Using the files from a local path.
1
pod 'AFNetworking', :path => '~/Documents/AFNetworking'
From a podspec in the root of a library repository
1
2
3
4
5
6
7
8
9
#To use the master branch of the repository
pod 'AFNetworking', :git => 'https://github.com/gowalla/AFNetworking.git'
#To use a different branch of the repository
pod 'AFNetworking', :git => 'https://github.com/gowalla/AFNetworking.git', :branch => 'dev'
#To use a tag of the repository
pod 'AFNetworking', :git => 'https://github.com/gowalla/AFNetworking.git', :tag => '0.7.0'
#Or specify a commit:
pod 'AFNetworking', :git => 'https://github.com/gowalla/AFNetworking.git', :commit => '082f8319af'
use_frameworks!
Use frameworks instead of static libraries for Pods.
1
use_frameworks!
参考
小坑xcrun: error: unable to find utility “simctl”, not a developer tool or in PATH
利用 podspec 的 subspec 来实现多个预处理宏的灵活配置