Pod組件開發(fā)的流程和常用配置

創(chuàng)建SDK項(xiàng)目

1、打開終端到相應(yīng)的目錄下執(zhí)行pod lib create sdkName,sdkName是SDK名稱,執(zhí)行之后看到如下信息:

 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、選擇平臺(tái),根據(jù)提示輸入iOS或者macOS,這里我們選擇iOS:

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

3、選擇編程語言。這里我們選擇ObjC,執(zhí)行:

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

4、選擇是否需要demo。為了方便自測,我們需要一個(gè)demo,選擇Yes、執(zhí)行:

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

5、選擇測試框架。這里我們選著None,繼續(xù)執(zhí)行:

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

6、選擇是否需要集成基于view的測試框架。這里我們選擇No,繼續(xù)執(zhí)行:

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

7、設(shè)置項(xiàng)目代碼前綴。這里根據(jù)自己需要設(shè)置,也可以不設(shè)置。執(zhí)行之后就會(huì)創(chuàng)建并自動(dòng)打開一個(gè)xcode工程:

What is your class prefix?
 >

8、工程結(jié)構(gòu)


1630031969818.jpg

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

Example是demo。SDK源碼目錄在TestSDK->Classes,資源文件TestSDK->Assets。
9、自動(dòng)生成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開發(fā)

SDK源碼編寫

在TestSDK->Classes目錄下添加代碼文件。當(dāng)資源文件代碼文件或者podspec有更新時(shí)直接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'

  # 依賴的系統(tǒng)frameworks
  s.frameworks = 'UIKit', 'MapKit'
  # 依賴的系統(tǒng).a文件
  s.libraries = 'c++', 'resolv', 'stdc++.6.0.9'

  # 通過Pod依賴的第三方庫,多個(gè)庫就多個(gè)s.dependency
  s.dependency 'AFNetworking', '~> 2.3'
  s.dependency 'SDWebImage'

  # 手動(dòng)依賴第三方framework
  s.vendored_frameworks = 'Classes/b/*.framework', 'TestSDK/Classes/a/*.framework'
  # 手動(dòng)依賴第三方.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為靜態(tài)庫
  s.static_framework = true
  
  #支持系統(tǒng)版本
  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對(duì)外開放的頭文件,如果我們不指定的話,默認(rèn)就是源代碼的全部頭文件。所以我們要根據(jù)自己需要,開放指定目錄下的頭文件:

  # public頭文件
  s.public_header_files = 'Classes/**/*.h'
依賴庫管理

依賴庫系統(tǒng)庫和第三方依賴庫。系統(tǒng)庫都可以通過podspec自動(dòng)依賴;第三方依賴庫依賴包括手動(dòng)依賴和通過Pod自動(dòng)依賴。

  • 依賴系統(tǒng)庫
  # 依賴的系統(tǒng)frameworks
  s.frameworks = 'UIKit', 'MapKit'
  # 依賴的系統(tǒng).a文件
  s.libraries = 'c++', 'resolv', 'stdc++.6.0.9'
  • 通過Pod自動(dòng)依賴第三方庫(第三方庫支持)。
  # 通過Pod依賴的第三方庫,多個(gè)庫就多個(gè)s.dependency
  s.dependency 'AFNetworking', '~> 2.3'
  s.dependency 'SDWebImage'
  • 手動(dòng)依賴第三方庫
    首先得為第三方庫創(chuàng)建一個(gè)目錄,然后通過podspec指定相應(yīng)的路徑進(jìn)行依賴:
# 手動(dòng)依賴第三方framework
  s.vendored_frameworks = 'Classes/b/*.framework', 'TestSDK/Classes/a/*.framework'
  # 手動(dòng)依賴第三方.a文件
  s.vendored_libraries = 'Classes/a/*.a','Classes/b/*.a'
資源管理

資源管理有兩種方式,分別是 resource_bundles 和 resources 兩種方式引用。

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

使用 resources 之后只會(huì)簡單的將資源文件 copy 到目標(biāo)工程(Example 工程),最后和目標(biāo)工程的圖片文件以及其他同樣使用 resources 的 Pod 的圖片文件,統(tǒng)一一起打包為了一個(gè) Assets.car。使用 resources,如果出現(xiàn)同名的圖片,顯然是會(huì)出現(xiàn)沖突的。
resources 優(yōu)點(diǎn):

可以使用 .xcassets 指定資源文件;
不需要用硬編碼方式獲取圖片。

resources 缺點(diǎn):

可能會(huì)導(dǎo)致每個(gè)庫和主工程之間的同名資源沖突;

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

所以,一般來說使用 resource_bundles 會(huì)更好,不過關(guān)于硬編碼,還可以再找找別的方式去避免。

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

使用 resource_bundles 之后會(huì)為為指定的資源打一個(gè) .bundle,.bundle包含一個(gè) Assets.car,獲取圖片的時(shí)候要嚴(yán)格指定 .bundle 的位置,很好的隔離了各個(gè)庫或者一個(gè)庫下的資源包。避免資源同名沖突。
resource_bundles 優(yōu)點(diǎn):

可以使用 .xcassets 指定資源文件
可以避免每個(gè)庫和主工程之間的同名資源沖突

resource_bundles 缺點(diǎn):

獲取圖片時(shí)可能需要使用硬編碼的形式來獲取,比如想訪問TestResourceBundle的資源:
[[NSBundle bundleForClass:[self class]].resourcePath stringByAppendingPathComponent:@"/TestResourceBundle.bundle"]

子模塊subspec配置

subspec就相當(dāng)于SDK中的一個(gè)組件。如果我們想把SDK分層不同的模塊,使得app在引用SDK時(shí)可以按需加載,就可以使用subspec。子模塊跟主的spec是一樣的,可以理解為它也是一個(gè)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、依賴庫等等。子模塊內(nèi)部也可以在劃分子模塊,也可以引用其他子模塊,但是要注意循環(huán)引用的問題。
那么在Podfile引用的時(shí)候可以是:

pod TestSDK/ModelA 

內(nèi)部子模塊的依賴,如:

 # 子模塊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、注冊(cè)Trunk賬戶

注冊(cè)Trunk賬戶(郵箱地址建議寫成github注冊(cè)的郵箱,用戶名寫成github對(duì)應(yīng)的用戶名),例如在終端輸入:

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

注冊(cè)命令執(zhí)行完之后,對(duì)應(yīng)的郵箱地址會(huì)收到一封郵件,“請(qǐng)確認(rèn)您的注冊(cè)CocoaPods通過點(diǎn)擊以下鏈接:”,打開鏈接地址完成驗(yàn)證,如果地址不能點(diǎn)擊就直接粘貼URL到瀏覽器上執(zhí)行。

注冊(cè)完成之后可以通過pod trunk me查看注冊(cè)信息。

2、提交代碼到git,并打tag,用tag作版本號(hào)

(.podspec, LICENSE 這兩個(gè)文件必須提交到git上)
git add .
git commit -m “1.0.0”
git push
git tag 1.0.0
git push –tags

3、提交之前先驗(yàn)證.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

只要驗(yàn)證通過,提交時(shí)一般沒有什么問題, 一般會(huì)卡在“Updating spec repo ‘master’”, 這時(shí)不要關(guān)閉終端。

5、查找提交成功的庫

先重置一下cocoapods:

pod setup

然后搜索剛才提交的SDK名稱:

pod search TestSDK

如果查不到會(huì)報(bào)錯(cuò)如下 [!] Unable to find a pod with name, author, summary, or description matching。
解決方案: 先刪除search_index.json文件,然后再search (文件不存在時(shí)會(huì)自動(dòng)下載,根據(jù)不同的網(wǎng)絡(luò)可能要花一會(huì)時(shí)間,要等)。

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

Pod私有庫創(chuàng)建

1、創(chuàng)建一個(gè)spec Repo的私有遠(yuǎn)程倉庫和一個(gè)存放pod所需的項(xiàng)目工程文件的遠(yuǎn)程倉庫;

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

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

通過 cd ~/.cocoapods/repos 可以進(jìn)入到podspec本地目錄,并能看到nonameorganazation目錄

2、通過pod創(chuàng)建一個(gè)本地庫
pod lib create TestModule
3、創(chuàng)建一個(gè)組件的git倉庫,指定組件的Git地址
git remote add origin https://github.com/dongjianxiong/NoNameOrganazation/TestModule.git

會(huì)自動(dòng)生成一個(gè)TestModule.podspec, 編寫podspec。

4、本地檢查podspec的有效性
pod lib lint TestModule.podspec 
或
pod lib lint TestModule.podspec --allow-warnings(忽略警告)
// 如果依賴私有庫,加私有庫的sources,sources可以是多個(gè),后面以逗號(hào)隔開即可
pod lib lint TestModule.podspec --sources=https://github.com/CocoaPods/Specs.git(公有庫), https://github.com/NoNameOrganazation/LNSpec.git(私有庫) -allow-warnings
5、設(shè)置podspec版本號(hào)

設(shè)置podspec的版本號(hào)后,通過打tag或分支命名為版本號(hào)。每次更新組件的版本號(hào)都要更新podspec的版本號(hào)(s.version)。比如:

git tag 0.1.0
git push origin 0.1.0
6、遠(yuǎn)端檢查podspec的有效性
pod spec lint TestModule.podspec
或
pod spec lint TestModule.podspec --allow-warnings(忽略警告)
// 如果依賴私有庫,加私有庫的sources,sources可以是多個(gè),后面以逗號(hào)隔開即可
pod spec lint LNLogin.podspec --sources=https://github.com/CocoaPods/Specs.git(公有庫), https://github.com/NoNameOrganazation/MySpecs.git(私有庫) -allow-warnings

遇到未知錯(cuò)誤可以加上--verbose打印更詳細(xì)的日志信息。
校驗(yàn)成功即可更新到私有pod倉庫。

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

遇到未知錯(cuò)誤可以加上--verbose打印更詳細(xì)的日志信息。

8、使用自己創(chuàng)建的私有pod庫;

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

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

使用Pod過程中遇到的一些問題

  • 在執(zhí)行本地檢查命令pod lib lint TestModule.podspec 時(shí)遇到如下錯(cuò)誤:
- ERROR | [iOS] xcodebuild: Returned an unsuccessful exit code.

這種問題沒有一般沒有明確的錯(cuò)誤代碼源,通常是一些依賴的問題。子模塊間依賴也要處理好。避免循環(huán)依賴或依賴缺失。

  • 的cocoapods版本更新的問題
    更新版本執(zhí)行如下命令:
    sudo gem install cocoapods 和
    sudo gem install -n /usr/local/bin cocoapods
    都報(bào)如下錯(cuò)誤:
You don't have write permissions for the /System/Library/Frameworks/Ruby.framework/Versions/2.6

很明顯沒有修改權(quán)限??梢酝ㄟ^Homebrew安裝新的ruby:

brew install ruby

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

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

然后在執(zhí)行:

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
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容