# OMCUVideo **Repository Path**: creeve/OMCUVideo ## Basic Information - **Project Name**: OMCUVideo - **Description**: OMCUVideo Container Project - **Primary Language**: Objective-C - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2018-03-09 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # OMCUVideo 基于Carthage组件化开发的工程Demo ## 工程介绍 本工程是基于Carthage进行组件化开发的Demo主工程,主工程只是作为一个容器,包含了其他子模块的引用,这里主要包含了OMCSplash,OMCHome,OMCVOD三个模块。工程只是对其进行简单的创建和轮流显示操作,实际按需要进行操作(比如填入TabBarController等) 运行需要执行: ``` carthage update --platform iOS ``` 这样就可以将子模块通过Carthage组件的方式集成到主工程中。 后续开发除了新增组件或修改工程设置之外,基本都不用动主工程,只需要在子模块的工程里面进行对应功能的开发即可。 ## 设计思路 以往App的设计思路都是一个工程,然后每个功能都新建所需的文件,拖到工程里面,进行开发,开发完之后打包发布。 这种模式如果实现简单的功能,以及单一的路线下问题不大,但是当项目功能增多,而且功能分支较多的时候,就会产生以下问题: 1. 代码复用性差,实际开发中,肯定会积累很多公共的功能模块,比如网络请求模块,一些方便的Category,一些格式化时间的工具等。当这些功能需要移植到其他项目/分支上时,只能复制粘贴代码,而这些模块若有后续更新,同步到各个项目/分支上也是非常麻烦的。 2. 模块独立性差,由于在同一工程中,往往很多功能编写的时候,会依赖其他模块,我们如果需要抽取代码其中一个功能模块出来使用,往往连带需要引入各种头文件。当我们修改某一模块的时候,往往也会影响到其他模块的功能 3. 编译时间增加,当我们添加了很多代码文件时,重新编译的成本是比较高的,目前工程上千的文件就需要编译5分钟以上。 解决这个问题其中一个较好的方式就是用SDK的思维来编程,把各个功能模块,组件化为一个个SDK。 我们使用一些SDK的时候,一般是填入他需要的数据,然后就能给我们输出对应的结果,这个过程对于调用者来说是非常简单的,我们不需要了解SDK内部的实现,只管输入正确的数据,并处理输出的结果即可。 我们的目标是把App划分为各个模块,每个模块都能独立运行,模块开发的时候不需要考虑App的其他功能,只需要用SDK的思维做好一个SDK该做的事情就好了。 以一个视频App为例,假设我们这个视频App需要有以下几个功能模块: 启动页、首页、直播、点播、我的、播放器 这几个模块对应的是一个个ViewController,各个VC会实现自己的功能,我们可以分别命名为: OMCSplashKit,OMCHomeKit,OMCLiveKit,OMCVODKit,OMCMeKit,OMCPlayerKit。 各个模块只需要关注自己功能的实现即可,不需要关心其他模块的实现,以及App工程的结构等无关信息。 以下就是如何高效,稳定的实现此功能。经过探索之后,发现使用Carthage是较为适合实现的。 [Carthage](https://github.com/Carthage/Carthage)的安装和使用这里就不说了。在具备了Carthage的环境之后,我们先需要一个主工程,主工程并没有具体的功能代码,主要进行一些工程的参数配置,以及引入各个模块进行拼装,调用一些子模块提供的初始化方法初始化App等。 这里以新建一个名为OMCUVideo为例,展示通过Carthage添加需要的启动页面的方法。 新建完工程之后,为了方便使用加载页面,我们去掉Storyboard(删掉Storyboard文件同时删掉General里面的Main Interface引用),改用代码代码加载跟页面。 ```objective-c - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; UIViewController *rootViewController = [[UIViewController alloc] init]; rootViewController.view.backgroundColor = [UIColor orangeColor]; self.window.rootViewController = rootViewController; [self.window makeKeyAndVisible]; } ``` 这样我们就能加载一个背景色为橘黄色的App界面了。 接下来,我们就要通过Carthage的方式,添加真正的OMCSPlashViewController,最后实现的代码类似: ``` @import OMCSplashKit; - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; OMCSPlashViewController *splashVC = [[OMCSPlashViewController alloc] init]; self.window.rootViewController = splashVC; [self.window makeKeyAndVisible]; return YES; } ``` 第一步: 需要新建一个Git仓库,Carthage需要通过Git地址来加载OMCSplashKit,在这个仓库里面我们新建一个普通的iOS工程,添加OMCSPlashViewController.h/m来实现功能(这里我们只是简单修改了背景色,实际项目中需要实现更多的功能)。 第二步: 新建一个Target,这里命名为OMCSplashKit,选择Cocoa Touch Framework,然后再Build Phases里添加Compile Source(需要编译的.m文件),以及Headers-Public(需要暴露给外部的.h文件) 第三步: 打开Edit Scheme - Manage Schemes,打开OMCSplashKit的Shared属性,以使Carthage能编译此Target,修改完成后提交Git即可。然后打开Terminal定位到工程文件同级的文件夹,输入: ``` carthage build --no-skip-current ``` 成功之后再提交Git即可,此外,由于Carthage是通过Tag来获取版本号的,我们需要给Git的提交添加Tag版本号,最好与工程里面的版本号一致(一般用三段式命名,例如1.0.0)。 这样我们支持Carthage的库就已经完成了。 第四步: 回到OMCUVideo工程,新建一个Cartfile,填入对应的地址即可: ``` git "https://xx.com/OMCSplash.git" ``` 然后,保存文件,在Terminal中输入 ``` carthage update --platform iOS ``` 便会下载并编译生成对应的framework,位于Carthage/Build/iOS下,拖入Linked Frameworks And Libraries中,然后再到Build Phases中添加Run Script: ``` /usr/local/bin/carthage copy-frameworks ``` 添加Input Files:$(SRCROOT)/Carthage/Build/iOS/OMCSplashKit.framework 之后编译即可使用OMCSplashKit了。 ``` @import OMCSplashKit; ``` ### PS1. 功能修改及提交 后续具体功能的修改,是通过模块工程进行的,一般不需要修改主工程。 而每一个模块,都是一个Demo工程,编译成App的时候,可以独立运行,方便调试,修改之后只需要提交到Master分支,并打上对应的tag,主工程只需要运行`carthage update --platform iOS`即可更新。 ### PS2. 独立模块之间的依赖 在实际开发过程中,会遇到A模块依赖B模块的情况,比如点播模块,获取节目需要依赖网络模块,点击播放的时候,需要调用播放器模块。只需要在设计点播模块的时候,在demo工程中添加包含网络模块,播放器模块的Cartfile即可,主工程添加对应的Cartfile添加所有的依赖(点播/网络/播放器)即可 ### PS3. 和CocoaPods的兼容 通常来说我们不会再主程序中实现具体内容,而是在子模块中进行。主程序不需要引入CocoaPods,子模块引入即可。步骤与正常添加Pod类似,唯一的区别是需要给Framework的target也添加Pod。 假设子模块A引入了库X,子模块B也引入了库X,最后根工程引用A和B,这样会引入两次库X,不会导致错误,但会使包增大。 这里建议公用的库,都通过Carthage集成,这样就不会重复引入,目前来说,大部分广泛使用的第三方库都已经支持Carthage,问题不大。 ### PS4. 模块中包含切图或Xib/Storyboard等文件资源 **图片** 首先要新建一个bundle,假设命名为ImageResource.bundle,然后把图片拖入bundle文件夹中,然后在使用该切图的类中: ``` NSBundle *bundle = [NSBundle bundleForClass:[self class]]; NSURL *url = [bundle URLForResource:@"ImageResource" withExtension:@"bundle"]; self.imageBundle = [NSBundle bundleWithURL:url]; UIImage *thumbImage = [UIImage imageNamed:@"player_touch_point" inBundle:self.imageBundle compatibleWithTraitCollection:nil]; ``` 然后再将Target - Build Phases的Copy Bundle Resource中添加这个bundle,这样打出的Framework就能包含切图的bundle了,主工程只需要引用Framework即可。 这里要新建bundle主要是因为切图一般较多,用bundle易于管理。 **XIB** 由于一般是一个VC类对应一个XIB,通常XIB不会很多,我们直接按照正常的方式添加即可(即VC文件和xib同级),XIB的加载方式类似 ``` NSBundle *xibBundle = [NSBundle bundleForClass:[self class]]; if (self = [self initWithNibName:NSStringFromClass(self.class) bundle:xibBundle]) { } return self; ``` 然后把xib文件添加到Copy Bundle Resource即可。 ## Wrap up 以上就是实现Carthage管理App模块的方式,实际的开发过程与此步骤类似,总结起来就是: 1. 建立主工程,完成一些工程设置。 2. 建立模块工程,实现模块的功能代码,新建Framework Target,添加头文件和编译的文件,打开该Target Scheme里面的Shared。 3. 主工程通过Carthage引用模块工程生成的Framework,调用其实现具体的功能。