最近想了解一些组件化的知识,去看了Casa写的iOS应用架构谈 组件化方案这篇文章,Casa在文中针对蘑菇街的组件化方案提出了一些不同的观点,陈述了自己的组件化方案。
大神们讨论具体的实施方案,是对理论的描述,在架构层面来分析利弊,我看过之后感觉还是有点晦涩,具体的方案异同之处我们先不说,今天我们先从应用着手,在自己当前的工程实施组件化。
当然了,我们选择使用的方案是Casa的CTMediator。
准备
首先我们得先了解组件化这个概念,其实通俗的讲,就是把我们的项目拆解成一个一个的小组件分别管理。我们平时使用cocoapods继承的三方的库,可以理解成是一个公有的组件。我们项目中,也可以把一些模块拆解出来,使用cocoapods来集成。这样拆解成一个个的组件的好处有很多,比如说业务模块之间解耦,复用模块,节省编译时间等等。
所以我们要先学会创建cocoapods私有库。
这里多说一句,Casa的组件化方案在实施的时候,每独立出来一个组件,就会相应的创建一个Category工程,作为中间的调度,所以说,我们每做一个组件,就要创建两个私有的pod工程。
我们结合Casa这篇在现有工程中实施基于CTMediator的组件化方案,来做一下补充或者说是注解吧,本文中的流程取自于上文。
创建私有Pod工程
1. 先去开一个repo,这个repo就是我们私有Pod源仓库
2. pod repo add [私有Pod源仓库名字] [私有Pod源的repo地址]
3. 创立一个文件夹,例如Project。把我们的主工程文件夹放到Project下:~/Project/MainProject
4. 在~/Project下clone快速配置私有源的脚本repo:git clone git@github.com:casatwy/ConfigPrivatePod.git
5. 将ConfigPrivatePod的template文件夹下Podfile中source 'https://github.com/ModulizationDemo/PrivatePods.git'改成第一步里面你自己的私有Pod源仓库的repo地址
6. 将ConfigPrivatePod的template文件夹下upload.sh中PrivatePods改成第二步里面你自己的私有Pod源仓库的名字
首先我们先创建一个名为Project的文件,然后把我们项目的主程序,我们叫做MainProject放到Project路径下,然后在Project路径下clone出我们需要的脚本(Casa提供)
在~/Project下clone快速配置私有源的脚本:
git clone git@github.com:casatwy/ConfigPrivatePod.git
现在我们的文件目录结构是这样的。
Project
├── ConfigPrivatePod(脚本文件)
└── MainProject
在Project路径下创建我们的组件工程(一个普通的iOS工程),我们把这个工程名字叫PayComponents (模拟抽取项目中的支付模块)。
当前目录结构
Project
├── ConfigPrivatePod
├── MainProject
└── PayComponents
有了本地的工程之后,我们现在需要创建一个repo,作为我们的私有pod源仓库。也就是在github,或者gitee(码云)上面创建一个项目,放我们的项目代码,命名PayComponents。
然后呢,我们还需要创建一个东西,就是私有Pod源仓库名字。
pod repo add [私有Pod源仓库名字] [私有Pod源的repo地址]
落实到我们这个项目中,我们应该这样写。
pod repo add PayComponents https://gitee.com/LittleBin/PayComponents.git
那这到底代表着我们创建了什么?
我们打开finder->前往->前往文件夹,然后输入~/.cocoapods/repos
可以看到目录是这样子的
repos路径下面有一个master,一个payComponents。这两个文件夹我们可以粗略的认为他和pod search还有install有关。
打个比方就拿search来说,我们查询一个库的时候会用下面这个命令
pod search AFNetworking
然后会从master路径下找到AFNetworking,然后列出来他有哪些版本什么的。我们有的时候会发现一个库其实已经跟新到2.x.x版本,但是我们search出来只有1.x.x,这也可能是我们的cocoapods没有更新,我们的master路径下没有新的版本。
这个PayComponents文件夹,就代表我们本地有一个私有的pod库。我们search的时候,也会查这些本地的私有库。
下面把远程的这个repo和我们本地创建的项目关联到一起,这个工作Casa给我们提供的脚本就可以完成,顺便还会帮我们生成.podspec的文件,具体这个文件的作用我们后面再说,还会初始化podfile。
我们进到ConfigPrivatePod文件中,执行config.sh脚本,然后在终端根据提示输入就行了。
[localhost:ConfigPrivatePod sunxiaobin$ ./config.sh
Enter Project Name: PayComponents
Enter HTTPS Repo URL: https://gitee.com/LittleBin/PayComponents.git
Enter SSH Repo URL: git@gitee.com:LittleBin/PayComponents.git
Enter Home Page URL: https://gitee.com/LittleBin/PayComponents
================================================
Project Name : PayComponents
HTTPS Repo : https://gitee.com/LittleBin/PayComponents.git
SSH Repo : git@gitee.com:LittleBin/PayComponents.git
Home Page URL : https://gitee.com/LittleBin/PayComponents
================================================
confirm? (y/n):y
copy to ../PayComponents/FILE_LICENSE
copy to ../PayComponents/.gitignore
copy to ../PayComponents/PayComponents.podspec
copy to ../PayComponents/readme.md
copy to ../PayComponents/upload.sh
copy to ../PayComponents/Podfile
editing...
edit finished
cleaning...
Initialized empty Git repository in /Users/fmb/Documents/LEARN/Project_test/PayComponents/.git/
clean finished
finished
localhost:ConfigPrivatePod sunxiaobin$
Enter Project Name:的时候,后面的名字一定要跟我们创建的PayComponents工程一样,要不然脚本找不到文件,就配置不了。
脚本跑完之后PayComponents里面变成下面这样子。
我们要修改一下Podfile文件和upload.sh。下面是生成的Podfile文件里面的内容
# Uncomment this line to define a global platform for your project
# platform :ios, '9.0'
source 'https://github.com/ModulizationDemo/PrivatePods.git'
source 'https://github.com/CocoaPods/Specs.git'
use_frameworks!
target 'PayComponents' do
end
因为脚本都是照着模板来生成的这些文件,上面是podfile文件里面的内容,我们要把第一个source后面的'https://github.com/ModulizationDemo/PrivatePods.git'
改成我们这个库的地址,https://gitee.com/LittleBin/PayComponents.git
。
然后在upload.sh中,最后一行
pod repo push PrivatePods PayComponents.podspec --verbose --allow-warnings --use-libraries --use-modular-headers
把PrivatePods替换为我们上面的私有pod库名称。
也就是我们之前执行的下面这个命令中的PayComponents。
//不用重复执行
pod repo add PayComponents https://gitee.com/LittleBin/PayComponents.git
我们在看一下PayComponents项目文件的结构,脚本给我们生成了一个空的PayComponents文件。
我们需要把这个文件拖拽到我们的项目中
然后我们这个PayComponents组件的文件就全部放到这个路径下。我们的私有库暂时就先写到这里。下面创建我们的Category工程
创建Category工程
因为篇幅原因,这里我把创建Category工程略过一下,不一一展示了。
其实按道理说在实际项目中,这个Category工程也要做成私有库的,就像我们上面说的步骤,先创建本地工程,创建远程的repo,然后创建本地私有库(pod repo add ...),在用脚本关联本地和远程的库,然后修改Podfile和upload.sh等等这一整套步骤。
最终Category项目的结构是下面这样的。(包含为CTMediator添加的分类)
我们调用PayComponents组件里面的vc都是通过这个category来调用的。所以说我们的这个Pay_category工程应该在Podfile文件中加上pod 'CTMediator'
,然后执行pod install
。
我们之前有遇到过这种情况,我们在使用A库的时候,pod install之后,会自动帮我们导入A库依赖的B库,回到我们的项目也就是说当我们在主工程里面集成Pay_Category这一组件的时候,应该默认帮我们把CTMediator库和PayComponents组件也集成进工程。这就要修改Pay_Category.podspec文件。
在文件的最底部,end之前加上下面两句
s.dependency "CTMediator"
s.dependency "PayComponents"
说回我们新建的这个CTMediator+pay文件,我们要在主工程MainProject跳转到PayComponents里面的VC,所以CTMediator+pay应该提供一个返回vc的方法,如下:
- (UIViewController *)PayViewController {
return [self performTarget:@"PayManager" action:@"pay" params:nil shouldCacheTarget:NO];
}
我们想不去管return后面的代码是什么意思,只要他是返回了vc给我们就可以。
然后在MainProject里面的跳转代码就如下:
// 导入CTMediator+pay头文件
UIViewController * viewController = [[CTMediator sharedInstance] PayViewController];
[self.navigationController pushViewController:viewController animated:YES];
下面我们再来说return [self performTarget:@"PayManager" action:@"pay" params:nil shouldCacheTarget:NO];
是什么意思。
我们可以从CTMediator的源码中,看一下- (id)performTarget:(NSString *)targetName action:(NSString *)actionName params:(NSDictionary *)params shouldCacheTarget:(BOOL)shouldCacheTarget
这个方法。
那这里我就不绕圈子里,直接说结论,其实在上述的方法中是找到了一个叫Target_PayManager的类,调用了它里面的Action_pay方法,这个前缀Target_和Action_是在方法内部拼接的,所以说我们可以得出,CTMediator是通过反射拿到类名和方法名,然后调用,得到目标vc的。所以说在PayComponents工程中,我们还得创建Taregt文件来做间接的调用。
这里的Target_PayManager文件的文件名后半部分PayManager要跟- (id)performTarget:(NSString *)targetName action:(NSString *)actionName params:(NSDictionary *)params shouldCacheTarget:(BOOL)shouldCacheTarget
里面的targetName对应起来,然后类里面的方法名字也得对应。(PayViewController就是我们的目标文件)
- (UIViewController *)Action_pay:(NSDictionary *)param {
PayViewController *viewController = [[PayViewController alloc] init];
viewController.param = param;
return viewController;
}
最后我们在MainProject的Podfile文件中引入Pay_Category库就行了。这个时候我们的私有库可能还没有完全创建成,所以我们可以用这种导入本地的方法
pod "Pay_Category", :path => "../Pay_Category"
当然如果私有库做好了,就只需要pod "Pay_Category"
就行了。
完善私有库
在Casa的博客中说到,可以使用他的upload.sh脚本来更新私有库代码,我用过它的脚本,总是有错无,而且库的版本号也是依次+1的形式,版本号我喜欢x.x.x这种,所以我选择自己提交代码,更新私有库。
针对于每个工程来说,首先是一些基本的提交代码操作,
git add .
git commit -m “新版本号“
git tag 新版本号
git push origin master —tags
要更新私有库,我们拿PayComponents这个项目来说,执行下面的指令
//私有库升级
pod repo push PayComponents PayComponents.podspec
这个PayComponents就是我们pod repo add时候起得名字,后面是.podspec文件,这操作等于把我们的私有库更新推到我们本地的库里面。注意.podspec里面的版本号要记得更新,与tag一致。
那这种私有库我们项目的其他成员,还是拿PayComponents这个来说,首先在代码管理库上面得给他们下载代码的权限,然后执行下面:
//待核实~
pod repo add PayComponents https://gitee.com/LittleBin/PayComponents.git
公有库
补充一点,那如果想做成公有库,让大家都可以使用要怎么搞?
执行下面操作:
pod trunk push PayComponents.podspec
就可以把组件推到Cocoapods主仓库。别人就可以通过pod search来查找你的库了。
pod trunk push 可能失败,因为首次使用trunk需要注册自己的电脑。
pod trunk register [E-mail] [User Name]
执行完成之后,会受到一封验证邮件,按邮件提示完成验证即可。
全部都完成了之后pod search也可能会搜不到自己的库,这时候可以尝试把缓存删掉
使用命令:rm ~/Library/Caches/CocoaPods/search_index.json
清除后,再重新搜索,此时CocoaPod会重新创建搜索索引。
这只是一些可能的原因,具体的问题需要具体针对解决。
参考文章
https://casatwy.com/modulizat...
https://www.jianshu.com/p/59c...
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。