前言:
也许大家也会遇到播放器过于臃肿,播放器控制逻辑复杂度高,业务耦合度高,页面逻辑分散(跨页面动画,续播逻辑)等等这类问题,而这些问题其实归根结底就是播放器本身没有“干(播放器本身)湿(播放器控制)”分离。如果产品中的播放器形态多样化,那么在这个播放器中新增某些需求起来也是极其困难,往往牵一发而动全身。所以需要对播放器进行业务分离,把播放器核心业务以及UI控制层进行抽象化,从而减少相互之间的依赖关系。
播放器重构之路
背景
项目之前的业务重心一直在社区方面,在视频日记以及长视频做了很多尝试,做了很多差异化的处理,起初的播放器是由一个基础类,慢慢演变到多个继承类,而后在产品的优化需求中一直打补丁,加入了很多小功能,比如说:手势快进,列表滑动播放优化,续播,网络条件下的自动播放等;项目在起初的时候没有考虑整体的播放器架构,导致后期播放器的逻辑严重依赖页面,以至于后期的业务变更难以继续,出现的问题也难以解决。(新人看了不敢乱动,旧人看了一眼,祖传“屎山”,千万别动)
探索
在经过足够耐心的分析之后,在项目中发现了多个层面存在问题:
- 播放器的交互部分与业务上的UI耦合在一起,并且多个业务层模块依赖这个基础的播放器控制层,往往某一处修改,影响都是成倍的。
- 列表播放时,太多重复性的侵入代码
- 续播逻辑过于复杂,因为起初的续播方案建立在打补丁的基础上,所以方案不合理;
- 底层播放器的架构存在问题,没有和业务完全分离;
既然发现了问题,那么如何去设计播放器模块的架构呢?或者说什么样的架构满足自身的业务呢?
那么根据自身的业务需求从而制定了一些必须要满足的条件:
- 播放器底层是否需要满足不容内核的播放器
avplayer、ijkplayer
或者更多;(需要有统一的播放器适配协议) - 播放器控制层是否需要实现差异化的处理;(需要有统一的控制层协议)
- 播放器列表自动播放的实现方案与业务分离;(需要通过协议的形式或者tableView的分类实现解耦)
- 播放器手势统一管理;(手势合集)
实践
既然知道了要如何满足哪些条件,那就放手去做吧。
遵循设计模式的六大原则,我们尽可能将每个类的职责单一化,把底层依赖的模块抽象化,从而达到上层业务最大的灵活性。
VideoPlayerCenter
VideoPlayerCenter
类是中间控制层,它的职责是用来整合所有的模块,将播放器中的事件(播放器本身的事件、或者主动触发控制层的事件、或者网络层面监测的事件等)分发给对应的功能模块,你可以把它当做一个调度。
以下是VideoPlayerCenter
的结构:
VideoPlayerCenter
会对外开放各个模块的方法来处理,每个新增的模块可以通过添加分类的方式去添加自身的功能实现。
在这个类中,会把各个功能模块组装,然后根据每个功能模块的回调触发到对应的功能模块,比方说:
VideoPlayerPlaybackProtocol
的实现类中有播放器的播放回调,如果触发该回调之后,会在VideoPlayerCenter
中转发事件到VideoPlayerControlProtocol
的实现类controlView
中,用于处理播放回调后的控制层UI变更;
VideoPlayerGestureManager
类中有播放器的手势回调,如果触发该回调之后,会在VideoPlayerCenter
中转发事件到VideoPlayerControlProtocol
的实现类controlView
中,用于处理手势操作后控制层UI变更;
同样VideoPlayerNetworkManager
类中也是相同;
VideoPlayerPlaybackProtocol
VideoPlayerPlaybackProtocol
类是播放器的控制层,它的职责是用来抽象播放器,减少外界对播放器的依赖;
这个类会定义播放器的基本属性,方法,回调,用于统一播放器的接口,在接入不同的播放器时,只需要实现对应的这套播放器协议即可使用。
VideoPlayerControlProtocol
VideoPlayerControlProtocol
类是播放器的UI控制层,它的职责是用来抽象化UI层的事件,减少外界对播放器的依赖;
VideoPlayerCenter
中的controlView就是这个VideoPlayerControlProtocol
协议的实现类,同时controlView自定义自己的布局,在页面切换的时候可以直接通过切换controlView就可以完成播放器的过度。
这个类会定义控制层所有的事件,所有可能会影响到控制层的事件都会通过VideoPlayerCenter
转发到VideoPlayerControlProtocol
的实现类中。
VideoPlayerGestureManager
VideoPlayerGestureManager
类是播放器控制层的手势管理,它的职责是管理控制层的手势;
手势种类有很多中,可以单击,双击,长按,拖拽等,响应哪一种手势取决于配置;
VideoPlayerNetworkManager
VideoPlayerGestureManager
类是播放器的网络监测,它的职责是监测网络波动;
每个类的职责划分是单一的,不会去干涉其他类的逻辑。通过对控制层的抽象化,解决了控制层差异化的配置,解决了列表播放切换至详情页播放的的无缝续播,解决了上层业务对播放器的过度依赖,极大程度的保证了业务层的干净整洁。
后续
因为播放器的业务侧做了很多减法,目前的这些功能类已经满足需求。列表自动播放的逻辑是在tableview的分类中(可以复用原来的逻辑),并没有放在VideoPlayerCenter
中管理,有违最初设计的初心,如果后面要把播放器模块化,可能会有些影响,后面在考虑下是否要把列表播放也放在VideoPlayerCenter
中。后续会继续完善切换横竖屏,以及控制层的手势快进、快退、长按三倍速等相关的功能。