项目组件化时用的包管理技术。

要解除循环依赖,引入包管理技术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抛出的异常开始,如下图:


image.png

**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文件

打开项目可以开到工程里都给你配置好了 画的地方就是你开发自己静态库文件编码的地方(怎么打包成静态库,请往下看)这里因为特殊原因,一些文件不能展开

image.png

$ 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'

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。

image.png

上面报错的原因就是,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'

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上重新建一个仓库。**