iOS 元件化 使用cocoapods整合實戰演練

aron1992發表於2019-04-04

背景

之前寫過一篇 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' => '862709539@qq.com' }
    # 提交到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' => '862709539@qq.com' }
    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庫的處理

參考: guides.cocoapods.org/syntax/pods…
podspec檔案新增新增

s.vendored_frameworks = 'PTDataModule/Frameworks/*.framework'
複製程式碼

ARC環境中配置非ARC檔案

需要用到podspec規則中的subspec和requires_arc
參考:
guides.cocoapods.org/syntax/pods…
guides.cocoapods.org/syntax/pods…

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

參考: guides.cocoapods.org/syntax/pods…

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檔案中

可以使用這種方式,直接把需要匯入的標頭檔案使用引數的方式指定
參考:
guides.cocoapods.org/syntax/pods…

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開發庫依賴本地開發庫的問題

參考:
stackoverflow.com/questions/1…
比如Pod開發庫A依賴Pod開發庫B,依賴的資訊填寫如下即可,不需要指定路徑獲取其他資訊

s.dependency 'DevLibB'
複製程式碼

在測試工程或者客戶端工程的的podfile檔案中需要顯示的匯入DevLibB,這樣即可

pod 'DevLibB', :path => '../../DevLibB'
複製程式碼

原始檔沒有配置對會找不到

subspec.source_files = 'PTThirdPlatformKit/WeiboManager/**/*'
複製程式碼

如果配置(如下所示)是錯誤的路徑,在客戶端是找不到這個類的,需要檢查原始檔配置的是否正確

subspec.source_files = 'PTThirdPlatformKit/WeiboManager111/**/*'
複製程式碼

總結

以上是我在使用cocoapods做元件化整合實踐的一些總結和遇到的一些問題,希望對有需要的朋友有幫助。

參考連結

cocoapods專案主頁

相關文章