天天看点

「商业移动端」开屏重构

作者:闪念基因

项目背景

1、开屏广告,是商业客户端维护的最重要模块,有,,,,,等特点。

2、商业早期开屏广告功能单一,实现随意,多处违背基本设计原则,更没有系统的进行架构设计,80%的代码堆砌在少数几个类中。

3、随着,,,人力无法满足业务deadline时的,,。目前开屏模块已接近无法维护,烟囱化严重,研发测试成本翻倍,质量濒临失控,性能肉眼可见的日益劣化。

重构目标

核心意图:管理复杂度,建设为独立商业能力,角色由面向页面的,转向面向接口的。

重构收益:

1、提供开屏服务,独立组件、可独立运行。

2、可插拔式UI插件库设计。

3、调试速度大幅提升,从运行一次应用10分钟左右,提升至30秒左右,提升95%。

4、无用、过期代码下线,包体积缩小100k左右。

5、去烟囱化,多套开屏逻辑统一,独立组件高速调试,开屏开发周期缩短30%以上,故障率减少50%以上,QA测试周期缩减50%以上。

6、优化开屏耗时200ms,开屏展示率提升3%。

7、独立商业能力之一,可为任何业务,任何知乎app,直接提供插屏广告能力。

开屏模块现状

现有问题&代码性能评估

重构前梳理:Android 开屏广告梳理

对梳理过程中,代码现存具体问题进行归类,总结,从而进一步评估代码性能现状。

结论:现有开屏架构不能满足商业日渐复杂的开屏场景,与日俱增的开屏收入。重构时需重点关注可读性、可维护性、可复用性。

「商业移动端」开屏重构

可读性

「商业移动端」开屏重构

可拓展性

「商业移动端」开屏重构

可维护性

「商业移动端」开屏重构

可复用性

「商业移动端」开屏重构

代码性能

设计原则匹配

结合代码性能现状,评估设计原则匹配度,找出重构侧重点及方向。

结论:重构设计中,重点关注SRP、LKP、OCP、DIP四个指导性原则上的优化。

「商业移动端」开屏重构

代码结构

核心类 LaunchAdFragmentDelegation 现状,70%功能堆叠在一个类中,20%功能与该类有关

「商业移动端」开屏重构

现有架构

页面级开发,即每个页面有自己的一套开屏逻辑,一个需求点,多倍工作量,且难以保持一致性。

「商业移动端」开屏重构

纵向与横向(架构与切面)

纵向:

如上面简易架构图,目前纵向纵深不够,整体是一个拍平的状态。基本的UI层、数据层、逻辑层、核心层结构都不具备。UI层和逻辑层在一处,且或多或少包含数据层及核心层逻辑。

横向:

目前关键节点间途径若干方法或回调,其间散落了大量各方面逻辑,不成体系,难以理解,且任何一处出错都会打断开屏逻辑,没统一管理。

「商业移动端」开屏重构

架构设计

理念

1、核心思想为将开屏广告子系统「SDK化」,抽象为一种商业能力,面向API开发、维护。

2、SDK内部只包含通用功能,高稳定性,高可拓展性,不关注具体业务场景。

3、纵向架构层级上讲究「动静分级」。

4、横向切面分割上讲究「统一精准」。

5、于使用方而言,内部实现黑盒,高度可配置,可插拔,可自定义。

商业整体架构图

「商业移动端」开屏重构

开屏模块架构图

「商业移动端」开屏重构

SDK 层:

抽象出和业务完全无关的 SDK 层,面向接口设计,可为知乎App,来鸭App,知乎日报App或外公司App提供开屏广告接入支持。

基建层:

基础能力,日常开发时无需修改。

框架层:

将通用业务、共性代码等低频率修改代码独立出来,形成框架层,这层代码是可由专人维护,其他业务线同学无法修改。

拓展层(Api):

处于组件api中间件之中,对外提供两套接口,一套为命令式,控制开屏广告;一套为响应式,接收开屏广告各类回调。

接口设计:

ZHSplashAd:

    • 构造方法:ZHSplashAd(Activity activity, String posId, ZHSplashAdListener adListener)
    • fetchAd() 拉取广告,配合showAd使用,实现和fetchAndShowIn相同的功能。
    • showAd(ViewGroup container) 展示广告,配合fetchAdOnly使用
    • addViewPlugin(SplashPlugin plugin),添加自定义插件
    • removeViewPlugin(),删除任意开屏插件
    • isLaunchAdShow() 开屏广告展示条件是否满足

ZHSplashAdListener:

    • onNoAD(AdError error) 广告加载失败,error 对象包含了错误码和错误信息,错误码的详细内容可以参考文档第5章
    • onADDismissed() 广告关闭时调用,可能是用户关闭或者展示时间到。此时一般需要跳过开屏的 Activity,进入应用内容页面
    • onTimeOut()熔断时间内,开屏广告未就绪
    • onADClicked() 广告被点击时调用,不代表满足计费条件(如点击时网络异常)
    • onADExposure() 广告曝光时调用
    • onADTick(long millis) 倒计时回调,返回广告还将被展示的剩余时间,单位是 ms
    • onADLoaded(long expireTimestamp) 广告加载成功的回调,在此方法中调用SplashAD.showAd(ViewGroup container) 方法,即可展示广告。

业务层:

SDK层的使用者。如超级首映,冷启动开屏,热启动开屏,端内开屏等,知乎创新产品App等。

组件化设计

重构前开屏代码并不独立,处于ad组件中,,,其他业务线组件直接调用,,且。

重构前组件图:

「商业移动端」开屏重构

重构后新增launch组件,并伴生luanch-api中间件,面向接口编程,与其他业务线解耦,可独立编译(开发现状:跑一次主工程10分钟。可独立编译后,开屏需求跑一次只需要1分钟,大幅提升人效)

重构后组件图:

「商业移动端」开屏重构

具体实现

响应式编程

重构前,由于开屏场景,多线程,阻塞,等待,数据转化场景复杂且丰富,皆采用回调的方式实现,造成了现在的“回调地狱”,代码可读性,可维护性很差。

重构后,采用rxjava,响应式编程方案。基于观察者的实现原理,丰富的操作符支持,使得开屏逻辑主干流程在100行代码以内实现,一目了然。

「商业移动端」开屏重构

主流程时序图

「商业移动端」开屏重构

开屏展示条件

重构前:

跳过方式:实现接口的方式跳过开屏

「商业移动端」开屏重构

重构后:

跳过方式:采用apt注解处理器的方式,利用编译期来标记不展示开屏的Activity,实现跳过开屏

「商业移动端」开屏重构

数据流、数据结构设计

重构前:

多套数据结构来回转换,重复赋值,容易造成内存泄漏,可读性差,浪费性能。

「商业移动端」开屏重构

重构后:

单数据结构Advert一以贯之

图层插件设计

开屏插件库:

开屏广告所需UI元素,皆以自定义view形式构建,并加入插件库,随时插拔。

「商业移动端」开屏重构

默认渲染流程图:

「商业移动端」开屏重构

默认渲染的插件:

「商业移动端」开屏重构

自定义插件默认处于最上层,可设置事件是否透传。

发射井设计

下发的多个开屏广告同时并发执行,抽象为发射井模型,设计上关注匹配、优先级、发射、返回队列、时限等。

流程图

「商业移动端」开屏重构

等待队列设计

「商业移动端」开屏重构

类图

「商业移动端」开屏重构

作者:知乎商业移动端团队-于铠瑞

出处:https://zhuanlan.zhihu.com/p/593000564

继续阅读