草庐IT

iOS项目组件化实施(一)

hylccmh 2023-03-28 原文

一、 前言

随着我们游戏社区产品的功能越来越丰富,多个项目的并行开发,以及一些功能模块重复开发,严重的增加了项目的维护成本,为了提升开发效率,以及解耦合,对于一些公共的模块,保证一端开发多端使用,对项目进行组件化,便提上了改造日程,首先是对一些公共模块进行私有库组件,然后是对业务模块进行本地组件划分。

二、 如何创建一个组件

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 工程


image1.png
2、把文件添加到私有库中

1、进入到刚创建的项目,可以看到 LoginModule 文件夹,这个文件就是用来存储,我们制作私有库时需要的代码文件和资源文件(图片、xib,以及其他资源文件)

image2.png

2、 把Class 文件内的文件进行替换


image3.png

3、 把文件加载到项目中
此时上一步加载的文件并未真正加载到项目中,此时需要在终端中进入到 Example目录中执行以下命令:

pod update --no-repo-update

在项目中可以看到我们添加的文件已经加载到工程中了


image4.png

4、加载本地化组件
在主项目中建一个专门存放本地库的文件夹,把LoginModule 组件放进去

image5.png

在Podfile文件中添加组件

image6.png

然后进行pod install ,就可以看到组件添加到项目中了

image7.png
三、制作线上私有库
1、接下来进入 LoginModule 项目打开 LoginModule.podspec 文件,删除多余的注释之后,如下:
image8.png

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

下面是提交代码后的界面


image9.png

因为 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

然后,提示没有通过验证


image10.png

在命令后面 添加 --allow-warnings ,再次执行命令

pod spec lint  LoginModule.podspec --allow-warnings 

这次通过了验证


image11.png

接下来把 0.1.0 版本 LoginModule.podspec 文件推送到 [私有repod] ,在终端执行命令:
pod repo push [私有repod] LoginModule.podspec --allow-warnings
注意:如果想看到实时的进度可以在命令后面添加 参数 --verbose

image12.png

至此,已经把 LoginModule 制作组件的过程已经完成,接下来我们就可以在 主工程中使用这个组件了
在需要用到此组件的项目的 podfile 文件中添加 pod 'LoginModule' ,并在终端执行 pod install
注意:因为这是我们的私有库 ,需要在 podfile 中添加 podspec 的路径源 :
source 'http://xxxxxxxxxx' ,否则会提示找不到此库

四、组件之间的通讯问题

目前业务组件之间的通讯我们使用的是 CTMediator ,具体的可以参考 文档
https://casatwy.com/CTMediator_in_Swift.html

五、在实施组件的过程中遇到的问题
1. 图片资源加载的问题

可以参考这篇文章

https://www.jianshu.com/p/1699f537558a?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

2. xib资源加载的问题
image13.png

关于xib 的加载遇到的一些坑,xib无法被加载 ,会报如下的错误:


image14.png

从上面的错误信息,可以看到没有在bundle中找到要加载的 xib资源
这里加载xib的方式分为两种:
1、 如果在 LoginModule.podspec 添加了 s.static_framework = false ,也就是把当前的源码打包成动态库 ,此时不需要把资源加载到 Assets 资源库中,直接放到代码中即可


image.png

编译后的xib资源位置,现在项目目录中找到LoginModule_Example.app,右键进入app文件夹中, 可以看到xib资源被放到了 LoginModule.framework 库中了,如图:
image(1).png

右键找到 Framework 文件夹


image(2).png

找到 LoginModule.framework 然后右键,可以看到xib文件被打包到 framwork 包中了


image(3).png

具体的加载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 了


image(4).png

image(5).png

2、 如果在 LoginModule.podspec 添加了 s.static_framework = true ,也就是把当前的源码打包成静态库,此时我们需要把 xib 添加到 Assets 资源库中才能正常使用和加载,此种情况打包后,LoginModule中的bundle资源库,会被加载到main bundle 中,如图:


image(6).png

进入到 LoginModule_Example.app 文件夹中


image(7).png

右键进入到 LoginModule.bundle 中,可以看到添加的 xib资源


image(8).png

可以看到 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 加载提示找不到第三方库
image17.png

看了网上一些解决方案,依然无法解决问题,最终是在podfile 文件上 添加 pod 源来解决

source 'https://github.com/CocoaPods/Specs.git'

4、当把新制作的私有库添加到项目中 pod install 时 ,提示如下 错误
image18.png

根据提示执行 pod install --repo-update 命令 就可以解决问题

5、目前我们项目组件化的方案是 本地组件+远程公共组件 ,针对变化性强的业务模块作为本地组件,基础服务和稳定的非业务模块作为公共组件 ,把本地化组件转化成公共组件的过程中,有同事遇到了一个问题,因为当前组件在主工程中,同时,又制作成公共基础组件供其他项目使用,同一个文件就属于两个Git ,在提交修改完文件后,主工程提交到远程端时,就会出现新修改的文件提交不上的情况。

如图gitlab上的显示:


image19.png

解决方案:
1、假如电脑A通过 pod lib create TestPod 创建一个 TestPod项目 ,默认 TestPod 项目包含一个git 隐藏文件,为了避免出现上面的问题,先把 .git 文件删除 ,然后把它放入到主项目中,此时做一次代码提交,然后,通过终端进入到 TestPod 目录,通过 git init 初始化 一个git ,然后,把 gitLab 上的远程仓库和TestPod做关联,提交代码即可。此时,两个工程【主工程和子工程】都可以提交代码了

六、总结

组件化实施与探索,对提升我们的项目开发效率是加成的,在这期间,我们也开发了通过脚本自动发布 组件的工具,大大的提升了开发效率,在接下来一段时间会继续带着小伙伴,深入的探索架构的演变与开发效率提升的工作。

有关iOS项目组件化实施(一)的更多相关文章

  1. ruby - 如何在 buildr 项目中使用 Ruby 代码? - 2

    如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby​​

  2. ruby-on-rails - 项目升级后 Pow 不会更改 ruby​​ 版本 - 2

    我在我的Rails项目中使用Pow和powifygem。现在我尝试升级我的ruby​​版本(从1.9.3到2.0.0,我使用RVM)当我切换ruby​​版本、安装所有gem依赖项时,我通过运行railss并访问localhost:3000确保该应用程序正常运行以前,我通过使用pow访问http://my_app.dev来浏览我的应用程序。升级后,由于错误Bundler::RubyVersionMismatch:YourRubyversionis1.9.3,butyourGemfilespecified2.0.0,此url不起作用我尝试过的:重新创建pow应用程序重启pow服务器更新战俘

  3. ruby-on-rails - 新 Rails 项目 : 'bundle install' can't install rails in gemfile - 2

    我已经像这样安装了一个新的Rails项目:$railsnewsite它执行并到达:bundleinstall但是当它似乎尝试安装依赖项时我得到了这个错误Gem::Ext::BuildError:ERROR:Failedtobuildgemnativeextension./System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/bin/rubyextconf.rbcheckingforlibkern/OSAtomic.h...yescreatingMakefilemake"DESTDIR="cleanmake"DESTDIR="

  4. ruby - 如何验证 IO.copy_stream 是否成功 - 2

    这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下

  5. Ruby 文件 IO 定界符? - 2

    我正在尝试解析一个文本文件,该文件每行包含可变数量的单词和数字,如下所示:foo4.500bar3.001.33foobar如何读取由空格而不是换行符分隔的文件?有什么方法可以设置File("file.txt").foreach方法以使用空格而不是换行符作为分隔符? 最佳答案 接受的答案将slurp文件,这可能是大文本文件的问题。更好的解决方案是IO.foreach.它是惯用的,将按字符流式传输文件:File.foreach(filename,""){|string|putsstring}包含“thisisanexample”结果的

  6. Ruby 从大范围中获取第 n 个项目 - 2

    假设我有这个范围:("aaaaa".."zzzzz")如何在不事先/每次生成整个项目的情况下从范围中获取第N个项目? 最佳答案 一种快速简便的方法:("aaaaa".."zzzzz").first(42).last#==>"aaabp"如果出于某种原因你不得不一遍又一遍地这样做,或者如果你需要避免为前N个元素构建中间数组,你可以这样写:moduleEnumerabledefskip(n)returnto_enum:skip,nunlessblock_given?each_with_indexdo|item,index|yieldit

  7. Get https://registry-1.docker.io/v2/: net/http: request canceled while waiting - 2

    1.错误信息:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders)或者:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:TLShandshaketimeout2.报错原因:docker使用的镜像网址默认为国外,下载容易超时,需要修改成国内镜像地址(首先阿里

  8. ruby - 为什么不能使用类IO的实例方法noecho? - 2

    print"Enteryourpassword:"pass=STDIN.noecho(&:gets)puts"Yourpasswordis#{pass}!"输出:Enteryourpassword:input.rb:2:in`':undefinedmethod`noecho'for#>(NoMethodError) 最佳答案 一开始require'io/console'后来的Ruby1.9.3 关于ruby-为什么不能使用类IO的实例方法noecho?,我们在StackOverflow上

  9. ruby - 如何在 Ruby 字符串中插入项目符号字符? - 2

    我正在尝试创建一个带有项目符号字符的Ruby1.9.3字符串。str="•"+"helloworld"但是,当我输入它时,我收到有关非ASCII字符的语法错误。我该怎么做? 最佳答案 你可以把Unicode字符放在那里。str="\u2022"+"helloworld" 关于ruby-如何在Ruby字符串中插入项目符号字符?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/1195

  10. ruby - 在 Rails 项目中测试本地版本的 gem - 2

    我的Rails站点使用了一个确实不是很好的gem。每次我需要做一些新的事情时,我最终不得不花费与向实际Rails项目添加代码一样多的时间来为gem添加功能。但我不介意,我将我的Gemfile设置为指向我的gem的GitHub分支(我尝试提交PR,但维护者似乎已经下台)。问题是我真的没有找到一种合理的方法来测试我添加到gem的新东西。在railsc中测试它会特别好,但我能想到的唯一方法是a)更改~/.rvm/gems/.../foo。rb,这看起来不对或者b)升级版本,推送到Github,然后运行​​bundleup,这除了耗时之外显然是一场灾难,因为我不确定我所做的promise是否正

随机推荐