一、前言
1.1 什么是组件化
组件:强调物理拆分,以便复用。例如:图片库
,网络库
等。
模块:强调逻辑拆分,以便解耦。例如:订单模块
,账户模块
等。
介于业界习惯称之为组件化
,所以我们继续使用这个术语。【组件化 = 功能组件
+ 业务模块
】
1.2 为什么要组件化
- 解决代码(工程)臃肿问题,提高编译速度。
- 核心业务
模块化
,职责分离,提高代码安全性。 - 通用功能
组件化
,提高复用率及完整性。 协议编程
具体化,形成独立子系统,可灵活配置。- 提高模块自治力,独立升级部署,相互间不形成绝对依赖。
- 支持异构,提升系统技术多元化能力。
二、业界方案
2.1 组件化演进之路
// TODO
2.2 微服务概念
2.2.1 三个⻆色
服务中介:联系服务提供者
和服务消费者
的桥梁。
服务提供者:将自己提供的服务地址注册
到服务中介。
服务消费者:从服务中介那里查找自己想要的服务的地址,然后享受这个服务。
2.2.2 三个⻆色在iOS组件化中的体现
iOS客户端
是一个单工程设计,简单说就是APP作为一个独立个体,所有的业务生命周期与APP是一致的。并不能真正实现微服务中的“每个服务完全独立生存、管理、销毁”。为此,组件化更多是解决职责分离、高复用、独立发布 (非独立运行)问题。
iOS中服务提供者通常指的是业务提供方,比如:行情模块需要调用交易模块的交易记录接口,此时交易模块即作为服务提供者。而行情模块作为服务需求方,即为服务消费者。由于模块与模块之间可能处于同一级,也可以不同 级。按照《软件工程设计:分层概述》原则,同一级模块间不能相互依赖,也就是不能相互直接调用。此时就需要 一个服务中介来解决模块间通信问题。
2.3 组件间通信常⻅方案
2.3.1 基于路由 URL 的 UI ⻚面统跳管理
概念
统跳路由是⻚面解耦的最常⻅方式,大量应用于前端⻚面
。
通过把一个 URL 与一个⻚面绑定,需要时通过 URL 可以方便的打开相应⻚面。 比如
bebull://quote/stockDetail?stock_id=00700 /**个股报价⻚**/
优点
多端一致
,H5、iOS、Android、Weex/RN/Cameron 、PC、Mac等。- 浏览器、其他APP可以通过openURL直接唤起APP指定⻚面。
- 可结合服务端下发配置表,动态绑定/解绑指定URL实现⻚面灰度。
缺点
- 无法支撑较为复杂操作及数据传输模型,比如跨模块⻓调用链场景。
2.3.2 基于反射的远程接口调用封装
概念
此类型适合动态语言,借助反射技术进行动态化调用,比如OC
的Runtime,可以采用以下方式调用:
Class quoteManager = NSClassFromString(@"QuoteManager");
NSArray *stockList = [quoteManager performSelector:@selector(getStockList)];
优点
- 调用较为方便
- 代码自动补全
- 编译检查有效
缺点
- 存在hardcode问题
Swift
静态语言不支持Runtime
2.3.3 基于面向协议思想的服务注册方案
概念
参考后端Dubbo服务框架,通过服务注册的方式来实现远程接口调用的。 即每个模块提供自己对外服务的协议声明(Protocol),然后将此声明注册到服务中介。调用方能从服务中介看到 存在哪些服务接口,然后直接调用即可。
@protocol QuoteModuleService
- (NSArray * _Nullable)getStockList;
@end
@interface QuoteModule : NSObject<QuoteModuleService>
@end
@implementation QuoteModule
+ (void)load {
[ServiceManager registerService:@protocol(QuoteModuleService)
withModule:self.class];
}
- (NSArray * _Nullable)getStockList {
return nil;
}
@end
id<QuoteModuleService> module = [ServiceManager
objByService:@protocol(QuoteModuleService)];
NSArray *stockList = [module getStockList];
优点
- 调用方便
- 代码自动补全
- 无需hardcode,面向协议,减少对接错误⻛险
缺点
- 高度依赖协议,协议变更时容易导致所有依赖方编译失败。
- 存在服务注册过程,有一定性能开销。
2.3.4 基于通知的广播方案
概念
直接基于系统的 NSNotificationCenter。
优点
- 实现简单。
- 适合一对多场景。
缺点
- 不适合复杂数据传输场景。
- 同步调用不方便。
三、架构设计思路
3.1 目标
- 业务模块分离,业务职责单一,划清边界。
- 业务模块间通信灵活且统一化。
- 业务模块间通信协议严格标准化,具备准入原则。
- 通用逻辑独立化,构建稳定后采用二进制形式链接。
- ⻚面多端统一性,方便后续
PAAS化
(可由服务端自主下发配置,灵活管理⻚面调用及组合)。 - 代码安全,只开放必要的模块代码权限。
- 服务异构化,后续部分模块可以采用更多语言如
c++
、python
等开发后引入。 - 设计模式规范化,明确各场景采用
MVC
、MVVM
等,如何组织类关系等。
3.2 组件间通信场景
3.2.1 场景一:UI独立⻚面
采用 路由 URL 的 UI ⻚面统跳管理方案
,实现跨端 + 端内任何场景可直接唤起指定⻚面能力。
3.2.2 场景二:跨模块UI嵌套
采用 基于面向协议思想的服务注册方案
,通过 BNBee组件中心
的 UIService
进行服务调用,获得指定的 View、VC。
3.2.3 场景三:跨模块数据传输
采用 基于面向协议思想的服务注册方案
,通过 BNBee组件中心
的 OpenService
进行服务调用,提供同步返回
(sync)和 异步返回(async)能力。
四、架构分层
4.1 图示

4.2 各层职责
总体分为 业务层、公共层、基础框架层 三层。
业务层
- 承担业务层面相关工作
- 主要包括
VC
、View
、Model
、ViewModel
、DC
、Manager
、APIClient
等 - 目前阶段分为行情、交易、资讯、账户、公共主体五类
公共层职责
- 承担整体性非业务相关的相关工作。
- 主要包括公共相关事务(如BNURLHelper),组件间通信API、Model,以及皮肤资源整合。
- 目前阶段分为公共基础平台、业务间通信API、皮肤资源中心。
基础框架层职责
- 包含一些日常使用,趋于稳定的库。
- 主要分为自研和第三方依赖两大类。
- 自研部分采用
framework
静态库方式,基于pod
引入。
4.3 各层间依赖关系
- 同层之间禁止直接依赖,通信方式通过BNBee组件服务中心。提供方提供具体实现,将协议定义于BNUAPI工程中;消费方于BNUAPI中获得对应API及model。
- 上层可以直接引用下层,也可以跨层下级引用
- 下层禁止引用上层。
4.4 模块说明
行情模块
:包括行情一级tab下的自选列表、市场列表、个股报价⻚等。交易模块
:包括交易一级tab下的开户、资金账户、持仓、买入卖出、交易记录、入金出金等。资讯模块
:包括资讯一级tab下的资讯列表、资讯详情⻚等。账户模块
:包括我的一级tab下的用户登录、注册、个人资料等。公共基础平台
:主要涵盖与业务无关的部分,包括暂时找不到基础框架层可以下沉的暂留组件,比如:WebView、 tabbar等。业务间通信API
:主要负责上层业务模块的组件间通信API协议定义、传输model定义、业务通知key等。 皮肤资源中心:存放所有必牛项目的图片、lottie动画等资源。
4.5 模块内结构
五、BNBee(待补充)
5.1 基本能力
5.2 URL注册绑定
5.3 面向协议服务注册
六、自研框架库
6.1 目标
- 将重要且需要稳定的模块独立出来,抽离成
framework
,实现复用性、稳定性、安全性目标。 - 标准化一些常用逻辑,做到多业务一致。
- 代码安全,只开放必要的代码权限。
- 服务异构化,后续可以采用更多语言如
c++
、python
等开发更多底层框架。
6.2 组件库
- 网络组件库:负责
socket⻓连接
管理、HTTPS短链接
生命周期、连接、安全、可靠性管理。 - 组件服务中心:负责管理
组件间通信
,提供基于URL注册、协议绑定等方案管理。 - 日志组件库:分级日志系统,对
info
、warning
、error
、file
及日志收集、存取和上报管理。 - 开发组件库:日常开发常用的
工具类
、系统类
、分类
等。 - 数据上报组件库:直接接驳三方数据上报平台,提供与上报平台无关的通用接口,包括
曝光时⻓
、曝光量
等统计接口。 - 分享组件库:主要提供通用分享组件,包括分享到
QQ
、微信
、Twitter
等。 - UI组件库:主要沉淀通用UI组件,如嵌套
Scrollview
,tabbar
等。 - 数据管理组件库:主要包装
内存级缓存
及磁盘级缓存
的接口,后端对接沙盒、SQLite
数据库等。 - 皮肤组件库:主要提供style定义系统,用于约定常用UI组件如
UIButton
、UIView
的多肤管理。 - 健康防护系统:防范常⻅类型
crash
兜底,启动连续crash绕行
等方案。 - k线组件库:k线组件作为核心性能指标,沉淀出来方便后续各业务使用。
七、第三方依赖库
7.1 设定准入标准
券商APP的安全性不容小觑,对于第三方依赖库的引入需持有谨慎的态度;因此后期需要增加第三方依赖库的准入 机制,形成选型
、评审
、安全鉴定
和引入
的原则。同时,尽量剔除一些功能重复、失去维护、功能滞后的三方库, 保证APP包大小
、启动性能
等各项指标。
7.2 选型需明确
如:选新不选旧 or 稳定大于能力?Swift实现的优先?轻量化还是重量级?是否跨端配套⻬全?等等问题,需要有 明确的标准,组件化工作落地后,需要再明确这块,保证快捷接入的同时,可以更稳定、更一致。