最近在研究组件化,发现网上的资料有很多,很详细,可是看的越多感觉越懵😳,我现在需要的是尽量简单化,于是就有了这一篇实战贴,简单实用!
一、简介
定义
简单来说,组件化
就是将一个APP
中的代码进行抽取,分成若干个项目,然后按照cocoapods
的方式进行组织,形成一个拥有完整业务逻辑的工程。也就是说一个组件就是一个可以独立运行的项目。它就是用来解耦
的,当你的APP业务越来越庞大的时候,就需要将业务隔离
,独立开发
。
优缺点
优点
- 组件的
独立性
,各组件独立开发,互不影响,可以减少提交代码时的冲突- 资源重用,将于业务无关的代码抽离出来放在一个基础组件中
- 高效迭代
- 配合二进制,可以加快项目的编译速度
缺点
- 开发起来步骤要复杂些,代码的抽离也不是很容易
二、组件的划分
每一个组件都是一个独立的pod库
,我们把组件化的代码放在Git
上托管,制作成私有pod
,然后通过cocoapods
就可以连接各个组件,最后把它们合在一起,变成一个完整的项目
原则
- 基础代码;基础配置(宏定义、常量)、分类、网络请求、其它的一些工具类
- 功能代码;自定义的一些UI控件;一些功能类,如音频处理、断点续传等
- 业务代码;具体的业务,如首页模块、个人中心模块等
三、组件的创建
pod 的原理
当我们执行 pod install
把代码集到项目中,这个过程会发生一些什么事情?
以AFNetworking
为例,当它的源码提交到Git
上的时候,里面会有一个.spec
的文件,这个文件是描述框架信息的,比如框架的名称、版本号、真实源码地址等。
在Git
上有专门的一个远程仓库用来存放所有的 .spec
文件,我们执行pod install
的时候,会先去本地找这个库对应的.spec
文件,这个文件是当你在安装pod
执行pod setup
的时候或者更新pod的时候,就会把远程仓库里的.spec
文件拉取到本地。那如果本地找不到这个描述文件,那么它就会去把远程仓库的spec文件拉取到本地,然后再去找,找到了之后,就能够得到描述文件里的真实源码地址,通过Git
把它拉取下来
制作一个私有pod库(重难点)
步骤
首先,打开终端,进入项目主目录中
cd ~
cd desktop
mkdir 组件化项目
cd 组件化项目
1. 组件工程(用来发布的组件,开发时用的工程)
- 思路:新建一个空白工程,在工程中进行业务代码的开发,比如首页;开发完毕后将代码提交到
Git
- 具体步骤
- 码云上新建一个私有仓库(为了代码安全,搞成私有的!)
-
clone
到本地,进行业务代码的开发(所有的代码都放在一个主目录文件夹中如ExamComponent
),可多人开发,使用Git
做版本控制 - 开发完毕后,上到到
Git
上,把ExamComponent
文件夹拷贝出来
2. 私有pod库
-
创建
本地pod库
-
进入项目目录中,执行以下命令
cd 组件化项目 pod lib create CXComponentBasic
这个是
pod
提供的一个模板命令,可以创建一个标准的pod
库,我们只需要把拷贝过来的业务代码
放在Classes
文件夹中,然后修改.spec
文件,就可以发布了,稍候将详细介绍
-
创建
私有索引库
通过上面介绍的pod的原理
,我们知道每个开源库都对应一个.spec
文件,这个.spec
文件默认是放在开源的pod索引库
里的,别人都可以搜索到,我们如果需要创建私有pod库
,就不能把.spec
文件放在默认开源索引库
里,我们需要把它放在自己的私有索引库
中。
- 码云上新建一个私有库,用来存放spec文件,这个库也可称为索引库
- 回到终端,将这个索引库关联到本地,命令如下
pod repo add CXGiteePrivateRepo https://git.oschina.net/baiyingqiu/CXGiteePrivateRepo.git
CXGiteePrivateRepo
是私有索引库的名称
可通过命令pod repo
可查看本地有哪些索引库
关联pod库的远程仓库
前面两步已经把本地pod库
和私有索引库
创建好了,下面就不要把pod库的.spec
文件,上传到私有索引库中就行了。-
关联
本地pod库
- 码云上新建一个私有库,名称和
本地pod库
一样,用来和它进行关联,命令如下
git remote add origin https://gitee.com/sunnoryChen/CXComponentBasic.git
- 码云上新建一个私有库,名称和
修改
.spec
文件
修改版本号和路径等-
发布
- 打开本地私有pod库的示例项目
cd xx pod install clean
先执行下安装,看看pod库是否报错,如果报错说明你的业务代码有问题,得改!
-
返回上一级目录
确保你的业务代码正常后,就可以返回到上级目录,准备发布啦- 关联远程仓库
git remote add origin https://gitee.com/sunnoryChen/CXComponentBasic.git
git remote -v 可查看关联了哪些远程仓库
- 上传到远程仓库
git add . git commit -m “0.1.2” git tag 0.1.2 git push origin master --tags -f
注意 tag 值需要和pod的版本号保持一致
- 验证
.spec
文件是否可用
pod spec lint --sources='https://gitee.com/sunnoryChen/CXGiteePrivateRepo.git,https://github.com/CocoaPods/Specs' --allow-warnings
这两个路径一个是我们的私有索引库地址,一个是pod的公共索引库地址
- 发布到私有索引库中
验证通过后,验证不通过,那就看哪报错就改哪儿吧,反正有不少坑的😆
发布的命令如下:
pod repo push CXGiteePrivateRepo CXComponentBasic.podspec --sources='https://gitee.com/sunnoryChen/CXGiteePrivateRepo.git,https://github.com/CocoaPods/Specs' --allow-warnings
CXGiteePrivateRepo
是我们之前创建的本地索引库名
CXComponentBasic.podspec
就是我们要发布库的索引库
3. 组件的使用
修改 podfile 文件,如下
# 使用私人pod库的需要在Podflie中添加这句话,指明你的版本库地址
source 'https://gitee.com/sunnoryChen/CXGiteePrivateRepo.git'
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, ‘8.0’
pod 'CXComponentBasic', '~> 0.1.2'
Tips
- 组件项目中怎么使用 .pch 预编译文件
找到pod的目录 “Support Files - RDZJComponentLogin-prefix.pch” ,这个相当于实际项目中的pch文件,防止一些预编译的命令,可全局调用的
- 组件内怎么分层级的
修改 .spec
文件
#头文件
s.public_header_files = 'Pod/Classes/Category/UIKit/CXUIKit.h'
s.subspec 'Category' do |vdr|
vdr.subspec 'Foundation' do |vd|
vd.source_files = "CXComponentPublic/Classes/Category/Foundation/**/*"
end
vdr.subspec 'UIKit' do |vd|
vd.source_files = "CXComponentPublic/Classes/Category/UIKit/**/*"
end
end
-
组件怎么依赖三方库
s.dependency 'MBProgressHUD', '~> 1.0.0'
-
组件怎么使用自己活三方的 framework 或者 .a 文件
s.ios.vendored_frameworks = "xxx//.framework"
s.ios.vendored_libraries = "xxx//.a” 组件内部相互依赖?
s.subspec 'BaseClass' do |bsc|
bsc.source_files = "TestPod/Classes/BaseClass/*"
# 字库BaseClass中用到了字库Controls中的东西,需要添加依赖
bsc.dependency "TestPod/Controls"
end
TestPod
是你的组件名,这个命令的意思是TestPod
组件里的BaseClass
子库依赖了 的TestPod
组件中的Controls
子库
- 组件中怎么使用
资源文件
比如图片
、Xib
、txt文档
,因为组件中图片不是放在默认Main Bundle
中的,所以是不能使用ImageNamed
方法获取图片的,需要知道当前图片所在的Bundle
, 例如
图片
+ (instancetype)cx_imagePathWithName:(NSString *)imageName bundle:(NSString *)bundle targetClass:(Class)targetClass {
NSInteger scale = [[UIScreen mainScreen] scale];
NSBundle *currentBundle = [NSBundle bundleForClass:targetClass];
NSString *name = [NSString stringWithFormat:@"%@@%zdx",imageName,scale];
NSString *dir = [NSString stringWithFormat:@"%@.bundle",bundle];
NSString *path = [currentBundle pathForResource:name ofType:@"png" inDirectory:dir];
return path ? [UIImage imageWithContentsOfFile:path] : nil;
}
Xib
+ (instancetype)base_mainView {
NSBundle *currentBundle = [NSBundle bundleForClass:[self class]];
CXBaseXibView *view = (CXBaseXibView *)[currentBundle loadNibNamed:@"CXBaseXibView" owner:nil options:nil].lastObject;
view.frame = CGRectMake(0, 0, UIScreen.mainScreen.bounds.size.width, 128);
return view;
}
txt
NSBundle *currentBundle = [NSBundle bundleForClass:[self class]];
NSLog(@"text_currentBundle = %@",currentBundle);
NSString *dir = [NSString stringWithFormat:@"%@.bundle",@"RDZJComponentLogin"];
NSString *plistPath = [currentBundle pathForResource:@"userDeal" ofType:@"txt" inDirectory:dir];
NSLog(@"plistPath = %@",plistPath);
Questions
-
pod
发布命令不可用
需要先注册
一下pod
才能有发布库的权限 eg.
pod trunk register 2235037295@qq.com "georry"
- 发布库时,报 Swift 版本错误
在 podspec中添加 s.swift_version = '4.0'
- 更新私有库版本时,出现
[!] The repo MySpecs at ../../../../.cocoapods/repos/MySpecsis not clean
需要更新一下我们的索引库
执行命令pod repo update
本地私有索引库名称(MySpecs)
执行命令 pod repo update 本地私有索引库名称(MySpecs)
- 在组件内部使用三方库时,要这样导入
Masonry/Masonry.h
- OC、Swift 混编包,怎么做组件
不使用!!!
四、组件的通讯
采用 CTmediator
的路由解决方案,将需要暴露的接口放在它的分类方法中,具体使用方法可参考上篇文章