知乎 iOS 客户端工程化工具 Venom
更多移动技术文章请关注本文集:知乎移动平台专栏
前言
知乎 iOS 客户端从一开始围绕问答社区到目前涵盖 Feed,会员,商业,文章,想法等多个业务线的综合内容生产与消费平台。项目的复杂程度已经在超级 App 的范畴。单周发布与业务并行开发也逐渐变成主流。同时在知乎 iOS 平台,技术选型一直也都比较开(sui)放(yi)。较早了引入了 Swift 进行业务开发,列表引入了需要 OC++ 的 ComponentKit 作为核心引擎。所以在这种多业务方团队,技术形态复杂,组件仓库数量多等场景下,也同样遇到了各种超级 App 团队都面临的一些问题。
问题如下:
- 如何统一开发环境
- 提高编译速度
- 提高打包速度
- 二进制组件调试
- 多组件联合调试
- 多组件联合打包
- 约束组件依赖关系等
当然在思考解决上面这些问题前,知乎 iOS 项目也同样经历过组件化的工作。与众多组件化拆分方案殊途同归,进行了业务划分,主仓库代码清空,业务线及 SDK 进行独立仓库管理。引入基于路由,基于协议声明的组件间通信等机制等,这里就不多赘述了。
简介
核心介绍的项目名称为 Venom,灵感来源于电影《毒液》。Venom 的用户端是一款为开发人员打造 Mac App,应用内置了工程构建需要的全套 Ruby Gem 和 Cocoapods 等其相关构建环境。核心目标是解决工程构建,二进制构建,组件管理,调试工具等一系列开发过程中的繁琐耗时任务。
image所以当一台全新的 Mac 电脑希望运行工程时, 只需要 3 步:
- 安装 Venom For Mac 客户端。
- 使用 Venom 打开工程点击 Make 按钮。
- 构建完成点击 XCode 按钮打开工程。(当然默认己装 XCode )
从此告别 ruby,cocoapods 版本不对,gem 问题,bundle 问题以及权限问题等困扰。因为构建环境内置,使得构建环境与工程师本地环境隔离,极大的降低了工程 setup 的成本。
完整的 Venom 包含了 3 个部分:
- Venom App
- Venom 内核
- Venom Server
下面会着重介绍客户端和内核相关的技术方案,数据服务目前仅为组件的附加信息提供 API 支持。
Venom 内核介绍
在引入 Venom 前,一直使用 Cocoapods 的 Podfile 进行组件的引用。但如果希望对 pod 命令的 DSL 进行扩展,发现是不够方便的。索性在 Cocoapods 上层建立自己的组件描述文件,每一个描述文件最终都会被转化为一次 podfile 的 pod 调用。
image如上图,使用 Venom 方式集成的项目,由在 VenomFiles 目录内的组建描述文件组成。
组件描述文件
VenomFile.new do |v| v.name = 'XXModuleA' v.git = 'git@git.abc.abc.com:Team-iOS-Module/XXModule.git' v.tag = '1.0.0' v.binary = false v.use_module_map = true v.XX...end
组件描述文件可以理解是 pod 命令的一个超集,在包含了 pod 的原有功能基础上,扩展其他功能(胶水代码创建,二进制化与源码切换等)。
组件调试
同时在与 VenomFile 同级别还设计了一个 Customization.yml 的文件。当开发过程中,需要对某个组件进行源码二进制的切换,或者源码路径的切换,版本引用的切换等,不会直接改动 VenomFile,会改动 Customization.yml 来进行。在构建过程中的优先,Customization.yml > Venomfile 。为了每个工程师的改动不会互相影响,Customization.yml 是非 git 托管的。而 VenomFiles 内的文件只有更新版本号或其他配置改动,才会更新。
构建过程
所有组件都通过一个个 Venomfile 文件方式管理在主工程仓库中,通过目录对组件进行层级划分管理。
image原来的 Podfile 文件通过嵌入 Venom 进行构建职责的接管。
image使用 Venom 后 pod install 的实际过程就如下图:
image整体上来看, Venom 内核提供了一套扩展 pod 属性的描述文件,开发阶段通过 customization.yml 进行可配置的构建。构建过程中,依赖 Venomfile 文件的唯一标识进行二进制库和源码的关联。通过对 Cocoapods 构建过程的 hook 实现二进制与源码的引用切换。二进制化方案可参考 :
Xinyu Zhao:知乎 iOS 基于 CocoaPods 实现的二进制化方案
命令接口
Venom 内核除了主要的构建职责,还提供了一系列的 ipc 命令。通过这些 ipc 命令,上层的 Venom 客户端就可以更容易的操作每个组件,进行定制化的开发组织。来构建工程。
例如:
复制代码
// 修改组件二进制使用方式,使用二进制venom ipc customization \ --path /Users/abc/Developer/zhihu/abc/def \ --edit \ --name ZHModuleABC \ --binary// 修改组件二进制使用方式,使用源码venom ipc customization \ --path /Users/abc/Developer/zhihu/abc/def \ --edit \ --name ZHModuleABC \ --source// 修改 yml 文件中指定组件的路径venom ipc customization \ --path /Users/abc/Developer/zhihu/abc/def \ --edit \ --name ZHModuleABC \ --pod_path /path/to/ZHModuleABC// reset 某个组件在 customization 中的 change,不指定 name 参数会给整个文件置成空venom ipc customization \ --path /xxx \ --reset \ --name ZHModuleABC
Venom App 介绍
通过对 Venom 内核的简单介绍,其实可以认为,只通过命令行版的工具,就可以达到用到的大部分功能。但因为实际开发情况一般不会一个人一次只处理一个模块,所以希望以一种所见即所得方式来让业务工程师不用关心下层的逻辑,学习命令。可以快速建立起开发环境是我们的主要目标。
image<center style="color: rgb(74, 74, 74); font-family: Avenir, Tahoma, Arial, "PingFang SC", "Lantinghei SC", "Microsoft Yahei", "Hiragino Sans GB", "Microsoft Sans Serif", "WenQuanYi Micro Hei", Helvetica, sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">客户端主要模块</center>
Venom App 内置了全套的 guby gem 环境来运行命令。通过 CLITask 来访问 Venom-core 以及 git 等其他命令(venom 内核一样内置在 Venom App 内)。
image这样很好的控制了执行命令的环境,特别是对新入职的员工是十分友好的。
核心功能
开发组件关联
正常情况下 clone 下来的主工程(壳工程)内是没有代码的,只有空的工程文件和组件描述文件。Venom 工具划分了 2 个区域,普通组件和定制组件。
image因为每个开发者维护的组件其实是有限的几个,一般都会将源码放在固定目录,所以通过设置客户端的自动扫描路径。在 Venom 界面上,如果在扫码路径下发现了相关组件,则可以一键关联本地目录组件,这样组件会切换到定制组件的模式进行开发。
特定版本关联
image在开发过程中,有时需要对某一个依赖库的特定版本进行调试或连调。所以也支持通过 tag,commit,branch 等方式,进行特定源码的切换和关联。
源码与二进制切换
image某些特殊场景下,可能希望工程以所有组件都是源代码方式构建,排查问题。那么也可以通过 2 种不同的构建模式一键切换。(当然全源码构建一次需要十足的耐心)
二进制模式下搜索与调试
二进制化后,大部分情况下都工作在二进制模式下,但有时在进行源码搜索时,希望可以全局搜索。所以在构建过程中,会把当前版本的源码目录也引用到工程目录下。
image所以在工程进行检索代码时,是完全没问题的。有了源码,在云端进行二进制打包时,通过 fdebug-prefix-map ( Clang command line argument reference )这个参数重新在二进制文件中改写 Debug 模式的源代码路径。这样即使在二进制模式下,也可以直接关联源码进行断点调试。
组件依赖关系分析
当组件很多后,就会出现一些工程师对组件所处层级不够了解,导致出现依赖混乱的问题。所以在构建结束后会通过对组件层级的检查,进行组件依赖层级的判断。
image总结
在推进所有工程师使用 Venom 客户端后,相当于在开发环节有了一个强有力的抓手。由于 App 的自动更新功能,可以在平台下提供给开发者更多的工具,而开发者只需要更新客户端使用。通过工具化客户端的开发,我们重构了原有散落在各处的脚步,工具集中整合在一起。使得开发工具维护更统一,更新也更及时,开发人员上手成本也更低。
Venom 核心承担的是开发环境管理,工程组织与构建管理,提高工程效率工作。但上线后,我们还陆续在此基础上提供了一些其他功能。
- 多仓库 MR 自动填充提交
- 本地非独立业务仓库单元测试
- 个人开发者账号真机调试
- 无用图片扫描工具
- 轻量的 app 网络和日志查看等
另外,知乎移动平台团队也在招人中,欢迎各位 iOS 小伙伴的加入,和我们一起做一些酷事情!具体招聘信息在这里 https://app.mokahr.com/apply/zhihu/3819#/job/f15ff88f-84a9-40f1-b33d-e568b0b30812?_k=m4kqqs
关于作者
付三岁,2016 年加入知乎,现为知乎 iOS 基础架构团队负责人,有着丰富的 iOS 工程化,组件化经验,设计并主导了知乎的 iOS 组件化拆分工作