爱奇艺知识目前有多个业务承载端,包括爱奇艺移动端APP的知识插件、爱奇艺iPad端APP的知识插件、随刻移动端APP的知识插件和爱奇艺知识移动端独立APP。由于各个端上线的时间不同,所承载的业务功能也不完全一致,造成了多端多套代码的情况,维护成本很高。首先当相同或类似的功能需要迭代升级时,开发和测试都需要在多端同步进行,成本成指数级增长;其次随着业务的快速发展,业务模块在不断增加,模块间的依赖关系也变得越来越模糊,代码耦合度和复杂度都在增大;另外在现有人力成本的基础上如果想增加更多的业务端,就会变得非常困难。因此长期看非常不利于业务的高效迭代。下图描述了组件化之前,爱奇艺知识各端的业务模块架构。

爱奇艺组件化技术探索与项目实践

从上图我们也能看出其实每个端之间是存在很多公共业务模块的,各个业务模块的底层支撑模块也几乎相同,所以结合爱奇艺知识自身的业务特点,我们提出了适合于爱奇艺知识移动端的组件化方案。

[]( )1.2目标


我们将组件化的目标定义为以下几个:

· 解决多端代码维护问题

根据业务特点,横向和纵向划分组件,以组件为单位承接迭代需求,各端进行组件复用;

· 解决跨组件调用和组件间路由的问题

业务划分更加清晰、组件间解耦更加彻底、组件间通信更高效,对原有业务模块进行抽离和整合,明确组件间的业务边界;

· 提升开发效率,方便开发调试

组件可以单独编译和调试,使模块开发者更聚焦本模块业务;

· 提升集成和提测效率

各端项目需要哪个组件,可以直接通过工具快速集成和提测。

基于以上目标,我们设计了适合爱奇艺知识业务的组件划分策略,下图为组件化之后的功能架构图,横向分为基础组件、功能组件和业务组件,纵向对每个层级的组件又进行细分;从划分粒度上看,组件不仅包括功能性的sdk,还可能包括业务UI,宗旨就是业务模块独立,边界清晰,方便扩展和维护。

爱奇艺组件化技术探索与项目实践

[]( )二、整体技术架构

====================================================================

基于功能架构,知识组件化的技术架构如下图所示。

爱奇艺组件化技术探索与项目实践

最下层是基础组件,包括baselib和componentService,我们将网络库、pingback、数据库、日志和工具类等公共底层实现构成基础组件,屏蔽了系统和各端的差异,位于功能和业务组件的下层。所有功能和业务组件都使用同一套基础组件,可以保证公共部分的统一性。基础组件比较稳定,不会频繁迭代。

再往上一层是功能组件,如承载播放能力的播放器和历史记录组件、承载支付能力的支付和营销组件,、承载多端定制化分享能力的分享&海报组件等各个端都有的基础功能,功能组件位于基础组件和业务组件之间,功能组件会根据业务组件的需要而不断迭代升级。

接下来是业务组件,这层是各个端有可能包含也有可能不包含核心业务模块,为了开发和维护方便,我们将核心业务模块抽取为业务组件,如搜索、筛选、发现feed流、评论、评价、作业作品等,业务组件位于基础组件和功能组件的上层,迭代较频繁,但业务本身比较独立,边界清晰。

最上层是壳工程,各端都需要一个主工程负责集成所需要的组件,我们统称为壳工程,壳工程包括了各端的基础框架,比如组件注册和初始化逻辑,平台相关性处理逻辑等,还有各端特有的业务模块,不适合抽离和拆解的部分。

右侧是负责管理组件间交互和跳转的MoudleRouter和UIRouter。这部分是公共基础设施,各端都要集成。

左侧是构建系统,它不在组件化代码中,属于辅助系统,负责组件和各端应用包的构建。

[]( )三、核心技术实现

====================================================================

组件化实践中比较核心的两个技术点是,组件间交互和组件间路由。

[]( )3.1组件交互


组件间交互的难点是降低组件耦合度,最好能达到完全无侵入式的调用。经过调研,iOS端使用ModuleManager的方式,它被定义为最底层的服务组件,每个组件都需要对外提供被调用的服务接口,接口的定义存在于ModuleManager组件。ModuleManager的代码对其他组件代码来说是无侵入的,只负责对传递过来的数据进行解析,并将调用消息传递给对应组件。

爱奇艺组件化技术探索与项目实践

为了解决URL硬编码 ,以及字典参数类型不明确等问题,iOS端在组件化方案中选用了Protocol方案,在程序开始运行时将自身的Class注册到ModuleManager中,并将Protocol反射为字符串当做key,Class遵守协议并实现协议定义的方法,外界通过Protocol获取的Class并实例化为对象,调用服务方实现的协议方法。独立APP和各个插件的服务注册的时机不同,独立APP是在程序启动时,而插件则是外部调用插件时,在插件退出时去需要解除注册释放资源。Protocol方案描述如下:

爱奇艺组件化技术探索与项目实践

在Android端,组件间交互使用的是ZRouter组件,实现思路和iOS端类似,是参考了java中SPI机制(服务提供发现机制),每个组件对外提供一个服务接口service,接口的实现交给对应组件内。在组件初始化注册时候,会同时注册该service接口和对应service实现。业务方使用时,只需要通过service接口调用组件功能。这样组件间就没有了直接依赖关系,实现了组件间解耦隔离。具体调用如下图所示:

爱奇艺组件化技术探索与项目实践

[]( )3.2组件路由


组件间路由跳转方面,iOS端采用了注册URL的方式,注册的时机分为静态、动态和懒加载三种,懒加载方式即为在调用跳转方法时检查URL与ClassName是否已经注册绑定,如果未绑定则从模块静态信息表中获取并完成注册绑定,Handler可以在动态注册时进行指定,这样跳转逻辑即可实现完全自定义而不走底层的统一跳转逻辑,同样要注意的是插件端需要在退出插件时释放资源并取消注册。

爱奇艺组件化技术探索与项目实践

Android端针对组件间UI跳转的实现方面,虽然前面讲到的ZRouter也能做到Activity、Fragment、View之间跳转,但是代码实现过于复杂。所以我们借鉴了业内组件化的优秀思想,专门开发了一个用于组件间UI跳转的UIRouter。在编译期间,通过Activity上添加的@RouterPath注解,生成一张Key为Scheme或页面短码,Value为Activity的路由表。跳转任何一个Activity都交由路由框架,根据路由表决定启动哪个Activity。

爱奇艺组件化技术探索与项目实践

为了提升开发效率,减少UIRouter初始化时重复开发的代码,我们开发了一个插入自动注册代码的gradle插件,利用此插件在编译期通过ASM向指定方法中注入初始化代码。

同时,在组件库注册的时候也有用到这个技术;组件初始化类在debug模式下通过反射加入内存,在release模式下则通过ASM插入注册代码。这样在debug模式下可以缩短编译时间提升开发效率,在release正式包中运行时可减少反射带来的消耗。

整个优化流程如下:

爱奇艺组件化技术探索与项目实践

[]( )四、构建系统

==================================================================

有了层次清晰的组件划分,那么如何快速构建组件和项目成了必需要解决的事情。针对组件化,爱奇艺知识团队结合公司已有的构建系统,开发了一套适用于组件化的快速构建子系统。

为了解决多端共用一套代码和在各个插件端都有包大小的限制的前提下,在组件库中存在的差异代码通过宏分割来控制,实现差异代码隔离,编译时仅编译当前指定的某一端代码,打包时通过指定打包参数来设置宏配置,完成指定端的构建。

iOS端每个组件都是一个单独的工程,由不同的git私有仓库来管理,各个组件是在主项目中通过CocoaPods来集成,将所有组件当做二方库集成到主项目中。爱奇艺知识APP与各端插件虽然都采用了Cocoapods集成的方案,但是在版本依赖上有所差异,为提升开发效率,知识APP作为独立应用程序直接采用了指定git仓库tag号的方式来依赖组件库,插件则需要通过插件库的podsec设置依赖来集成组件库的,这就需要将组件库打成二进制的库文件上传到云,并上传组件库的podspec到私有库中。iOS插件端在主项目中集成组件主要分为两种方式分为源码和framework,在开发调试阶段采用源码方式,可以直接修改代码完成需求开发,在打包提测和发布时采用生成framework,可以加快编译速度不会对外暴露源码。

爱奇艺组件化技术探索与项目实践

最后笔者收集整理了一份Flutter高级入门进阶资料PDF

以下是资料目录和内容部分截图

爱奇艺组件化技术探索与项目实践
爱奇艺组件化技术探索与项目实践
里面包括详细的知识点讲解分析,带你一个星期入门Flutter。还有130个进阶学习项目实战视频教程,让你秒变大前端。学不会来打我!
爱奇艺组件化技术探索与项目实践
以上资料皆无偿分享,领取方式:点击我的腾讯文档即可免费获取