写点什么

爱奇艺知识移动端组件化探索和实践

  • 2020-11-30
  • 本文字数:4637 字

    阅读完需:约 15 分钟

爱奇艺知识移动端组件化探索和实践

前言


组件化对于任何一个业务场景复杂的 APP 以及经过多次迭代之后的产品来说都是必经之路,组件化是指解耦复杂系统时将多个功能模块拆分、重组的过程。组件化要做的不仅仅是表面上看到的模块拆分解耦,其背后还有很多工作来支撑组件化的进行,例如结合业务特性的模块拆分策略、模块间的交互方式和构建系统等等。


本文主要讲述爱奇艺知识 APP 如何结合自身的业务特点,探索和实践了一套高效的移动端组件化方案。


01 背景与目标


1.1 背景


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



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


1.2 目标


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


  • 解决多端代码维护问题


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


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


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


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


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


  • 提升集成和提测效率


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


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



02 整体技术架构


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



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


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


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


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


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


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


03 核心技术实现


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


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 正式包中运行时可减少反射带来的消耗。


整个优化流程如下:



04 构建系统


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


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


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



iOS 端选择 Jenkins 作为构建系统,在组件化初始阶段,我们组件的构建是通过先构建最基础的组件,然后再构建上层组件来完成的整体构建,随着组件库数量增多,依赖关系变复杂之后手动逐一触发构建成为了构建过程的痛点,于是开始进行构建优化,引入了 Jenkins 的 ParameterizedTrigger 插件并配合 shell 脚本使用,使得我们支持组件的单个构建的同时,在主项目构建时支持触发多个组件,组件单独构建时也支持配置依赖构建的项目,实现了一次触发完成全部组件的构建。



组件库构建时会对当前迭代分支的代码进行更新检查,如果存在更新则会构建组件库,不存在更新则直接跳过此次构建。随着端的增加构建系统支持了多端构建,iPhone 插件和 iPad 插件为不同的插件 Job,通过脚本实现端的区分完成构建。建系统还实现了版本自增和定时构建,每一次构建完成后都会更新 podspec 文件中的版本号,在下一次构建时如果未手动指定构建版本便会获取之前的版本进行加一实现版本自增。构建系统对接了企业内部的即时通讯工具,在构建完成后发送通知给已经订阅的用户。下图描述了组件构建流程:



在 Android 端,同样每一个业务组件都是一个完整的个体,可以当作独立的 App 来运行,需要满足单独运行及测试的要求,这样可以提升编译速度和开发效率。


目前业界常规做法是每一个组件就是一个工程,由 build.properties 中一个常量控制区分不同场景,且在 build.gradle 中 sourceSets 设置单独调试组件时的配置,区别于发布组件 aar 时候的独立运行时的配置;


但是这种方案对于爱奇艺知识客户端来说并不完全适用,因为我们组件化最主要的一个目的是要达到多端组件复用,这样也会存在需要进行多端适配情况,每一个端的基础配置信息、基础 UI 样式等都有所不同,不可能在每一个新的组件工程中都配置一遍。所以,直接使用原本混沌工程的壳工程作为组件调试的 Project,将 runalone 文件夹设置在各自壳工程中,在根目录 build.properties 中通过常量 isModuleType 控制编译模式,动态加载测试所需组件依赖,这样就可以在各个环境中单独测试组件了。



此时的组件单独调试模式其实等价于理想状态下的组件化壳工程模式:只有少量配置相关代码、无其他组件无关页面逻辑、动态按需加载组件。


在壳工程根目录 gradle.properties 中包含各种常量,包括端控制、组件库版本号、编译环境控制、运行时依赖控制和运行模式控制参数等。



isDependenceMaven 用来控制依赖方式是源码还是远程 maven,开发期间 debug 可以使用源码方式方便调试,正式环境使用远程依赖方式节省编译时间,方便复用。


maven_version 用来统一控制组件版本号,在每一个版本升级时候对应的升级组件库版本和依赖的组件库版本,通过自定义的 maven_publish 上传脚本批量编译上传并更新。


对于 Android sdk 版本和第三方库版本,我们统一抽离到外层的一个 dependencies.gradle 中统一控制,这样能方便且直观管理版本号。


总结与展望


爱奇艺知识移动端已经基本实现了组件化的全部目标,组件间业务边界已经变得非常清晰,做到了一个组件升级多端受益,大幅提高了开发和测试效率。另外,组件增减灵活,使得新增一个业务承载端的成本很低,只需要组合已有组件并对组件做针对这个新增端的修改即可,使爱奇艺知识移动端做到了较少的人力能够支撑更多端的能力。组件化过程中遇到的一些问题已经全部解决,目前组件化从底层的基础组件到上层的业务组件都已经全部上线,组件化构建系统也已经投入生产环境。


当然组件化不是一蹴而就的,而是一个持续的过程,未来还需要不断优化和完善,让组件化在知识业务发展中起到更大的作用。


本文转载自公众号(ID:)。


原文链接


爱奇艺知识移动端组件化探索和实践


2020-11-30 14:002715

评论

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

API主导的商业模式是否将在AI时代蓬勃发展?

幂简集成

AI API

如何汇报自动化测试的成果

老张

研发效能 自动化测试

AWS RDS & ElasticCache 监控可观测最佳实践

观测云

AWS

苹果M1/M2电脑安装Lightroom Classic 2022(LRC2022) 后打开闪退怎么办?

Rose

记一次被黑的经验教训

zhumingwu

JetBrains Rider 2024永久注册码 mac/win 跨平台.NET IDE集成开发

Rose

ClickHouse沙龙来了,NineData将分享数据管理与同步的关键技术!

NineData

Clickhouse Meetup 杭州 NineData 迁移同步

vm虚拟机 mac版下载 vm虚拟机 含VMware Fusion Pro 12永久许可密钥

Rose

autocad2023破解版下载 含cad2023中文汉化包 Mac&Windows系统

Rose

苹果mac好用的SSh终端工具:SecureCRT for mac附最新许可文件

Rose

什么是蜜罐,在当前网络安全形势下,蜜罐能提供哪些帮助

德迅云安全杨德俊

如何申请 https证书

zhumingwu

教你如何搞定springboot集成kafka

华为云开发者联盟

kafka springboot 华为云 华为云开发者联盟 企业号2024年5月PK榜

NineData亮相GOPS大会:揭秘新时代企业级数据库DevOps最佳实践

NineData

数据库 DevOps 工具 NineData SQL IDE

报名开启|智能化可观测:可观测开源开发者Meetup

TRaaS

活动报名

Tuxera NTFS 2021破解版下载 Mac版NTFS工具推荐

Rose

抖音商品详情:短视频电商的新风向

Noah

立即注册 | 线上讲座:基于 NGINX 为现代应用构筑三大安全防线

NGINX开源社区

nginx DevOps DOS攻击 OWASP十大漏洞 NGINX PLUS

腾讯、阿里、B站最新面经汇总,有的妥妥的凉经

王中阳Go

golang 面试题 大厂面经 Go进阶

MES给制造业带来看得见的效益

万界星空科技

数字化 工业互联网 制造业 mes 万界星空科技

油猴浏览器辅助插件 Tampermonkey for Mac安装教程

Rose

Desktop Goose for Mac(抖音桌面宠物鹅),让你的苹果电脑桌面更加生动有趣!

Rose

MacDroid for mac:轻松实现mac与安卓设备数据互通

Rose

适用于Windows、Mac平台:Sublime Text代码编辑器 含注册码

Rose

漆包线行业你了解多少?专业漆包线行业MES生产管理系统

万界星空科技

制造业 mes 万界星空科技 漆包线mes 漆包线

NineData云原生智能数据管理平台新功能发布|2024年4月版

NineData

sql 数据迁移 数据备份 NineData 对比工具

得物质量管理体系的建设与应用

得物技术

测试 质量 企业号 2024年5月 PK 榜

【iOS逆向与安全】iOS远程大师:通过H5后台远程查看和协助iPhone设备

小陈

移动端 逆向 iOS逆向 ios安全 逆向技术

爱奇艺知识移动端组件化探索和实践_移动_爱奇艺技术产品团队_InfoQ精选文章