Pod组件开发的流程和常用配置

创建SDK项目

1、打开终端到相应的目录下执行pod lib create sdkName,sdkName是SDK名称,执行之后看到如下信息:

 pod lib create TestSDK
Cloning `https://github.com/CocoaPods/pod-template.git` into `TestSDK `.
Configuring TestSDK template.

------------------------------

To get you started we need to ask a few questions, this should only take a minute.

If this is your first time we recommend running through with the guide:
 - https://guides.cocoapods.org/making/using-pod-lib-create.html
 ( hold cmd and click links to open in a browser. )


What platform do you want to use?? [ iOS / macOS ]

2、选择平台,根据提示输入iOS或者macOS,这里我们选择iOS:

What platform do you want to use?? [ iOS / macOS ]
 > iOS

3、选择编程语言。这里我们选择ObjC,执行:

What language do you want to use?? [ Swift / ObjC ]
> ObjC

4、选择是否需要demo。为了方便自测,我们需要一个demo,选择Yes、执行:

Would you like to include a demo application with your library? [ Yes / No ]
 > Yes

5、选择测试框架。这里我们选着None,继续执行:

Which testing frameworks will you use? [ Specta / Kiwi / None ]
 > None

6、选择是否需要集成基于view的测试框架。这里我们选择No,继续执行:

Would you like to do view based testing? [ Yes / No ]
 > No

7、设置项目代码前缀。这里根据自己需要设置,也可以不设置。执行之后就会创建并自动打开一个xcode工程:

What is your class prefix?
 >

8、工程结构


1630031969818.jpg

截屏2021-08-27 上午10.38.42.png

Example是demo。SDK源码目录在TestSDK->Classes,资源文件TestSDK->Assets。
9、自动生成Podfile文件,并且指定了SDK的路径到本地路径path:

use_frameworks!

platform :ios, '9.0'

target 'TestSDK_Example' do
  pod 'TestSDK', :path => '../'

  target 'TestSDK_Tests' do
    inherit! :search_paths

    
  end
end

SDK开发

SDK源码编写

在TestSDK->Classes目录下添加代码文件。当资源文件代码文件或者podspec有更新时直接pod install就可以了。

podspec文件编写
Pod::Spec.new do |s|
  s.name             = 'TestSDK'
  s.version          = '0.1.0'
  s.summary          = 'A short description of TestSDK.'

  # This description is used to generate tags and improve search results.
  #   * Think: What does it do? Why did you write it? What is the focus?
  #   * Try to keep it short, snappy and to the point.
  #   * Write the description between the DESC delimiters below.
  #   * Finally, don't worry about the indent, CocoaPods strips it!

  s.description      = <<-DESC
  TODO: Add long description of the pod here.
                       DESC
  s.homepage         = 'https://github.com/ksxx.com/TestSDK'
  # s.screenshots     = 'www.example.com/screenshots_1', 'www.example.com/screenshots_2'
  s.license          = { :type => 'MIT', :file => 'LICENSE' }
  s.author           = { '123@126.com' => '123456@kingsoft.com' }
  s.source           = { :git => 'https://github.com/ksxx.com/TestSDK.git', :tag => s.version.to_s }
  # s.social_media_url = 'https://twitter.com/<TWITTER_USERNAME>'

  s.ios.deployment_target = '9.0'

  # 代码文件
  s.source_files = 'Classes/**/*'
  # public头文件
  s.public_header_files = 'Classes/**/*.h'

  # 依赖的系统frameworks
  s.frameworks = 'UIKit', 'MapKit'
  # 依赖的系统.a文件
  s.libraries = 'c++', 'resolv', 'stdc++.6.0.9'

  # 通过Pod依赖的第三方库,多个库就多个s.dependency
  s.dependency 'AFNetworking', '~> 2.3'
  s.dependency 'SDWebImage'

  # 手动依赖第三方framework
  s.vendored_frameworks = 'Classes/b/*.framework', 'TestSDK/Classes/a/*.framework'
  # 手动依赖第三方.a文件
  s.vendored_libraries = 'Classes/a/*.a','Classes/b/*.a'

  # 资源文件打包成bundle,避免资源文件冲突
  s.resource_bundles = {
    'TestResourceBundle' => ['Assets/Resource/*']
    'TestImgesBundle' => ['Assets/Images/*.png']
  }
  # 使用resources方式引用资源文件
  # spec.resources = ['Assets/Images/*.png', 'Assets/Resource/*']
  
  # 配置xcode的other flag
  s.pod_target_xcconfig = { 'OTHER_LDFLAGS' => '-lObjC' }

  # 指定SDK为静态库
  s.static_framework = true
  
  #支持系统版本
  s.ios.deployment_target = '9.0'

  # 子模块ModelA
  s.subspec 'ModelA' do |a|
    a.source_files = 'Classes/ModelA/**/*.{h,m}'
    a.public_header_files = 'Classes/ModelA/*.h'
    a.dependency 'CocoaAsyncSocket', '7.6.3'
    a.libraries = 'c++', 'resolv'
    a.frameworks = 'CoreBluetooth', 'ExternalAccessory'
    a.vendored_frameworks = 'Classes/Frameworks/ModelA.framework'
    a.pod_target_xcconfig = { 'OTHER_LDFLAGS' => '-lObjC' }
  end
   
  # 子模块ModelB
  s.subspec 'ModelB' do |b|
    b.source_files = 'Classes/ModelB/**/*.{h,m}'
    b.public_header_files = 'Classes/ModelB/*.h'
    b.dependency 'HongDa', '4.8.6'
  end

end
Public头文件

这部分主要是SDK对外开放的头文件,如果我们不指定的话,默认就是源代码的全部头文件。所以我们要根据自己需要,开放指定目录下的头文件:

  # public头文件
  s.public_header_files = 'Classes/**/*.h'
依赖库管理

依赖库系统库和第三方依赖库。系统库都可以通过podspec自动依赖;第三方依赖库依赖包括手动依赖和通过Pod自动依赖。

  • 依赖系统库
  # 依赖的系统frameworks
  s.frameworks = 'UIKit', 'MapKit'
  # 依赖的系统.a文件
  s.libraries = 'c++', 'resolv', 'stdc++.6.0.9'
  • 通过Pod自动依赖第三方库(第三方库支持)。
  # 通过Pod依赖的第三方库,多个库就多个s.dependency
  s.dependency 'AFNetworking', '~> 2.3'
  s.dependency 'SDWebImage'
  • 手动依赖第三方库
    首先得为第三方库创建一个目录,然后通过podspec指定相应的路径进行依赖:
# 手动依赖第三方framework
  s.vendored_frameworks = 'Classes/b/*.framework', 'TestSDK/Classes/a/*.framework'
  # 手动依赖第三方.a文件
  s.vendored_libraries = 'Classes/a/*.a','Classes/b/*.a'
资源管理

资源管理有两种方式,分别是 resource_bundles 和 resources 两种方式引用。

  • 使用resources方式引用资源:
  spec.resources = ['Assets/Images/*.png', 'Assets/Resource/*']

使用 resources 之后只会简单的将资源文件 copy 到目标工程(Example 工程),最后和目标工程的图片文件以及其他同样使用 resources 的 Pod 的图片文件,统一一起打包为了一个 Assets.car。使用 resources,如果出现同名的图片,显然是会出现冲突的。
resources 优点:

可以使用 .xcassets 指定资源文件;
不需要用硬编码方式获取图片。

resources 缺点:

可能会导致每个库和主工程之间的同名资源冲突;

[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];

所以,一般来说使用 resource_bundles 会更好,不过关于硬编码,还可以再找找别的方式去避免。

  • 使用resource_bundles方式引用资源
# 资源文件打包成bundle,避免资源文件冲突
  s.resource_bundles = {
    'TestResourceBundle' => ['Assets/Resource/*']
    'TestImgesBundle' => ['Assets/Images/*.png']
  }

使用 resource_bundles 之后会为为指定的资源打一个 .bundle,.bundle包含一个 Assets.car,获取图片的时候要严格指定 .bundle 的位置,很好的隔离了各个库或者一个库下的资源包。避免资源同名冲突。
resource_bundles 优点:

可以使用 .xcassets 指定资源文件
可以避免每个库和主工程之间的同名资源冲突

resource_bundles 缺点:

获取图片时可能需要使用硬编码的形式来获取,比如想访问TestResourceBundle的资源:
[[NSBundle bundleForClass:[self class]].resourcePath stringByAppendingPathComponent:@"/TestResourceBundle.bundle"]

子模块subspec配置

subspec就相当于SDK中的一个组件。如果我们想把SDK分层不同的模块,使得app在引用SDK时可以按需加载,就可以使用subspec。子模块跟主的spec是一样的,可以理解为它也是一个SDK。比如这里的ModelA:

  # 子模块ModelA
  s.subspec 'ModelA' do |a|
    a.source_files = 'Classes/ModelA/**/*.{h,m}'
    a.public_header_files = 'Classes/ModelA/*.h'
    a.dependency 'CocoaAsyncSocket', '7.6.3'
    a.libraries = 'c++', 'resolv'
    a.frameworks = 'CoreBluetooth', 'ExternalAccessory'
    a.vendored_frameworks = 'Classes/Frameworks/ModelA.framework'
    a.pod_target_xcconfig = { 'OTHER_LDFLAGS' => '-lObjC' }
  end

subspec可以像主spec一样指定自己的source_files、依赖库等等。子模块内部也可以在划分子模块,也可以引用其他子模块,但是要注意循环引用的问题。
那么在Podfile引用的时候可以是:

pod TestSDK/ModelA 

内部子模块的依赖,如:

 # 子模块ModelA
  s.subspec 'ModelA' do |a|
    a.source_files = 'Classes/ModelA/**/*.{h,m}'
    a.public_header_files = 'Classes/ModelA/*.h'
    a.dependency 'CocoaAsyncSocket', '7.6.3'
    a.libraries = 'c++', 'resolv'
    a.frameworks = 'CoreBluetooth', 'ExternalAccessory'
    a.vendored_frameworks = 'Classes/Frameworks/ModelA.framework'
    a.pod_target_xcconfig = { 'OTHER_LDFLAGS' => '-lObjC' }
  end
   
  # 子模块ModelB
  s.subspec 'ModelB' do |b|
    b.source_files = 'Classes/ModelB/**/*.{h,m}'
    b.public_header_files = 'Classes/ModelB/*.h'
    b.dependency 'TestSDK/ModelA '
    b.dependency 'HongDa', '4.8.6'
  end

SDK提交到CocoaPods

1、注册Trunk账户

注册Trunk账户(邮箱地址建议写成github注册的邮箱,用户名写成github对应的用户名),例如在终端输入:

pod trunk register helloworld@github.com 'helloworld' –verbose

注册命令执行完之后,对应的邮箱地址会收到一封邮件,“请确认您的注册CocoaPods通过点击以下链接:”,打开链接地址完成验证,如果地址不能点击就直接粘贴URL到浏览器上执行

注册完成之后可以通过pod trunk me查看注册信息。

2、提交代码到git,并打tag,用tag作版本号

(.podspec, LICENSE 这两个文件必须提交到git上)
git add .
git commit -m “1.0.0”
git push
git tag 1.0.0
git push –tags

3、提交之前先验证.podspec文件是否合法
pod spec lint TestSDK.podspec

如果警告一般没有影响,下面如果忽略警告提交可以用–allow-warnings忽略他们:

pod spec lint TestSDK.podspec –allow-warning
4、提交.podspec文件到trunk中
pod trunk push TestSDK.podspec

如果不想有警告,可以用下面的:

pod trunk push TestSDK.podspec –use-libraries  –allow-warnings

只要验证通过,提交时一般没有什么问题, 一般会卡在“Updating spec repo ‘master’”, 这时不要关闭终端。

5、查找提交成功的库

先重置一下cocoapods:

pod setup

然后搜索刚才提交的SDK名称:

pod search TestSDK

如果查不到会报错如下 [!] Unable to find a pod with name, author, summary, or description matching。
解决方案: 先删除search_index.json文件,然后再search (文件不存在时会自动下载,根据不同的网络可能要花一会时间,要等)。

rm ~/Library/Caches/CocoaPods/search_index.json 
pod search TestSDK
6、从cocoapods移除刚才的SDK
pod trunk delete TestSDK 1.0.0

Pod私有库创建

1、创建一个spec Repo的私有远程仓库和一个存放pod所需的项目工程文件的远程仓库;

比如:https://github.com/NoNameOrganazation/LNSpec.git

pod repo add nonameorganazation https://github.com/NoNameOrganazation/LNSpec.git

通过 cd ~/.cocoapods/repos 可以进入到podspec本地目录,并能看到nonameorganazation目录

2、通过pod创建一个本地库
pod lib create TestModule
3、创建一个组件的git仓库,指定组件的Git地址
git remote add origin https://github.com/dongjianxiong/NoNameOrganazation/TestModule.git

会自动生成一个TestModule.podspec, 编写podspec。

4、本地检查podspec的有效性
pod lib lint TestModule.podspec 
或
pod lib lint TestModule.podspec --allow-warnings(忽略警告)
// 如果依赖私有库,加私有库的sources,sources可以是多个,后面以逗号隔开即可
pod lib lint TestModule.podspec --sources=https://github.com/CocoaPods/Specs.git(公有库), https://github.com/NoNameOrganazation/LNSpec.git(私有库) -allow-warnings
5、设置podspec版本号

设置podspec的版本号后,通过打tag或分支命名为版本号。每次更新组件的版本号都要更新podspec的版本号(s.version)。比如:

git tag 0.1.0
git push origin 0.1.0
6、远端检查podspec的有效性
pod spec lint TestModule.podspec
或
pod spec lint TestModule.podspec --allow-warnings(忽略警告)
// 如果依赖私有库,加私有库的sources,sources可以是多个,后面以逗号隔开即可
pod spec lint LNLogin.podspec --sources=https://github.com/CocoaPods/Specs.git(公有库), https://github.com/NoNameOrganazation/MySpecs.git(私有库) -allow-warnings

遇到未知错误可以加上--verbose打印更详细的日志信息。
校验成功即可更新到私有pod仓库。

7、更新私有pod
pod repo push nonameorganazation TestModule.podspec --use-libraries 
或
pod repo push nonameorganazation TestModule.podspec --use-libraries --allow-warnings(忽略警告)

遇到未知错误可以加上--verbose打印更详细的日志信息。

8、使用自己创建的私有pod库;

需要在Podfile 指定source ,包括公有source和私有source:

source 'https://github.com/CocoaPods/Specs.git'
source 'https://github.com/NoNameOrganazation/LNSpec.git'

使用Pod过程中遇到的一些问题

  • 在执行本地检查命令pod lib lint TestModule.podspec 时遇到如下错误:
- ERROR | [iOS] xcodebuild: Returned an unsuccessful exit code.

这种问题没有一般没有明确的错误代码源,通常是一些依赖的问题。子模块间依赖也要处理好。避免循环依赖或依赖缺失。

  • 的cocoapods版本更新的问题
    更新版本执行如下命令:
    sudo gem install cocoapods 和
    sudo gem install -n /usr/local/bin cocoapods
    都报如下错误:
You don't have write permissions for the /System/Library/Frameworks/Ruby.framework/Versions/2.6

很明显没有修改权限。可以通过Homebrew安装新的ruby:

brew install ruby

然后指定本地ruby指向brew安装的ruby:

export PATH="/usr/local/opt/ruby/bin:$PATH"

然后在执行:

sudo gem install -n /usr/local/bin cocoapods

就成功安装了cocoapods。

Homebrew常用命令:

brew install 安装,比如brew install ruby
brew uninstall 卸载,比如 brew uninstall cocoapods
brew list 安装列表
brew outdated 需要更新的包
brew update 更新自身
brew upgrade 更新由brew安装的包,也可指定更新的包名,如:
brew upgrade ruby
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342

推荐阅读更多精彩内容