要解除循环依赖,引入包管理技术cocoapods会让我们更有效率。pod不允许组件间有循环依赖,若有pod install时就会报错。
cocoapods,提供私有pod repo,使用时把自己的组件放在私有pod repo里,然后在Podfile里直接通过pod命令集成。一个组件对应一个私有pod,每个组件依赖自己所需要的三方库。多个组件联合开发的时候,可以再一个podspec里配置子模块,这样在每个组件自己的podspec里,只需要把子模块里的pod依赖关系拷贝过去就行了。
pod repo update命令。
有个场景,几个人共同维护一个项目,Podfile也是共同维护一份。有一天其中一个人,升级了Podfile中某个库的版本,比如AFNetworking从3.0.4升级到了3.1.0, pod 'AFNetworking', '~> 3.1.0’。然后,你更新了最新的Podfile,跑了一下pod install。。。。。。
1、先从pod install抛出的异常开始,如下图:
**1.Github **
创建自己的Repository,我创建了SDKLib,然后从本地上传到github上, 这些步骤就不在这里赘述了,经常跑github的同学应该都会。
**2 基于pod命令创建SDK **
具体的pod命令如下:
pod lib create SDKLib
调用以后terminal中会需要填写以下问题,一般选择创建Demo,其他选项根据需求填写:
What languagedoyou want to use??[ Swift / ObjC ]
ObjC
Would you like toincludea demo application with your library? [ Yes / No ]
YES
Which testing frameworks will you use? [ Specta / Kiwi / None ]
None
Would you like todoview based testing? [ Yes / No ]
Yes
What is yourclassprefix?
SDK
第二种:(使用xcode手动创建静态库,网上比较多的版本,需要做一些配置,这里个人觉得太不方便,如果喜欢xcode自己创建的可以参考这篇https://www.jianshu.com/p/e588bb0411d8)费力不讨好的工程
3.建tag
打开终端,cd 到项目SDKLib目录下,
git tag '1.0.0'//这个命令是本地创建tag,1.0.0版本
git push --tags // 这个命令是把tag推送到远端。
4.创建项目的podspec文件
现在终端还是在项目QShare的目录下,执行以下命令
$ pod spec createSDKLib
在本地目录下同时也生成了SDKLib.podspec文件
打开项目可以开到工程里都给你配置好了 画的地方就是你开发自己静态库文件编码的地方(怎么打包成静态库,请往下看)这里因为特殊原因,一些文件不能展开
$ vim SDKLib.podspec
编辑podspec文件,会发现这个文件已经生成了部分的字段
以下是编辑好的podspec 文件 做一些解释
Pod::Spec.new do |s|
s.name = 'SDKLib'
s.version = '0.4.9'
s.summary = 'A short description of SDKLib.'
s.platform = :ios
s.homepage = 'https://github.com/wangxiaokui'#
s.screenshots = 'www.example.com/screenshots_1', 'www.example.com/screenshots_2's.license = { :type => 'MIT', :file => 'LICENSE' }
s.author = { 'xiaokui' => 'm18736056517@163.com' }
s.source = { :git => 'https://github.com/xiaokui/SDKLib.git', :tag => s.version}
s.source = { :git => '/Users/fan/SDKLib' } #加载本地自己的库的引用
s.social_media_url = 'https://twitter.com/'
s.ios.deployment_target = '8.0'
s.source_files = 'SDKLib/Classes/*/'
s.resource_bundles = {
'SDKLib' => ['SDKLib/Assets/*.png']
}
s.public_header_files = 'Pod/Classes/*/.h'
s.frameworks = 'SystemConfiguration','MobileCoreServices','CoreGraphics','UIKit','AVFoundation','Photos','AdSupport','GLKit','MediaPlayer','MessageUI','CoreMotion','CoreTelephony'
s.dependency 'MBProgressHUD'
s.dependency 'MJExtension'
s.dependency 'SDWebImage'
s.dependency 'Masonry'
s.dependency 'MJRefresh'
s.dependency 'SVProgressHUD'
s.dependency 'Google-Mobile-Ads-SDK'
end
podspec中重要的几个内容解释如下:
s.source中是表示使用pod package打包时候pod去寻找的打包的路径,podspec默认使用git commit tag作为路径,也可以修改成本地路径/Users/pp/Desktop/MyCustomLib,如果当前没有设置:tag,打包时候默认使用当前git commit的head节点(如果部分修改内容没有commit,那么使用git package不会将未commit的内容进行打包).
s.source_files表示具体的源码的路径,这里注意源码一般放到Classes文件夹目录下,而且实体文件中不要有非源码内容放到Classes文件夹.Classes文件夹的所有内容都要Add Targets To: MyCustomLib.不要Classes文件夹或子文件夹中部分内容被remove referrence.
s.resource_bundles中的资源.系统会自动将MyCustomLib/Assets文件夹下的内容,cocoapod会将我们把Assets中的内容自动打包成MyCustomLib.bundle.这里也可以使用简单的方式
1 在Assets文件夹中放入我们自己写好的MyCustomLib.bundle,bundle中是我们使用的资源.
2 使用s.resource = 'MyCustomLib/Assets/*'.最后会将这些资源打入framework中.
3 在Example中手动引用我们自己创建的*.bundle资源文件.
s.public_header_files用来指定需要对外部暴露的头文件的位置
s.frameworks和s.libraries,表示当前sdk依赖的系统的framework和类库
s.dependency表示当前podspec类库对外部第三方库的依赖.如果使用pod package打包sdk时候,这里的dependency会被自动添加前缀,防止重复引用冲突.而且这里的依赖只能是pod库(公有或者私有)的内容.
s.subspec用来引入我们sdk依赖的自己的framework或者.a等静态库
特别注意在.podspec 操作了s.dependency依赖了一些库了后,就不需要再同一工程里使用podfile文件再次pod这些库了,它们会冲突,同时需要理解.podspec 里一些配置的意思相信会解决你不少问题
编辑好podspec文件后,需要验证一下这个文件是否能通过编译。
$ pod spec lint SDKLib.podspec --verbose
然而并没有通过
- ERROR | [iOS] Encountered an unknown error (The'Pods'target has transitive dependencies that include static binaries:
找了一些相关的,这个错误是因为依赖库(s.dependency)包含了.a静态库造成的。虽然这并不影响Pod的使用,但是验证是无法通过的。可以通过 --use-libraries 来让验证通过。使用以下的命令:
$ pod spec lint QShare.podspec --verbose --use-libraries
这种情况下使用 --use-libraries 虽然不会出现错误(error),但是有时候会带来一些警告(waring),警告同样是无法通过验证的。这时可以用 --allow-warnings 来允许警告。
$ pod spec lint QShare.podspec --verbose --use-libraries --allow-warnings
这里针对自己的项目情况判断添加那些命令通过了。
5、提交到pod (使用git命令,打上tag再次提交,版本号每次需要更新哦)这里不多说了
发布时也会验证 Pod 的有效性,如果你在手动验证 Pod 时使用了 --use-libraries 或 --allow-warnings 等修饰符,那么发布的时候也应该使用相同的字段修饰,否则出现相同的报错。
发布成功后,
终于可以使用 pod search 搜索到自己的 Pod 了。
➜fanpod search SDKLib
-> SDKLib (1.0.0)
Gather Some Auth Share Pay.
pod 'SDKLib', '~> 1.0.0'
Homepage: https://github.com/xiaokui/SDKLib
Versions: 1.0.0 [master repo]
6、版本升级
当需要更新 Pod 版本的时候,修改 .podspec 中的 s.version 为更高的版本号,并修改 s.source 中对应的 Git 版本。提交到Git,并打上对应tag。然后再次执行pod trunk push SDKLib.podspec将新的 .podspec 发布到 CocoaPods。更新完成!
为了更方便的修改版本号,用了以下的语句:
s.source = { :git => "https://github.com/xiaokui/SDKLib.git", :tag => "v#{s.version}" }
这样与 s.version进行了绑定,每次提交新的版本只需要修改s.version = "xxxx"。
7:将源码打包成静态库.a或者.framework
需要安装cocoapods-packager.(安装命令:sudo gem install cocoapods-packager)
然后执行pod package SDKLib.podspec --force --verbose.通过这个命令打包时候会自动将podspec中dependency的第三方库进行重命名.这样打出来的是SDKLib.framework.
(打release 的包默认打包成framework,如果在后面加上参数“--library”则打包成.a文件,--force是指强制覆盖)前面资源文件都在SDKLib.framework/Reources/SDKLib.bundle里面可以手动把这个bundle拖出去.
前面提到过使用pod package打包时候需要注意.pod会根据当前podspec中的s.source的地址去查找当前sdk源文件的地址.如果使用的s.source = { :git => 'https://github.com/xiaokui/SDKLib.git', :tag => s.version.to_s },那么就会去git中拉取最后一个tag对应commit的源码.如果使用的s.source = { :git => '/Users/fan/Desktop/SDKLib'},那么会使用当前sdk中git 的HEAD位置的commit的源码进行打包编译.(如果源码有修改,一定要先git commit,然后再打包)
** 注意问题**
1、 重点问题一: Example中依赖某些类库
举例说明,如果SDKLib.podspec中依赖s.dependency 'AFNetworking', '~> 2.3',此时在Example中也需要使用AFNetworking,那么这里千万不要在Example中引入AFNetworking的源码,请在podfile中添加pod AFNetworking.
2、 重点问题二: SDK中依赖的第三方库无法使用BITCODE
在Example的podfile底部添加以下语句:
// post_install do |installer|
// installer.pods_project.targets.each do |target|
// target.build_configurations.each do |config|
// config.build_settings['ENABLE_BITCODE'] = 'NO'
// end
// end
3 、重点问题三: SDK中调用资源的问题
对于podfile,常见的库的地址引用写法如下:
pod'库名', :podspec =>'podspec文件路径'#指定导入库的podspec文件路径pod'库名', :git =>'源码git地址'#指定导入库的源码git地址pod'库名', :tag =>'tag名'#指定导入库的Tag分支pod'库名', :path =>'~/Documents/AFNetworking'#指定本地的某个库,文件夹中要有podspec文件
用AFNetworking举例:
// 使用仓库中的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'//指定一个提交记录:pod'AFNetworking', :git=>'https://github.com/gowalla/AFNetworking.git', :commit=>'082f8319af'//指定本地路径的最近一次提交commitpod'库名', :path=>'~/Documents/AFNetworking'
打包成功后会在SDKLib.podspec文件路径下面生成一个打包文件,在iOS文件夹里面会看到生成的静态库包
8:可以验证自己的pod地址了(这样pod下来的是静态库源码,你会发现自己开发的静态库文件,到pod文件下面了,具体需要你自己验证一篇)
** 再次创建一个项目,在配置podfile文件在里面添加自己的git地址,pod install 试试 ,一路有坑,根据特定的情况解决问题 **
特别注意:
** 7和8是不一样,7是打包看不到源码,8是在git上pod的下来的源码,如果想在git上pod下来是打包好的静态库不是开源的源码,可以把静态库配置好..podspec上传上git,你需要在git上重新建一个仓库。**
为了解决这个异常可能尝试一下:
(1)是不是Podfile和Podfile.lock 文件不同步?删掉.lock文件再pod install一次,仍然报错。
(2)是不是AFNetworking没有3.1.0版本?pod search afnetworking一下,版本存在。
如果被我猜中了,证明你把焦点放在了异常前三行,而忽略了最关键的信息:None of your spec sources contain a spec satisfying the dependencies: AFNetworking (~> 3.1.0), AFNetworking (= 3.1.0)。
这句话的意思是说:你spec资源中不包含AFNetworking的3.1.0的配置信息。这里面有个关键词,spec资源和配置信息。
然后最下面提醒pod repo update’ does not happen on ‘pod install’ by default。意思是默认情况下,执行pod install不会自动执行pod repo update命令。那么pod repo update做了什么?
2、pod repo update
简单来说,pod repo update命名是用来更新本地cocoapods的spec资源配置信息。
安装完cocoapods后,在用户根目录下有个隐藏文件夹,/Users//.cocoapods,里面是cocoapods收录的所有库的配置信息,/Users//.cocoapods/repos/master/Specs/。比如AFNetworking就是/Users//.cocoapods/repos/master/Specs/AFNetworking,内部分版本包含多个文件夹,每个文件夹内包含一个配置文件,比如AFNetworking.podspec.json。
上面报错的原因就是,Podfile中AFNetworking的版本更新到了3.1.0,但是本地.cocoapods下找不到相应的配置文件。
然后按照提示,执行pod repo update,碰到网速慢的时候,命令执行完了就不动了,又被迫摆出葛优躺等着。
重点来了,pod repo update实际是更新整个.cocoapods下的所有库,其实我们可以只更新其中某个库来达到快速可用的目的。下面提供两个方法解决:
(1)正规方法:
指定更新单独库pod repo update /Users//.cocoapods/repos/master/Specs/
(2)野路子:
如果方法1仍然无法解决问题,而又着急使用。可以直接到相应目录下手动增加缺少的版本目录和spec文件,/Users//.cocoapods/repos/master/Specs//3.2.0/.spec。spec文件参考git上相应库的版本。
podspec
**1.Github **
创建自己的Repository,我创建了SDKLib,然后从本地上传到github上, 这些步骤上面有,不过经常跑github的同学应该都会。
**2 基于pod命令创建SDK **
具体的pod命令如下:
pod lib create SDKLib
调用以后terminal中会需要填写以下问题,一般选择创建Demo,其他选项根据需求填写:
What languagedoyou want to use??[ Swift / ObjC ]
ObjC
Would you like toincludea demo application with your library? [ Yes / No ]
YES
Which testing frameworks will you use? [ Specta / Kiwi / None ]
None
Would you like todoview based testing? [ Yes / No ]
Yes
What is yourclassprefix?
SDK
第二种:(使用xcode手动创建静态库,网上比较多的版本,需要做一些配置,这里个人觉得太不方便,如果喜欢xcode自己创建的可以参考这篇https://www.jianshu.com/p/e588bb0411d8)费力不讨好的工程
3.建tag
打开终端,cd 到项目SDKLib目录下,
git tag '1.0.0'//这个命令是本地创建tag,1.0.0版本
git push --tags // 这个命令是把tag推送到远端。
4.创建项目的podspec文件
现在终端还是在项目QShare的目录下,执行以下命令
$ pod spec createSDKLib
在本地目录下同时也生成了SDKLib.podspec文件
$ vim SDKLib.podspec
编辑podspec文件,会发现这个文件已经生成了部分的字段
以下是编辑好的podspec 文件 做一些解释
Pod::Spec.new do |s|
s.name = 'SDKLib'
s.version = '0.4.9'
s.summary = 'A short description of SDKLib.'
s.platform = :ios
s.homepage = 'https://github.com/wangxiaokui'#
s.screenshots = 'www.example.com/screenshots_1', 'www.example.com/screenshots_2's.license = { :type => 'MIT', :file => 'LICENSE' }
s.author = { 'xiaokui' => 'm18736056517@163.com' }
s.source = { :git => 'https://github.com/xiaokui/SDKLib.git', :tag => s.version}
s.source = { :git => '/Users/fan/SDKLib' } #加载本地自己的库的引用
s.social_media_url = 'https://twitter.com/'
s.ios.deployment_target = '8.0'
s.source_files = 'SDKLib/Classes/*/'
s.resource_bundles = {
'SDKLib' => ['SDKLib/Assets/*.png']
}
s.public_header_files = 'Pod/Classes/*/.h'
s.frameworks = 'SystemConfiguration','MobileCoreServices','CoreGraphics','UIKit','AVFoundation','Photos','AdSupport','GLKit','MediaPlayer','MessageUI','CoreMotion','CoreTelephony'
s.dependency 'MBProgressHUD'
s.dependency 'MJExtension'
s.dependency 'SDWebImage'
s.dependency 'Masonry'
s.dependency 'MJRefresh'
s.dependency 'SVProgressHUD'
s.dependency 'Google-Mobile-Ads-SDK'
end
podspec中重要的几个内容解释如下:
s.source中是表示使用pod package打包时候pod去寻找的打包的路径,podspec默认使用git commit tag作为路径,也可以修改成本地路径/Users/pp/Desktop/MyCustomLib,如果当前没有设置:tag,打包时候默认使用当前git commit的head节点(如果部分修改内容没有commit,那么使用git package不会将未commit的内容进行打包).
s.source_files表示具体的源码的路径,这里注意源码一般放到Classes文件夹目录下,而且实体文件中不要有非源码内容放到Classes文件夹.Classes文件夹的所有内容都要Add Targets To: MyCustomLib.不要Classes文件夹或子文件夹中部分内容被remove referrence.
s.resource_bundles中的资源.系统会自动将MyCustomLib/Assets文件夹下的内容,cocoapod会将我们把Assets中的内容自动打包成MyCustomLib.bundle.这里也可以使用简单的方式
1 在Assets文件夹中放入我们自己写好的MyCustomLib.bundle,bundle中是我们使用的资源.
2 使用s.resource = 'MyCustomLib/Assets/*'.最后会将这些资源打入framework中.
3 在Example中手动引用我们自己创建的*.bundle资源文件.
s.public_header_files用来指定需要对外部暴露的头文件的位置
s.frameworks和s.libraries,表示当前sdk依赖的系统的framework和类库
s.dependency表示当前podspec类库对外部第三方库的依赖.如果使用pod package打包sdk时候,这里的dependency会被自动添加前缀,防止重复引用冲突.而且这里的依赖只能是pod库(公有或者私有)的内容.
s.subspec用来引入我们sdk依赖的自己的framework或者.a等静态库
特别注意在.podspec 操作了s.dependency依赖了一些库了后,就不需要再同一工程里使用podfile文件再次pod这些库了,它们会冲突,同时需要理解.podspec 里一些配置的意思相信会解决你不少问题
编辑好podspec文件后,需要验证一下这个文件是否能通过编译。
$ pod spec lint SDKLib.podspec --verbose
然而并没有通过
- ERROR | [iOS] Encountered an unknown error (The'Pods'target has transitive dependencies that include static binaries:
找了一些相关的,这个错误是因为依赖库(s.dependency)包含了.a静态库造成的。虽然这并不影响Pod的使用,但是验证是无法通过的。可以通过 --use-libraries 来让验证通过。使用以下的命令:
$ pod spec lint QShare.podspec --verbose --use-libraries
这种情况下使用 --use-libraries 虽然不会出现错误(error),但是有时候会带来一些警告(waring),警告同样是无法通过验证的。这时可以用 --allow-warnings 来允许警告。
$ pod spec lint QShare.podspec --verbose --use-libraries --allow-warnings
这里针对自己的项目情况判断添加那些命令通过了。
5、提交到pod (使用git命令,打上tag再次提交,版本号每次需要更新哦)这里不多说了
发布时也会验证 Pod 的有效性,如果你在手动验证 Pod 时使用了 --use-libraries 或 --allow-warnings 等修饰符,那么发布的时候也应该使用相同的字段修饰,否则出现相同的报错。
发布成功后,
终于可以使用 pod search 搜索到自己的 Pod 了。
➜fanpod search SDKLib
-> SDKLib (1.0.0)
Gather Some Auth Share Pay.
pod 'SDKLib', '~> 1.0.0'
Homepage: https://github.com/xiaokui/SDKLib
Versions: 1.0.0 [master repo]
6、版本升级
当需要更新 Pod 版本的时候,修改 .podspec 中的 s.version 为更高的版本号,并修改 s.source 中对应的 Git 版本。提交到Git,并打上对应tag。然后再次执行pod trunk push SDKLib.podspec将新的 .podspec 发布到 CocoaPods。更新完成!
为了更方便的修改版本号,用了以下的语句:
s.source = { :git => "https://github.com/xiaokui/SDKLib.git", :tag => "v#{s.version}" }
这样与 s.version进行了绑定,每次提交新的版本只需要修改s.version = "xxxx"。
7:将源码打包成静态库.a或者.framework
需要安装cocoapods-packager.(安装命令:sudo gem install cocoapods-packager)
然后执行pod package SDKLib.podspec --force --verbose.通过这个命令打包时候会自动将podspec中dependency的第三方库进行重命名.这样打出来的是SDKLib.framework.
(打release 的包默认打包成framework,如果在后面加上参数“--library”则打包成.a文件,--force是指强制覆盖)前面资源文件都在SDKLib.framework/Reources/SDKLib.bundle里面可以手动把这个bundle拖出去.
前面提到过使用pod package打包时候需要注意.pod会根据当前podspec中的s.source的地址去查找当前sdk源文件的地址.如果使用的s.source = { :git => 'https://github.com/xiaokui/SDKLib.git', :tag => s.version.to_s },那么就会去git中拉取最后一个tag对应commit的源码.如果使用的s.source = { :git => '/Users/fan/Desktop/SDKLib'},那么会使用当前sdk中git 的HEAD位置的commit的源码进行打包编译.(如果源码有修改,一定要先git commit,然后再打包)
** 注意问题**
1、 重点问题一: Example中依赖某些类库
举例说明,如果SDKLib.podspec中依赖s.dependency 'AFNetworking', '~> 2.3',此时在Example中也需要使用AFNetworking,那么这里千万不要在Example中引入AFNetworking的源码,请在podfile中添加pod AFNetworking.
2、 重点问题二: SDK中依赖的第三方库无法使用BITCODE
在Example的podfile底部添加以下语句:
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['ENABLE_BITCODE'] = 'NO'
end
end
3 、重点问题三: SDK中调用资源的问题
对于podfile,常见的库的地址引用写法如下:
pod'库名', :podspec =>'podspec文件路径'#指定导入库的podspec文件路径pod'库名', :git =>'源码git地址'#指定导入库的源码git地址pod'库名', :tag =>'tag名'#指定导入库的Tag分支pod'库名', :path =>'~/Documents/AFNetworking'#指定本地的某个库,文件夹中要有podspec文件
用AFNetworking举例:
// 使用仓库中的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'//指定一个提交记录:pod'AFNetworking', :git=>'https://github.com/gowalla/AFNetworking.git', :commit=>'082f8319af'//指定本地路径的最近一次提交commitpod'库名', :path=>'~/Documents/AFNetworking'
打包成功后会在SDKLib.podspec文件路径下面生成一个打包文件,在iOS文件夹里面会看到生成的静态库包
8:可以验证自己的pod地址了(这样pod下来的是静态库源码,你会发现自己开发的静态库文件,到pod文件下面了,具体需要你自己验证一篇)
** 再次创建一个项目,在配置podfile文件在里面添加自己的git地址,pod install 试试 ,一路有坑,根据特定的情况解决问题 **
特别注意:
** 7和8是不一样,7是打包看不到源码,8是在git上pod的下来的源码,如果想在git上pod下来是打包好的静态库不是开源的源码,可以把静态库配置好..podspec上传上git,你需要在git上重新建一个仓库。**