脚本组件化
第一步:创建一个主工程MainProject,然后在主工程里面有几个模块后者说是业务线;如下图中的A B ,主工程点击进去到A界面,A界面点击进入到B界面
第二步:开一个repo的私有源仓库,终端输入
pod repo add [私有仓库名][私有仓库git地址]
第三步:创建一个文件夹,比如叫projects,将主工程MainProject放到projects中,然后在projects文件夹下面,终端输入:
git clone git@github.com:wode0weiyi/ConfigPrivatePod.git
clone完成后,将ConfigPrivatePod的template文件夹下Podfile中的第一个sources改为自己的私有仓库地址;
文件目录是这样的:
Project
├── ConfigPrivatePod
└── MainProject
第四步:创建私有的Pod工程和category工程
MainProject是一个非常简单的应用,一共就三个页面。首页push了AViewController,AViewController里又push了BViewController。我们可以理解成这个工程由三个业务组成:首页、A业务、B业务。
我们这一次组件化的实施目标就是把A业务组件化出来,首页和B业务都还放在主工程。
既然要把A业务抽出来作为组件,那么我们需要为此做两个私有Pod:A业务Pod(以后简称A Pod)、方便其他人调用A业务的CTMediator category的Pod(以后简称A_Category Pod)。这里多解释一句:A_Category Pod本质上只是一个方便方法,它对A Pod不存在任何依赖。
我们先创建A Pod
1.新建一个工程,命名为A,放在projects文件夹下面;在github或者其他第三方托管网站上面创建A的repo,新建好之后,网页不要关掉
Project
├── ConfigPrivatePod
├── MainProject
└── A
然后cd到ConfigPrivatePod下,执行./config.sh脚本来配置A这个私有Pod。脚本会问你要一些信息,Project Name就是A,要跟你的A工程的目录名一致。HTTPS Repo、SSH Repo网页上都有,Home Page URL就填你A Repo网页的URL就好了。
A
├── A
| ├── A
| │ ├── AViewController.h
| │ └── AViewController.m
| ├── AppDelegate.h
| ├── AppDelegate.m
| ├── ViewController.h
| ├── ViewController.m
| └── main.m
└── A.xcodeproj
我们再创建A_Category工程Pod
步骤和创建A工程pod是一个流程。然后去A_Category下,在Podfile中添加一行pod "CTMediator",在podspec文件的后面添加s.dependency "CTMediator",然后执行pod install
接下来打开A_Category.xcworkspace,把脚本生成的名为A_Category的空目录拖放到Xcode对应的位置下,然后在这里新建基于CTMediator的Category:CTMediator+A。最后你的A_Category工程应该是这样的:
A_Category
├── A_Category
| ├── A_Category
| │ ├── CTMediator+A.h
| │ └── CTMediator+A.m
| ├── AppDelegate.h
| ├── AppDelegate.m
| ├── ViewController.h
| └── ViewController.m
└── A_Category.xcodeproj
主工程中引入A_Category,并让主工程编译通过
去主工程的Podfile下添加pod "A_Category", :path => "../A_Category"来本地引用A_Category。
然后编译一下,说找不到AViewController的头文件。此时我们把头文件引用改成#import 。
然后继续编译,说找不到AViewController这个类型。看一下这里是使用了AViewController的地方,于是我们在Development Pods下找到CTMediator+A.h,在里面添加一个方法:
- (UIViewController *)A_aViewController;
再去CTMediator+A.m中,补上这个方法的实现,把主工程中调用的语句作为注释放进去,将来写Target-Action要用:
-(UIViewController*)A_aViewController
{
/*
AViewController *viewController = [[AViewController alloc] init];
*/
return[selfperformTarget:@"A"action:@"viewController"params:nilshouldCacheTarget:NO];
}
补充说明一下,performTarget:@"A"中给到的@"A"其实是Target对象的名字。一般来说,一个业务Pod只需要有一个Target就够了,但一个Target下可以有很多个Action。Action的名字也是可以随意命名的,只要到时候Target对象中能够给到对应的Action就可以了。
关于Target-Action我们会在第三步中去实现,现在不实现Target-Action是不影响主工程编译的。
category里面这么写就已经结束了,后面的实施过程中就不会再改动到它了。
然后我们把主工程调用AViewController的地方改为基于CTMediator Category的实现:
UIViewController*viewController=[[CTMediatorsharedInstance]A_aViewController];
[self.navigationControllerpushViewController:viewControlleranimated:YES];
再编译一下,编译通过。
到此为止主工程就改完了,现在跑主工程点击这个按钮跳不到A页面是正常的,因为我们还没有在A工程中实现Target-Action。
而且此时主工程中关于A业务的改动就全部结束了,后面的组件化实施过程中,就不会再有针对A业务线对主工程的改动了。
添加Target_Action,并让A工程编译通过
我们在A工程中创建一个文件夹:Targets,然后看到A_Category里面有performTarget:@"A",所以我们新建一个对象,叫做Target_A。A工程目录是这个样的
然后又看到对应的Action是viewController,于是在Target_A中新建一个方法:Action_viewController。这个Target对象是这样的:
图这里写实现文件的时候,对照着之前在A_Category里面的注释去写就可以了。
因为Target对象处于A的命名域中,所以Target对象中可以随意import A业务线中的任何头文件。
另外补充一点,Target对象的Action设计出来也不是仅仅用于返回ViewController实例的,它可以用来执行各种属于业务线本身的任务。例如上传文件,转码等等各种任务其实都可以作为一个Action来给外部调用,Action完成这些任务的时候,业务逻辑是可以写在Action方法里面的。
换个角度说就是:Action具备调度业务线提供的任何对象和方法来完成自己的任务的能力。它的本质就是对外业务的一层服务化封装。
现在我们这个Action要完成的任务只是实例化一个ViewController并返回出去而已,根据上面的描述,Action可以完成的任务其实可以更加复杂。
然后我们再继续编译A工程,发现找不到BViewController。由于我们这次组件化实施的目的仅仅是将A业务线抽出来,BViewController是属于B业务线的,所以我们没必要把B业务也从主工程里面抽出来。但为了能够让A工程编译通过,我们需要提供一个B_Category来使得A工程可以调度到B,同时也能够编译通过。
B_Category的创建步骤跟A_Category是一样的,不外乎就是这几步:新建Xcode工程、网页新建Repo、跑脚本配置Repo、添加Category代码。
B_Category添加好后,我们同样在A工程的Podfile中本地指过去,然后跟在主工程的时候一样。
后续操作和在主工程引入A_Category时候一样,修改代码,创建B业务的target_Action
最后:
我们创建了三个pod,分别为A 、A_Category、B_Category
接下来就是给这个三个pod发版。
终端cd到各个工程的项目下,然后执行./upload.sh脚本文件,就可以了!如果提示错误,不知道怎么去解决的时候,下面给出分布的发布指令:
git add .
git commit -m '版本号' //说明:这个版本号必须和你podSpec文件里面的version一致,脚本生成让输入的versionNum也是一样的
git tag 版本号
git push origin master --tags
pod lib lint 项目名称.podspec --use-libraries//说明:这个是验证podspec文件的正确性
如果是用上述方法创建的pod和执行./config.sh脚本就不需要执行:
cd ~/.cocoapods/repos/[你的私有仓库名字]
git pull origin master//这里经常会提示already up to date,如果是先创建pod的,就可以不用理会
cd -
pod repo push [你的私有源名称] [podspec文件名].podspec --verbose --allow-warnings --use-libraries
最后提示build success就说明成功了。
这个时候在主工程的Podfile文件中,先引入两个sources
source '你的私有仓库git地址'
source 'https://github.com/CocoaPods/Specs.git'
然后将之前引入的本地的path去掉,最后就是
pod 'A'
pod 'A_Category'