背景
之前寫過一篇 iOS 組件化實現的一些思路總結 ,這篇作爲續集,聊一聊使用 Cocoapods
在iOS平臺組件化的實現和集成。
結果
本文中的兩個例子可以在 YTThirdPlatformManager 項目中找到。
工具介紹
Cocoapods
是iOS/osx平臺的開發庫管理工具,簡單的配置然後執行安裝命令 Cocoapods
會自動去下載第三方庫並且做好相應的配置,簡化了引入第三方庫的流程,讓開發更簡單高效,是iOS開發的必備工具,使用 Cocoapods
作爲組件化的工具是一個不錯的選擇。
安裝和設置
安裝和設計可以參考這篇文章: Cocopods安裝和升級備忘錄
實現
簡單項目組件化
以一個測試模塊解耦的場景實現簡單項目的組件化,主要包含以下內容
- Pod庫項目創建
- 最基礎podspec文件的編寫的解釋
- 客戶端集成
創建項目
使用 pod lib create
創建項目,會遇到幾個需要輸入的地方,具體的解釋看代碼段中的註釋
➜ DevPods pod lib create PTTestKit
Cloning `https://github.com/CocoaPods/pod-template.git` into `PTTestKit`.
Configuring PTTestKit 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:
- http://guides.cocoapods.org/making/using-pod-lib-create.html
( hold cmd and double click links to open in a browser. )
# 使用的語言
What language do you want to use?? [ Swift / ObjC ]
> Objc
# 是否包好測試工程,指定YES用於模塊化的解耦測試
Would you like to include a demo application with your library? [ Yes / No ]
>
yes
# 集成的測試模塊,不需要指定None
Which testing frameworks will you use? [ Specta / Kiwi / None ]
> None
# UI測試模塊,不需要指定No
Would you like to do view based testing? [ Yes / No ]
> No
# 指定類前綴
What is your class prefix?
> PT
Running pod install on your new library.
podspec 文件編寫
一個簡單的 podspec 文件如下,具體字段的解釋查看代碼中的註釋即可
Pod::Spec.new do |s|
s.name = 'PTTestKit'
s.version = '0.1.0'
s.summary = 'Wow PTTestKit.'
# 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
Wow this is a amazing kit,
Enjoy yourself!
DESC
# 提交到git服務區的項目主頁,沒提交可以指定任意值,但需要保留這一項,否則會報錯
# attributes: Missing required attribute `homepage`.
s.homepage = 'https://github.com/flypigrmvb/PTTestKit'
# s.screenshots = 'www.example.com/screenshots_1', 'www.example.com/screenshots_2'
# 授權文件
s.license = { :type => 'MIT', :file => 'LICENSE' }
# 用戶信息
s.author = { 'flypigrmvb' => '[email protected]' }
# 提交到git上的源碼路徑,沒提交可以指定任意值,但需要保留這一項,否則會報錯
# attributes: Missing required attribute `source`.
s.source = { :git => 'https://github.com/flypigrmvb/PTTestKit.git', :tag => s.version.to_s }
# s.social_media_url = 'https://twitter.com/<TWITTER_USERNAME>'
# 指定最低的ios版本
s.ios.deployment_target = '8.0'
# 源文件的路徑
s.source_files = 'PTTestKit/Classes/**/*'
# 公共的頭文件,按需設置
s.public_header_files = 'PTTestKit/Classes/Public/**/*.h'
# 私有的頭文件,按需設置
s.private_header_files = 'PTTestKit/Classes/Private/**/*.h'
# 依賴的系統Framework,按需設置
# s.frameworks = 'UIKit', 'MapKit'
# 依賴其他的pod庫,按需設置
# s.dependency 'AFNetworking', '~> 2.3'
end
客戶端集成
如果在創建Pod庫項目的步驟集成了 Example 測試項目,在測試項目下的podfile默認包含了當前的Pod庫項目
#use_frameworks!
target 'PTTestKit_Example' do
pod 'PTTestKit', :path => '../'
target 'PTTestKit_Tests' do
inherit! :search_paths
end
end
切換到測試項目目錄下,運行 pod install
命令,完了之後測試項目集成了Pod項目。下面是在測試項目中使用Pod庫項目中一些功能的簡單例z
#import "PTViewController.h"
#import <PTTestKit/PublicFile.h>
// !!private header 可以導入
#import <PTTestKit/PrivateFile.h>
// !!報錯
//#import <PTTestKit/ProjectFile.h>
@interface PTViewController ()
@end
@implementation PTViewController
- (void)viewDidLoad
{
[super viewDidLoad];
[self addActionWithName:@"Test" callback:^{
NSLog(@"====");
}];
[self addActionWithName:@"PrivateFile" callback:^{
[PrivateFile test];
}];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[PrivateFile test];
}
@end
分模塊組件化
以一個第三發組件集成的場景爲例,實現分模塊組件化,主要包含以下內容:
- 創建核心模塊
- 創建子模塊
- 客戶端集成
pod庫項目的創建流程和簡單模塊組件步驟一致,不在贅述
podspec 文件編寫
該文件創建了一個Core模塊,用於存放抽象的接口、基類以及一些公用的工具類和頭文件,以及幾個子模塊用於具體的第三方平臺的實現。具體的內容可以查看以下代碼中的註釋內容
Pod::Spec.new do |s|
s.name = 'PTThirdPlatformKit'
s.version = '0.1.0'
s.summary = 'A short description of PTThirdPlatformKit.'
# 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/flypigrmvb/PTThirdPlatformKit'
# s.screenshots = 'www.example.com/screenshots_1', 'www.example.com/screenshots_2'
s.license = { :type => 'MIT', :file => 'LICENSE' }
s.author = { 'flypigrmvb' => '[email protected]' }
s.source = { :git => 'https://github.com/flypigrmvb/PTThirdPlatformKit.git', :tag => s.version.to_s }
# s.social_media_url = 'https://twitter.com/<TWITTER_USERNAME>'
s.ios.deployment_target = '8.0'
# 設置默認的模塊,如果在pod文件中導入pod項目沒有指定子模塊,導入的是這裏指定的模塊
s.default_subspec = 'Core'
# 定義一個核心模塊,用戶存放抽象的接口、基類以及一些公用的工具類和頭文件
s.subspec 'Core' do |subspec|
# 源代碼
subspec.source_files = 'PTThirdPlatformKit/Classes/**/*'
# 配置系統Framework
subspec.frameworks = 'CoreMotion'
subspec.dependency 'SDWebImage'
# 添加依賴的系統靜態庫
subspec.libraries = 'xml2', 'z', 'c++', 'stdc++.6', 'sqlite3'
end
# 支付寶模塊
s.subspec 'AlipayManager' do |subspec|
# 源代碼
subspec.source_files = 'PTThirdPlatformKit/AlipayManager/**/*'
# 添加資源文件
subspec.resource = 'PTThirdPlatformKit/AlipayManager/**/*.bundle'
# 添加依賴第三方的framework
subspec.vendored_frameworks = 'PTThirdPlatformKit/AlipayManager/**/*.framework'
# 添加依賴系統的framework
subspec.frameworks = 'CoreTelephony', 'SystemConfiguration'
# 依賴的核心模塊
subspec.dependency 'PTThirdPlatformKit/Core'
end
# QQ模塊
s.subspec 'TencentManager' do |subspec|
# 源代碼
subspec.source_files = 'PTThirdPlatformKit/TencentManager/**/*'
# 添加資源文件
subspec.resource = 'PTThirdPlatformKit/TencentManager/**/*.bundle'
# 添加依賴第三方的framework
subspec.vendored_frameworks = 'PTThirdPlatformKit/TencentManager/**/*.framework'
# 添加依賴系統的framework
subspec.frameworks = 'SystemConfiguration'
# 依賴的核心模塊
subspec.dependency 'PTThirdPlatformKit/Core'
end
# 微博模塊
s.subspec 'WeiboManager' do |subspec|
# 源代碼
subspec.source_files = 'PTThirdPlatformKit/WeiboManager/**/*'
# 依賴的微博pod庫
subspec.dependency 'WeiboSDK'
subspec.dependency 'PTThirdPlatformKit/Core'
end
# 微信模塊
s.subspec 'WXManager' do |subspec|
# 源代碼
subspec.source_files = 'PTThirdPlatformKit/WXManager/**/*'
# 依賴的微信pod庫
subspec.dependency 'WechatOpenSDK'
subspec.dependency 'PTThirdPlatformKit/Core'
end
end
客戶端集成
podfile文件如下,可以導入主模塊和任意的子模塊的組合
#use_frameworks!
platform :ios, '8.0'
target 'PTThirdPlatformKit_Example' do
pod 'PTTestKit', :path => '../../PTTestKit'
# 主模塊
pod 'PTThirdPlatformKit', :path => '../'
# 子模塊快
pod 'PTThirdPlatformKit/AlipayManager', :path => '../'
pod 'PTThirdPlatformKit/TencentManager', :path => '../'
pod 'PTThirdPlatformKit/WeiboManager', :path => '../'
pod 'PTThirdPlatformKit/WXManager', :path => '../'
end
target 'PTThirdPlatformKit_Example_Developer' do
pod 'PTTestKit', :path => '../../PTTestKit'
pod 'PTThirdPlatformKit', :path => '../'
pod 'PTThirdPlatformKit/AlipayManager', :path => '../'
pod 'PTThirdPlatformKit/TencentManager', :path => '../'
pod 'PTThirdPlatformKit/WeiboManager', :path => '../'
pod 'PTThirdPlatformKit/WXManager', :path => '../'
end
遇到問題
開發中的Pod庫依賴另一個Pod庫的處理
參考: https://guides.cocoapods.org/syntax/podspec.html#vendored_frameworks
podspec文件添加添加
s.vendored_frameworks = 'PTDataModule/Frameworks/*.framework'
ARC環境中配置非ARC文件
需要用到podspec規則中的subspec和requires_arc
參考:
https://guides.cocoapods.org/syntax/podspec.html#requires_arc
https://guides.cocoapods.org/syntax/podspec.html#subspec
s.requires_arc = true
# no arc files rules
non_arc_files = 'PTDataModule/Classes/**/JSONKit.{h,m}'
s.exclude_files = non_arc_files
s.subspec 'no-arc' do |sna|
sna.requires_arc = false
sna.source_files = non_arc_files
end
PrefixHeader
參考: https://guides.cocoapods.org/syntax/podspec.html#prefix_header_file
podspec指定 PTDataModule-prefixheader.pch 文件
s.prefix_header_file = 'PTDataModule/SupportFiles/PTDataModule-prefixheader.pch'
PTDataModule-prefixheader.pch 文件內容
#import "UtilMacro.h"
#import "DebugConfig.h"
#import "TIMAdapter.h"
有個坑,使用pod install 之後自定義的pch文件在項目中找不到了,但是內容會添加到PTDataModule-prefix.pch文件中
可以使用這種方式,直接把需要導入的頭文件使用參數的方式指定
參考:
https://guides.cocoapods.org/syntax/podspec.html#prefix_header_contents
spec.prefix_header_contents = '#import <UIKit/UIKit.h>', '#import <Foundation/Foundation.h>'
Pod 更新不成功問題
[!] The 'Pods-PTThirdPlatformKit_Example' target has transitive dependencies that include static binaries: (/Users/aron/PuTaoWorkSpace/Plush_devpods_developer/DevPods/PTThirdPlatformKit/Example/Pods/WechatOpenSDK/OpenSDK1.8.0/libWeChatSDK.a and /Users/aron/PuTaoWorkSpace/Plush_devpods_developer/DevPods/PTThirdPlatformKit/Example/Pods/WeiboSDK/libWeiboSDK/libWeiboSDK.a)
解決辦法:
#use_frameworks! (註釋這個)
添加.a靜態庫和對應的頭文件 PTBehaviorStat
s.public_header_files = 'PTBehaviorStat/Classes/**/*.h', 'PTBehaviorStat/vendor/**/*.h'
s.vendored_library = 'PTBehaviorStat/**/*.a'
pod lib create 創建庫拉取GitHub模板數據慢的問題
--template 參數指定本地的 模板數據
Pod開發庫依賴本地開發庫的問題
參考:
https://stackoverflow.com/questions/16905112/cocoapods-dependency-in-pod-spec-not-working
比如Pod開發庫A依賴Pod開發庫B,依賴的信息填寫如下即可,不需要指定路徑獲取其他信息
s.dependency 'DevLibB'
在測試工程或者客戶端工程的的podfile文件中需要顯示的導入DevLibB,這樣即可
pod 'DevLibB', :path => '../../DevLibB'
源文件沒有配置對會找不到
subspec.source_files = 'PTThirdPlatformKit/WeiboManager/**/*'
如果配置(如下所示)是錯誤的路徑,在客戶端是找不到這個類的,需要檢查源文件配置的是否正確
subspec.source_files = 'PTThirdPlatformKit/WeiboManager111/**/*'
總結
以上是我在使用cocoapods做組件化集成實踐的一些總結和遇到的一些問題,希望對有需要的朋友有幫助。