大型移动办公APP工程如何实现业务模块组件化
BOX是一款跨多语言多平台用于生产力协作的综合型移动应用,且设计之初就考虑到单独的业务模块后续会复用到其它app的业务场景,因此我们采用组件化设计开发模式,所谓的组件化设计开发模式,就是把APP根据业务拆分为各独立的组件,各个组件相互协作,组成完整的APP,很多通用方案只是组件化的冰山一角,实际落地过程中还有相当多的东西需要考量,本文我们只是通过相关的实践经验总结和思考分析,提供一种解题思路,希望对遇到类似问题的同学能有所启发。
一、需要解决的问题
首先思考如下几类问题,我们在平时开发中是如何优雅地解决的。
1.app内复杂的跳转逻辑:
react router路由传参例如点击桌面推送消息可以直接跳转到“我的二维码名片”。“我的二维码名片”界面在我的里面的第三级界面。或者再极端一点,产品给了更加变态的需求,要求跳转到App内部第n层的界面,怎么处理?
如何能统一iOS和Android两端的页面跳转逻辑?甚至如何能统一三端的请求资源的方式?项目里面某些模块会混合ReactNative,H5界面,这些界面还会调用Native的界面,以及Native的组件。那么,如何能统一Web端和Native端请求资源的方式?
自家的一系列App之间如何相互跳转问题,如APP1使用APP2授权登录怎么处理?
2.多人开发冲突问题:A同学开发的功能依赖B同学的功能?多位同学开发修改同一文件导致的冲突问题?
3.特殊业务场景:如果使用了动态下发配置文件来配置App的跳转逻辑,那么如果做到iOS和Android两边只需共用一套配置文件?
如果App出现了bug,如何不用JSPatch,就能做到简单的热修复功能?比如App上线突然遇到了紧急bug,能否把页面动态降级成H5,ReactNative?或者是直接换成一个本地的错误界面?
如何在App任何界面都可以调用同一个界面或者同一个组件?只能在AppDelegate里面注册单例来实现?
比如App出现问题了,用户可能在任何界面,如何随时随地的让用户强制登出?或者强制都跳转到同一个本地的error界面?或者跳转到相应的H5,ReactNative界面?如何让用户在任何界面,随时随地的弹出一个View ?
这些都是BOX实践过程中遇到的客观问题,为了解决这些问题我们经过多次迭代演变成现有的APP架构,大部分问题通过路由组件都能友好地解决掉。
4.技术选型
调研目前市场上的主流移动框架,能够符合大型移动APP开发的不过三种:原生开发、ReactNative(停更)和Flutter。React Native的优势在于JavaScript和React的丰富生态,并且支持热更新,劣势是在界面兼容和性能上不及Flutter,Flutter的优势在于高性能的界面开发、控件平台无关性和多平台支持,最明显的劣势是不支持热更新,同时目前生态不及React Native丰富。考虑到BOX的平台特殊性及后续维护成本及平台兼容性,我们选择原生开发+RN热更新混合。
iOS平台语言:object-c + swift;Android平台语言:java + konlit;
其中单页面会引入RN,提高人效并保证体验一致性。
二、设计架构
1.初期结构
App的开发类似于汽车生产过程,有的团队造轮子,有的团队造发动机,需要的零件组装在一起,套个壳换层漆,上线!
2.代码管理
组件化可以利用 git 源代码管理工具的便利性来实施,具体就是建立一个项目工程的私有化仓库,然后把各个组件的 podspec 上传到私有仓库,在需要用到组件时,直接从仓库里面取。
3.目录结构
4.壳工程
MainBox:用于引入各pod模块及配置管理;AppDelegate:module初始化及处理简单场景逻辑。
5.封装公共库和基础 UI 库
在具体的项目开发过程中,我们常会用到三方库和自己封装的 UI 库,我们可以把这些库封装成组件,然后在项目里用 pod 进行管理。其中,针对三方库,最好再封装一层,使我们的项目部直接依赖三方库,方便后续开发过程中的更换。
6.独立业务模块化
在开发过程中,对一些独立的模块,如:SSO登录模块、IM模块,云空间等等,都封装成组件,因为这些组件是项目强依赖的,调用的频次比较高。另外,在拆分组件化的过程中,拆分的粒度要合适,尽量做到组件的独立性。同时,组件化是一个渐进的过程,不可能把一个完整的工程一下子全部组件化,要分步进行,通过不停地迭代,来最终实现项目的组件化。
7.公共组件
常用的公共组件有以下组件:埋点组件(ZTruck)、Common 组件(ZTool)、启动组件(ZLaunch)、性能监控组件(ZDebug)、定位组件(ZLocation)、图片处理组件(ZWebImage)、UIKit 封装和扩展组件(ZUIKit,ZKit)、持久化组件(ZDataBase)、布局组件(ZLayout)、分享组件(ZShare)、推送组件(ZPush)、日志组件(ZLogan)、基础业务组件(ZBaseUI)、跨平台桥接库(ZRN)、基于 AFNetworking 进行封装,提供 JSON 转 Model、缓存功能等。
三、实施
简单来看,APP的每个模块都是独立的可运行Module,假如我们的APP 有M-A、M-B、M-C、M-D各模块必然设置各种相互跳转,通常业务简单的app 我们会通用import方式导入头文件引用。那么,我们APP的跳转依赖逻辑如下图所示:
随着业务越来越复杂,我们封装的组件越来越多,要是封装的粒度拿捏不准,就会出现大量组件之间耦
合度高的问题。组件的粒度可以随着业务的调整,不断的调整组件职责的划分。但是组件之间的调用依旧不可避免,相互调用对方组件暴露的接口。如何减少各个组件之间的耦合度,是