iOS 组件化-使用cocoapods集成实战演练

背景

之前写过一篇 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库的处理

参考: 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做组件化集成实践的一些总结和遇到的一些问题,希望对有需要的朋友有帮助。

参考链接

cocoapods项目主页

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

推荐阅读更多精彩内容