一、 前言
随着我们游戏社区产品的功能越来越丰富,多个项目的并行开发,以及一些功能模块重复开发,严重的增加了项目的维护成本,为了提升开发效率,以及解耦合,对于一些公共的模块,保证一端开发多端使用,对项目进行组件化,便提上了改造日程,首先是对一些公共模块进行私有库组件,然后是对业务模块进行本地组件划分。
二、 如何创建一个组件
1、 创建私有化组件步骤
以登录模块组件为例 LoginModule
在终端上切换到你想要创建项目的位置 ,然后开始创建(前提条件你Mac上已经安装了cocoapod 工具)
bogon:~ hero$ cd /Users/hero/Desktop
bogon:Desktop hero$ pod lib create LoginModule
按回车后,终端会让你回答几个问题
选择项目使用平台
What platform do you want to use?? [ iOS / macOS ]
iOS
选择编程语言
What language do you want to use?? [ Swift / ObjC ]
Swift
在你的项目中是否创建一个demo工程
Would you like to include a demo application with your library? [ Yes / No ]
Yes
选择哪一个测试框架
Which testing frameworks will you use? [ Quick / None ]
None
要不要做视图测试
Would you like to do view based testing? [ Yes / No ]
Yes
至此,系统会帮你创建一个包含本地私有库的项目,新版本的cocoapod会自动执行 pod install ,模板库加载完成后,会通过命令行 打开我们刚创建的 LoginModule 工程
2、把文件添加到私有库中
1、进入到刚创建的项目,可以看到 LoginModule 文件夹,这个文件就是用来存储,我们制作私有库时需要的代码文件和资源文件(图片、xib,以及其他资源文件)
2、 把Class 文件内的文件进行替换
3、 把文件加载到项目中
此时上一步加载的文件并未真正加载到项目中,此时需要在终端中进入到 Example目录中执行以下命令:
pod update --no-repo-update
在项目中可以看到我们添加的文件已经加载到工程中了
4、加载本地化组件
在主项目中建一个专门存放本地库的文件夹,把LoginModule 组件放进去
在Podfile文件中添加组件
然后进行pod install ,就可以看到组件添加到项目中了
三、制作线上私有库
1、接下来进入 LoginModule 项目打开 LoginModule.podspec 文件,删除多余的注释之后,如下:
s.name 私有库的名字
s.version 私有库的版本:管理代码库的版本,这个是和git平台代码对应的tag版本是一一对应的
s.summary 私有库概要
s.description 描述
s.license 许可证
s.author 创建库的用户
s.source 代码在 gitLab上存储的地址,也就是远程仓库
s.ios.deployment_target 这个库最低可以安装的平台
s.source_files 存储代码文件的路径
s.resource_bundles 存储图片的路径
s.frameworks 代码中需要用到的 framework
s.dependency 依赖的第三方库
2.创建私有 Spec Repo
什么是 Spec Repo?它是所有的 Pods 的一个索引,就是一个容器,所有公开的pods都在这里面,它实际上是一个Git 仓库,remote 端在GitHub上,当我们使用 Cocoapods 后它会被 clone 到本地的 ~/.cocoapods/repos 目录下,可以看到有一个master文件件,这个就是官方的 Spec Repo 。
我们需要创建一个类似 master 的私有 Spec Repo,同理这个私有 Spec Repo也要有一个远程端,我们创建一个 Git仓库用来存储 .podspec 版本文件。如果创建私有的,需要给使用这个仓库的同事 Git仓库权限 ,我们在 Gitlab 创建仓库的名字是 HeroSpecKit ,此时,我们需要做一下关联,在终端 中执行如下命令:
命令格式# pod repo add [Private Repo Name] [GitLab HTTPS clone URL]
pod repo add HeroSpecKit Https://xxxxxxxxxxx
再次进入到~/.cocoapods/repos 目录时就可以看到 HeroSpecKit 目录了。
注意:如果有其他合作人员共同使用这个私有库 Spec Repo ,在他有对应 Git仓库权限的前提下执行相同的命令添加这个 Spec Repo 即可。
3、先在代码管理平台创建一个私有组件代码管理仓库,并把创LoginModule模块上传到远程端,我们这里是用GitLab来管理代码:
切换到 LoginModule 项目目录, 在终端执行命令:
git add .
git commit -m "第一次提交"
git remote add origin https://xxxxxxxx
git push --set-upstream origin master
下面是提交代码后的界面
因为 podspec 文件中获取 Git 版本控制的项目还需要 tag 号,所以需要打上一个 tag
在终端执行命令:
git tag 0.1.0
git push origin 0.1.0
注意:0.1.0 要和 podspec 中的 s.version 版本号一一对应
4.制作远程 cocoapod 库
上一步已经把本地的代码同步到了远程仓库,并且打了 tag,此时需要把 LoginModule.podspec 推送到 [Spec Repo] 私有库
先把已经编辑好的 LoginModule.podspec 文件进行一下验证,终端切换到 LoginModule 目录,执行以下命令:
pod spec lint LoginModule.podspec
然后,提示没有通过验证
在命令后面 添加 --allow-warnings ,再次执行命令
pod spec lint LoginModule.podspec --allow-warnings
这次通过了验证
接下来把 0.1.0 版本 LoginModule.podspec 文件推送到 [私有repod] ,在终端执行命令:
pod repo push [私有repod] LoginModule.podspec --allow-warnings
注意:如果想看到实时的进度可以在命令后面添加 参数 --verbose
至此,已经把 LoginModule 制作组件的过程已经完成,接下来我们就可以在 主工程中使用这个组件了
在需要用到此组件的项目的 podfile 文件中添加 pod 'LoginModule' ,并在终端执行 pod install
注意:因为这是我们的私有库 ,需要在 podfile 中添加 podspec 的路径源 :
source 'http://xxxxxxxxxx' ,否则会提示找不到此库
四、组件之间的通讯问题
目前业务组件之间的通讯我们使用的是 CTMediator ,具体的可以参考 文档
https://casatwy.com/CTMediator_in_Swift.html
五、在实施组件的过程中遇到的问题
1. 图片资源加载的问题
可以参考这篇文章
2. xib资源加载的问题
关于xib 的加载遇到的一些坑,xib无法被加载 ,会报如下的错误:
从上面的错误信息,可以看到没有在bundle中找到要加载的 xib资源
这里加载xib的方式分为两种:
1、 如果在 LoginModule.podspec 添加了 s.static_framework = false ,也就是把当前的源码打包成动态库 ,此时不需要把资源加载到 Assets 资源库中,直接放到代码中即可
编译后的xib资源位置,现在项目目录中找到LoginModule_Example.app,右键进入app文件夹中, 可以看到xib资源被放到了 LoginModule.framework 库中了,如图:
右键找到 Framework 文件夹
找到 LoginModule.framework 然后右键,可以看到xib文件被打包到 framwork 包中了
具体的加载xib代码如下:
let bundle = Bundle.init(for: LoginInfo.self)
let VC = LoginInfo.init(nibName: "LoginInfo", bundle: bundle)
view.addSubview(VC.view)
需要注意的地方:
因为xib的加载默认是从 mainbundle 中加载的,但是此时需要从指定的库中加载,所以在配置xib的时候,在 Tartget Membership 中选中 xib所属的库,同时,最后在设置一下xib所属的Module ,这样就可以正常加载 xib 了
2、 如果在 LoginModule.podspec 添加了 s.static_framework = true ,也就是把当前的源码打包成静态库,此时我们需要把 xib 添加到 Assets 资源库中才能正常使用和加载,此种情况打包后,LoginModule中的bundle资源库,会被加载到main bundle 中,如图:
进入到 LoginModule_Example.app 文件夹中
右键进入到 LoginModule.bundle 中,可以看到添加的 xib资源
可以看到 LoginModule.bundle,是在主 bundle中,此时加载xib的方式是从mainbundle中加载资源,代码如下:
let loginModuleBundlePath = Bundle.main.path(forResource:"LoginModule", ofType:"bundle")
let loginModuleBundle = Bundle.init(path: loginModuleBundlePath!)
let VC = LoginInfo.init(nibName: "LoginInfo", bundle: loginModuleBundle)
view.addSubview(VC.view)
3、 pod 加载提示找不到第三方库
看了网上一些解决方案,依然无法解决问题,最终是在podfile 文件上 添加 pod 源来解决
source 'https://github.com/CocoaPods/Specs.git'
4、当把新制作的私有库添加到项目中 pod install 时 ,提示如下 错误
根据提示执行 pod install --repo-update 命令 就可以解决问题
5、目前我们项目组件化的方案是 本地组件+远程公共组件 ,针对变化性强的业务模块作为本地组件,基础服务和稳定的非业务模块作为公共组件 ,把本地化组件转化成公共组件的过程中,有同事遇到了一个问题,因为当前组件在主工程中,同时,又制作成公共基础组件供其他项目使用,同一个文件就属于两个Git ,在提交修改完文件后,主工程提交到远程端时,就会出现新修改的文件提交不上的情况。
如图gitlab上的显示:
解决方案:
1、假如电脑A通过 pod lib create TestPod 创建一个 TestPod项目 ,默认 TestPod 项目包含一个git 隐藏文件,为了避免出现上面的问题,先把 .git 文件删除 ,然后把它放入到主项目中,此时做一次代码提交,然后,通过终端进入到 TestPod 目录,通过 git init 初始化 一个git ,然后,把 gitLab 上的远程仓库和TestPod做关联,提交代码即可。此时,两个工程【主工程和子工程】都可以提交代码了
六、总结
组件化实施与探索,对提升我们的项目开发效率是加成的,在这期间,我们也开发了通过脚本自动发布 组件的工具,大大的提升了开发效率,在接下来一段时间会继续带着小伙伴,深入的探索架构的演变与开发效率提升的工作。