GTLC全球技术领导力峰会·上海站,首批讲师正式上线! 了解详情
写点什么

iOS 业务组件化框架 Axe

2018 年 5 月 29 日

Axe框架是一个开源的 iOS 业务组件化框架。本文介绍Axe框架的业务组件化思路,并介绍基于Axe框架,实现的组件动态化与开发管理平台化。

一、使用 Axe 框架实现业务组件化

业务组件化是近几年非常火的 APP 架构思路, 究其原因,随着业务发展,APP 的规模也逐渐膨胀,代码管理与协作开发变得困难,编译耗时也屡创新高,应用功能的拆分与研发团队的拆分也不可避免。 这些发展需要 APP 架构的变更,以支持大型 APP 的开发,支持跨团队的协作。而解决方案就是将各个业务拆分成独立组件,从主工程中脱离,进行单独开发、编译、测试,不与其他业务组件相互耦合。

组件化方案,需要解决三个问题:

  1. 代码隔离 : 最基本的要求,使组件可以单独开发。
  2. 单独编译 : 组件单独构建编译,以提高 APP 编译速度,并为单独测试提供基础。
  3. 组件交互 : 满足组件之间交互的合理需求。

代码隔离

代码隔离比较容易实现,代码解耦,然后分离建仓,最后通过Cocoapods来管理引用。

单独编译

组件单独编译,构建成Framework静态库。

组件同时需要有源码版本,以进行调试。

组件的编译接入持续集成系统,一般会使用管理平台来管理组件的构建,下文中会提及。

组件交互

业务组件之间的沟通协调,是组件化中最关键的技术点, 一般的组件化方案,强调通过一种协议机制或者target-action的方式来实现。 而Axe中的组件交互,分为三个部分:

数据

我们将数据抽离出来,作为组件交互的重要一环 ,组件间的数据交互分为两种:

  1. 数据共享 : 共享的是所有组件都可以获取的数据。
  2. 数据传递 : 数据也可以附着在路由和事件中传递。

单独的数据组件,是为了解决特殊类型数据的问题。 我们支持特殊数据类型,如图片、二进制数据、Model类型等。

路由

界面逻辑的处理交给路由。

根据路由的表现,我们定义两种路由:

  • 跳转路由 : 进行页面跳转,如使用UINavigationControllerpush,以打开一个新页面。
  • 视图路由 : 返回一个界面元素, 即返回一个UIViewController, 以满足嵌套页面的需求, 如 侧边栏、Tab 栏等页面。

路由的表现形式是一个URL, 如同大多数的路由方案一样。默认支持的路由是Axe路由,结构为:

复制代码
axe://{moduleName}/{pageName}

如果URL附带参数,会自动转换为数据类型。路由支持回调处理。

Axe的路由支持协议扩展,以实现自定义的路由处理。

事件

使用事件监听机制,以实现更加灵活方便的跨组件交互。

在事件实现中,我们提供了方便好用的接口 :Axe中的事件支持 同步、异步、优先级设定。 并且实现了两个特殊的功能:

1. 组件初始化: 基于事件通知实现组件自注册。 通过事件中的优先级和同异步设定,来进行组件初始化的排序与管理。

上图是简单的示例,进行登录组件的初始化,该部分代码放在登录组件内部。当接入登录组件时,就会在启动时自动初始化,以注册路由。

2. 界面监听 : 提供一种适用于界面展示的监听接口,该监听会保留回调,直到页面回到前台才执行;且同名的通知,不会出现重复处理,只会使用最新的数据执行一次。

事件中可以附带数据。

总结

通过 路由事件监听 , 我们为组件之间的交互提供了完善的支持。且实现了组件之间的代码完全无依赖。 组件交互时,只需要知道 调用的路由地址, 事件的名称,以及数据的键值与类型 (与 Model数据的结构) ,只需要知道这些声明即可 (通过字符串的形式)。 一个声明文件的示例:

这也为后续支持其他容器的组件提供了基础。

二、基于Axe 实现组件动态化

在APP 动态化的需求下,使用 H5React Native成为很多APP的选择。 而我们也在Axe框架的基础上,再做优化,以更好的适应动态性的需求。

扩展容器

Axe不仅要支持iOS原生页面,也要支持WebView容器和React Native容器,使这两类业务组件也能够像原生一样,通过Axe接入组件化系统。

首先,通过协议扩展,在Axe上注册协议路由 : httpsreacts , 使其他组件可以通过路由调用这些页面。扩展后,我们可以使用路由跳转到H5页面:

复制代码
[self jumpTo:@"https://demo.axe-org.cn/login-h5/#/"];

然后做Native与容器之间的桥接 :在WebView上使用WebViewJavascriptBridge作为JavaScript的桥接,在React Native通过添加Native Module来做桥接 , 调用Axe来处理路由跳转、事件通知和数据请求。 路由与通知比较简单, 重点是数据, 我们通过特殊处理(标明类型和自动转换),以支持特殊类型的数据如NSDateNSDataUIImageModel等特殊类型,能在原生和JavaScript之间传递:

如上图代码所示,左侧是原生组件中的 OC代码,右侧是扩展容器的JavaScript代码,Axe能够做到跨容器传递数据,甚至特殊类型,如图片、Model等。

通过桥接处理,目前我们使WebViewReact Native容器接入了组件化,可以通过Axe调用其他组件,也可以通过Axe被其他组件调用, 使这两个容器在使用和表现上与原生组件完全一样

离线包支持

为了更好地使用JavaScript的容器,Axe提供了一套简单的离线包方案。 离线包指 : 将资源打包整合,统一管理下发,以使 APP 可以在离线的情况下,使用本地资源加载页面。

使用离线包,可以节约用户流量,提高页面加载速度,提高用户体验。 当前实现的简单离线包,使用bsdiff进行差分,支持上传到oss, 支持跟随APP打包,且拥有一个有趣的签名机制。

我们进行协议扩展 :

  • ophttp: 基于离线包的H5容器,路由 URL 形式是ophttp:// 组件 / 页面
  • oprn : 基于离线包的React-Native容器,路由 URL 格式是 oprn:// 组件 / 页面

组件等同性

Axe中强调组件等同性 , 即 如果两个组件实现了同样的声明 , 拥有相同的业务逻辑 (被其他组件调用表现一致),那这两个组件,在Axe组件化体系中就可以视为 相同的组件, 就可以互相替换。

所以,在Axe组件化下,我们不关注组件的实现,只关注组件的业务逻辑, 只关注组件的声明文件,只关注组件提供的页面、事件和数据。组件等同性,使组件可以互相替换。在Axe组件化下替换组件的实现,不会影响其他业务组件的运行。

组件等同性,使我们可以为业务组件开发多个版本,使不同的用户使用不同的版本,以实现基于组件化方案的组件灰度测试。

动态路由

组件等同性 要求相同的路由,但是我们知道,传统的路由只能对应一个具体页面。

所以为了使用组件等同性, Axe提出一个声明路由的概念, 声明路由是对实现路由的包装。使用动态路由后,组件的声明文件中标明的是声明路由 。所有业务组件通过声明路由来访问其他组件,而实际跳转时,再根据路由配置转换为实现路由

Axe提供了一个简单的动态路由服务, 通过这个服务管理和下发路由映射配置,使应用拥有线上动态切换组件实现的能力。

三、对组件开发进行平台化管理

基于Axe框架,我们实现了业务组件化, 组件动态化, 然后我们还要再进一步,实现组件管理平台化。

即通过一个平台,来规范组件化 APP 的开发、构建、测试、接入、发布流程,优化跨小组、团队、部门的协作开发,以做到协作开发的平台化。 平台化关注的问题有 :

APP 架构

Axe组件化下,我们推荐将公共业务和基础组件合成一个组件,称之为Ground, 地基组件,用于管理公共业务和公共的基础组件。

这样做的原因 :

  1. 统一管理基础内容的版本:业务组件开发时,只需要依赖Ground组件,而不需要过度关注具体基础组件的版本。
  2. 将零散琐碎的基础组件统一起来,编译成一个整体,减少了组件数量, 一定程度上优化 APP 的整体架构。
  3. 能够很好的处理基础组件中的.a.framework静态库。

Axe通过脚本自动处理Ground项目中包含的子组件的头文件,使业务组件可以通过正常的头文件引入方式来使用基础组件。

代码管理

使用gitlab

对于版本,建立版本分支,如version/0.0.1,设置权限,确保所有提交都经过代码检视。

使用git-lfs管理 二进制文件。

项目管理

对于组件和 APP 的版本,我们要明确并记录项目的时间节点,严格按照计划执行项目。

控制组件版本的接入 :组件的版本,必须经过 APP 管理人员的审核,才能接入 APP 中。

协作开发

组件的接口与更新日志要妥善的归档记录。

多组件协作开发时,需要提前设计好接口,以并发开发。设定好开发计划,以确保组件都能按时完成。最后合并在一起接入到 APP 中。

版本管理

组件版本号的管理,遵循语义化版本号,即使用 主版本号. 次版本号. 修订号 。然后,在使用Cocoapods进行组件版本的管理时,我们的处理方式是:

  1. 指定 具体组件版本。
  2. 只保留Podfile , 不上传Podfile.lock

在开发测试阶段,我们加入一个beta版本 :通过先行版本,做开发版本的自动提升,以解决开发阶段的版本频繁变更的问题。 在完成开发测试后,构建release版本进行最终发布与封版:

需要注意的是, pod依赖的编写,是使用工具自动处理,所以不用担心对开发阶段造成困惑。

业务开发者只需要知道,在没有打release版本之前,可以随意的构建beta版本,而其他人使用时,也会自动的接入到最新的beta版本。

持续集成

使用fastlaneJenkins做持续集成,fastlane编写脚本处理组件的管理、接入与打包。

自动化测试

由于Axe组件化中,一个组件最重要的是其声明。 所以自动化测试的内容,就是按照声明调用接口, 然后检测返回值是否正确。

在测试过程中一些重要节点进行截图,以快速检测 UI 问题。

自动化测试在 0.1.0 的Axe中并未实现。

组件开发管理平台

以上是Axe的解决方案的大致介绍。 同时Axe 提供了一个简单的组件化开发管理平台。该用来管理 :

  • 组件的开发计划
  • 组件的文档
  • 组件的构建
  • APP 的开发计划
  • 组件的接入和升级管理

当前Demo网址为 demo.axe-org.cn 。接下来我们简单介绍一下这套系统中的有趣或重要的地方:

时间线

APP版本或者组件版本开始前,先制定一个时间计划,指明 APP 版本或组件版本的重要时间节点 :

APP 版本概览

右侧是 APP的依赖图,通过脚本自动绘制。

组件概览

组件版本概览

右侧记录版本的更新日志。

组件API 文档

API文档,也就是上述的声明文件, 用于声明其支持的路由,暴露的数据和发送的通知。

组件依赖情况

依赖图是脚本自动绘制的。

连线括号内是声明的版本限制,而圆圈括号内是具体使用的版本号。

组件构建

对接jenkins,调用组件构建任务,自动打包并提交版本。

接入管理

当一个业务组件开发完成后,需要提交接入APP 的申请,由 APP管理员查看并确认,才能接入该版本。

总结

基于Axe框架,我们实现 iOS 应用的业务组件化,并在此基础上,进行动态化的扩展,最后更进一步,实现平台化的管理。目前项目开源在 github, 地址为 axe-org/axe ,我们会持续维护与更新,欢迎大家来体验、抓虫与吐槽。

感谢覃云对本文的审校。

2018 年 5 月 29 日 17:582719

评论

发布
暂无评论
发现更多内容

【STM32】PWM 输出 (标准库)

AXYZdong

硬件 stm32 2月春节不断更

3.Fiber(我是在内存中的dom)

全栈潇晨

React React Hooks react源码

【LeetCode】重塑矩阵Java题解

HQ数字卡

算法 LeetCode 2月春节不断更

Elasticsearch mapping 复杂数据类型

escray

elastic 七日更 死磕Elasticsearch 60天通过Elastic认证考试 2月春节不断更

一维数组的动态和

小马哥

算法

华为云FusionInsight MRS在金融行业存算分离的实践

华为云开发者社区

大数据 金融 华为云 存算分离 FusionInsight MRS

阿里云大佬爆裂推荐“redis全新手册”,内容即精华

比伯

Java redis 程序员 架构 程序人生

第 4 周作业

老元宵

话题讨论 | 如何使用“网站SEO”,让网站排在最前面?

魔王哪吒

前端 后端 话题讨论 SEO 2月春节不断更

哲少荐书:鞋狗

Jackey

书籍推荐

区块链挖矿系统APP开发|区块链挖矿软件开发(现成)

v16629866266

字幕组时代落幕,翻译的未来可能是?

字节跳动技术团队

端口隔离和VLAN的区别

【STM32】EXTI---外部中断/事件控制器

AXYZdong

硬件 stm32 2月春节不断更

心理声学基础

行者AI

心理 音乐

【函数计算实践】nodejs初探示例——本地mac环境

程序员架构进阶

架构 nodejs 函数计算 七日更 2月春节不断更

算法从有序数组中移除重复的数据,AI学习资源2020 John 易筋 ARTS 打卡 Week 38

John(易筋)

ARTS 打卡计划 ai youbute学习资源

什么是阻抗?

不脱发的程序猿

阻抗 电路设计 电子元器件

LeetCode题解:1091. 二进制矩阵中的最短路径,BFS,JavaScript,详细注释

Lee Chen

算法 LeetCode 前端进阶训练营

用例文档

三生赤水

如何 1 天快速集成自己的“Clubhouse”?

融云 RongCloud

音视频 clubhouse 语音社交 融云

gradle中的增量构建

程序那些事

maven Gradle 程序那些事 构建工具

IDEA插件:快速删除Java代码中的注释

xiaoxi666

代码注释 Java 8 JavaParser

门诊数字化:患者信息识别方式

boshi

医疗 数字化基础 七日更

面试的季节到了,老哥确定不来复习下数据结构吗

Silently9527

面试 数据结构与算法

EternalWallet为您提供快速、便捷、低价的国际汇款服务

Geek_c610c0

第四章作业-编写一个用例文档

秦挺

up主周月纪念日前夜总结文

Kylin

视频创作 自媒体 up主 周月纪念日

日记 2021年2月18日(周四)

Changing Lin

2月春节不断更

ElasticSearch.04 - 基础操作

insight

elasticsearch 2月春节不断更

厉害了!这群95后正在用三维成像技术让科幻变成现实

华为云开发者社区

视频 华为云 三维 裸眼 光学

DNSPod与开源应用专场

DNSPod与开源应用专场

iOS业务组件化框架 Axe-InfoQ