随着应用需求逐步迭代,应用的代码体积将会越来越大,为了更好的管理应用工程,我们开始借助CocoaPods版本管理工具对原有应用工程进行拆分。但是仅仅完成代码拆分还不足以解决业务之间的代码耦合,为了更好的让拆分出去的业务工程能够独立运行,必须进行组件拆分并且实现组件服务化。
1.组件和组件之间没有明确的约束。
2.组件单独开发、单独测试,不能揉入主项目中开发,测试也可以针对性的测试。
由于本人的习惯,喜欢把很复杂的问题大白话化。组件是什么?它就是通过CocoaPods来管理的几个文件,它能实现特定的功能。通常它都采用的私有库和私有源,不然大伙都可以看到你的代码。当然也有的组件本来就是为了开源的,开源的库通常放在公有源上。
组件化主要为了解决不同app代码重复性问题,便于维护,其次为了代码功能清晰。当组件更新,各个app只需要执行pod update就把组件的功能代码更新了,不用每个app重新导入或修改相同的代码了。新建app只需要配置Podfile文件,执行pod update命令就能把组件导入过来大大提高了开发效率。每个组件实现特定的功能,不用在一堆业务代码中翻找不同的功能代码了,你说代码功能能不清晰吗?
组件主要分三类:基础功能组件,基础UI组件,产品业务组件
1.独立的私有库形式,它又分两种:
1.1.基础功能组件:(类似于性能统计、Networking、网络诊断、定制Categories安全处理扩展类组件等)
按功能分库,不涉及产品业务需求,跟库Library类似
通过良好的接口拱上层业务组件调用;
不写入产品定制逻辑,通过扩展接口完成定制;
1.2. 基础UI组件:(例如下拉刷新组件、弹出框组件、小菊花组件、选择框组件等)
产品内通用UI组件;(各个业务模块依赖使用,但需要保持好定制扩展的设计)
公共通用UI组件;(不涉及具体产品的视觉设计, 目前较少)
2.封装的sdk。
3. 产品业务组件:(例如支付组件、分享组件、页面管理组件、评价组件、版本更新组件、WebSocket等长连接组件)
业务功能间相对独立,相互间没有Model共享的依赖;
业务之间的页面调用只能通过UIBus进行跳转;
业务之间的逻辑Action调用只能通过服务提供;
网络组件可以只包含对AFNetworking的进一步抽象,以便于更简单的使用。它比使用扩展类写在一个文件里的可读性要强的多。几个相关的请求在一个类文件里比所有的请求都在一个类文件里,大家想像就知道那个更合理。
本文主要的内容是组件化的实现,不是讲组件化的代码具体实现的,关于组件化代码实现以后再说。
你可以这样理解,就是想把几个.h和.m等文件怎么用CocoaPods把它变成私有库,指定的成员可以下载。大公司都是自己搭建的GitLab服务器。小公司大都使用的是git服务器。当然自己搭建的服务器上传下载要比git服务器要快的多。本文主要以git服务器为示例,所有***需要你换成自己的路径和文件,工程名。
以前在大公司都是比人专门建立了私有源和环境,自己上传组件就可以。当了新公司要当拓荒者一个人实现组件化,遇到问题不是一般的大,一个很小的问题就卡了我两周。从零开始组件化你才能充分理解组件化的重要和本质。
下面是实现组件化的步骤。
- 你首先要安装CocoaPods。网上一抓一大把,你慢慢学习去吧!不过我遇到一个奇靶的问题。我以前装CocoaPods装了一半失败了,以后怎么装也装不成功。后来把它卸载了再装才成功。
- 在git服务器上建立你自己私有源,就是存放podspec文件的地方。注意:创建时一定要勾选Initialize this repository with a README前面勾选。我就是开始忘记忘记勾选这个选型,上传了两周私有源全部失败。空工程无法使用pod repo push推送本地私有源到远程私有源。若忘记了,你可以删除这个私有源再重新创建并勾选这个选项。当然若因为各种原因不能删除,那么你就用git下载工程到本地,给它传一个说明文件吧!当然你也可以用命令创建。
echo “# TencentBugly” >> README.md
git init
git add README.md
git commit -m “first commit”
git remote add origin https://github.com/****/TencentBugly.git
git push -u origin master
这个TencentBugly是你要创建的私有源的名字,你修改成你自己的私有源的名称就可以。
- 创建本地私有源。
pod repo add YiXiangSpec https://github.com//.git - 在git服务器上建立你自己私有代码库,下载到本地,通常在本地需要建立一个工程,这个工程的主要目的是检查是否代码是否能编译和运行,当然也可以包含对该模块的测试代码。增加***.podspec。注意:配置文件中不能有中文标点符号,或者会编译不通过。
- 上传代码到私有库地址,并且打标签,注意一定要勾选推送标签:origin 。
一般一个指定组件都是一个人维护,所以一般都是指直接推送到master主分支。
- 在***.podspec所在文件路径下执行代码检查,告警一般可以忽略(–allow-warnings)。例如:pod spec lint ModuleManager.podspec --allow-warnings --use-libraries
注意:若是本组件需要访问私有源和公有源都需要加上。例如:pod spec lint YXRequestManager.podspec --sources=‘https://github.com//.git,https://github.com/CocoaPods/Specs.git’ --allow-warnings
编译成功的例子:
podspec --allow-warnings --use-libraries
-> ModuleManager (0.0.1)
Analyzed 1 podspec.
ModuleManager.podspec passed validation.
7. 编译检查通过,推送到私有源和私有库。例如:pod repo push *** ModuleManager.podspec --allow-warnings
注意:若是本组件需要访问私有源和公有源都需要加上。例如:pod repo push YiXiangSpec YXPayManager.podspec --sources=‘https://github.com//.git,https://github.com/CocoaPods/Specs.git’ --allow-warnings --use-libraries
若你的组件有几百兆(如通信基础组件),可能需要很常时间,毕竟git服务器在国外,大家耐心等待吧!
上传成功的例子
jiaguoshangdeMacBook-Air:ModuleManager jiaguoshang$ pod repo push *** ModuleManager.podspec --allow-warnings
Validating spec
-> ModuleManager (0.0.2)
Updating the `***’ repo
Already up to date.
Adding the spec to the `***’ repo
- [Add] ModuleManager (0.0.2)
Pushing the `***’ repo
注意:你下载时,以公有源映射的库优先,其次是私有源映射的组件。由于共有源上已经有一个ModuleManager的第三方库,你若你的私有源上的这个组件也叫ModuleManager,那么你用pod update下载时,下载的事公有源上的那个swift版本的第三方库。
8. 在项目所在文件夹修改或创建Podfile文件,增加你的组件。
9.使用pod update更新组件,若你以前已经执行过,只是想对新加的这个三方库进行下载。可以使用这个命令来提高更新速度:pod update --verbose --no-repo-update。
若有新加的组件或第三方库,需要关闭工程再打开工程才能生效。
10.若你已经下载这个第三方库,有时候你使用pod update命令可能下载的别人的组件是老版本的,更新不到老版本,可以先在Podfile文件中注释掉(#pod ‘MLeaksFinder’,‘0.2.1’)对应组件,再pod update --verbose --no-repo-update;再打开在Podfile文件中去掉注释,再pod update --verbose --no-repo-update就能下载别人的组件的最新版本了,估计这个是本地私有源的问题。若这个库就是在本电脑更新的库,再更新现在的肯定是最新版本。
下面是包含私有源和公有源的Podfile文件例子:
Uncomment this line to define a global platform for your project
source ‘https://github.com/enjoyor-runlu/***.git’
source ‘https://github.com/CocoaPods/Specs.git’
platform :ios, “8.0”
target ‘ArtEnjoymentWeChatAuction’ do
Uncomment this line if you’re using Swift or would like to use dynamic frameworks
use_frameworks!
Pods for ***
pod 'YXFDCategories'
##################################第三方###########################
#YYModel--数组转模型组件
pod 'YYModel', '1.0.4'
#YYCategories--给系统类添加的分类
pod 'YYCategories', '1.0.4'
#内存泄漏检测,正式环境需要注释下面一行
pod 'MLeaksFinder','0.2.1'
end
下面是一个简单的一个只包含Classes文件夹下的.h和.m文件的组件管理组件的配置文件(ModuleManager.podspec):
Any lines starting with a # are optional, but their use is encouraged
To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html
Pod::Spec.new do |s|
s.name = ‘ModuleManager’
s.version = ‘0.0.2’
s.summary = ‘ModuleManager.’
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 = ‘http://www.baidu.com/’
s.screenshots = ‘www.example.com/screenshots_1’, ‘www.example.com/screenshots_2’
s.license = { :type => ‘MIT’, :file => ‘LICENSE’ }
s.author = { ‘jiaguoshang’ => ‘@163.com’ }
s.source = { :git => 'https://github.com/**/ModuleManager.git’, :tag => s.version.to_s }
s.social_media_url = ‘https://twitter.com/<TWITTER_USERNAME>’
s.ios.deployment_target = ‘8.0’
s.source_files = 'ModuleManager/Classes/.{h,m}’
#s.source_files = “ModuleManager”, "'ModuleManager/**/.{h,m}"
s.resource_bundles = {
‘ModuleManager’ => [‘ModuleManager/Assets/*.png’]
}
s.public_header_files = ‘Pod/Classes/**/*.h’
s.frameworks = ‘UIKit’, ‘Foundation’
s.dependency ‘AFNetworking’, ‘~> 2.3’
end
下面是一个既依赖私有库又依赖公有库的配置文件(YXRequestManager.podspec):
Be sure to run `pod lib lint YXRequestManager.podspec’ to ensure this is a
valid spec before submitting.
Any lines starting with a # are optional, but their use is encouraged
To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html
Pod::Spec.new do |s|
s.name = ‘YXRequestManager’
s.version = ‘1.1.9’
s.summary = ‘YXRequestManager.’
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 = ‘http://www.baidu.com/’
s.screenshots = ‘www.example.com/screenshots_1’, ‘www.example.com/screenshots_2’
s.license = { :type => ‘MIT’, :file => ‘LICENSE’ }
s.author = { ‘jiaguoshang’ => ‘***@163.com’ }
s.source = { :git => ‘https://github.com/enjoyor-runlu/YXRequestManager.git’, :tag => s.version.to_s }
s.social_media_url = ‘https://twitter.com/<TWITTER_USERNAME>’
s.ios.deployment_target = ‘8.0’
s.source_files = ‘YXRequestManager/Classes/**/*.{h,m}’
s.source_files = ‘YXCache’, ‘YXRequestManager/Classes/YXCache/*.{h,m}’,
s.source_files = ‘AESCategory’, ‘YXRequestManager/Classes/AESCategory/*.{h,m}’
s.source_files = ‘YXRequest’, ‘YXRequestManager/Classes/YXRequest/*.{h,m}’
#s.source_files = “YXRequestManager”, "YXRequestManager/**/.{h,m}"
s.resource_bundles = {
‘YXRequestManager’ => ['YXRequestManager/Classes/.xcassets’]
}
s.public_header_files = ‘Pod/Classes/**/*.h’
s.frameworks = ‘UIKit’, ‘Foundation’
s.dependency ‘YXFDCategories’
s.dependency ‘AFNetworking’, ‘3.1.0’
s.dependency ‘TMCache’
end