前言
demo地址在最下面。请各位爷慢慢看。感觉满意了记得点个赞。
先来张图活跃一下气氛:
最近一个月,学习了一下iOS平台下面的IJKplayer,中间也遇到过一些坑,不过亏了哔哩哔哩的一些大神还有我们部门安卓组的大神鼎力相助,很多问题可以一一克服。如果你们在IJKplayer的GitHub上面的Issues里面看到一些特别傻逼的问题,说不定其中就有我提问的。接触IJKplayer时间不长,还有很多没有没有做好的地方,希望大神们勿喷。
之前遇到过的问题
先说一下我之前遇到过的关于视频播放器的问题都有哪些:
(1):只有声音,没有界面,完全黑屏的那种。
(2):点击几个视频之后内存飙升,严重点的直接崩溃掉。
(3):切换到后台或者上划出现控制界面下划出现通知界面回来之后播放器异常(也可能界面不动了,也可能是时间不走了或者等等其他问题)。
(4):进度条不灵敏,点击或者拖动进度条出现进度跳动现象(就是最终的进度不是你想要的结果,一般都是向前拖动结果回避你想要的结果靠后,向后拖动结果会比你想要的结果靠前)。
(5):等等等等。。。。。。
当然这些知识目前我遇到过的很基本的问题,后面如果有机会继续深入的话我会继续把我的研究成果分享给大家。
框架介绍
用一张图介绍一下我做的视频播放器的层次结构:
如上图,视频播放器分成两大部分,一部分是视频播放器的属性信息部分,另外一部分是UI部分。下面是对于各个部分的介绍:
ZFTPlayerOption:
存放视频播放器的属性信息,主要包括:屏幕方向、是否是正在播放状态、当前的播放进度、当前的播放时间、视频的总时长、当前视频是否处于可见位置、当前视频所在界面是否处于活跃状态
其中屏幕的方向主要包括五种情况:home键在下面、home键在左边。Home键在右边、home在上面、未知状态。(目前对于home键在上面和未知状态的方向有特别处理,这个后面再屏幕旋转的时候有说明)。
playerBaseView
负责视频播放器以及相关UI控件的展示功能。其中主要包括四部分UI控件:视频播放器以及附着在其上面的展位图片的PlayerView、播放暂停按钮还有时间显示等一系列说明视频播放器状态的CoverView、显示加载视图的LoadingView、网络异常时候显示的网络提醒界面:netShowView。示意图如下:
这四个控件之间的层级关系从下往上依次是(左边的是处于下面的,右边的是处于上面的):
netShowView(显示网络提醒界面)
LoadingView(加载视图)
coverView(播放暂停按钮、全屏按钮、返回按钮等控件)
playerView(视频播放界面、视频占位图片)
这样可以保证在具体使用过程中这四个UI控件不会出现层级混乱的现象。
一:配置依赖环境
1.1:ijkplayer需要的系统系统依赖库如下:
1.2:IJKMediaFramework.framework传到百度网盘了,具体的下载地址是:链接: https://pan.baidu.com/s/1o8wPRzO 密码: pdwm 下载完成之后解压放在项目中就可以了。
1.3:把AFNetworking,Masonry(SDWebimage)集成到项目中。
二:AppleDelegate相关设置
2.1:设置两个全局变量,以便于后面整个项目使用,第一个是:决定是不是允许支持屏幕旋转的参数,第二个是表示当前网络状态的参数。
2.2:iPhone手机端好像不支持home键在上面的方向吧,所以需要针对home键在上面的情况进行设置一下。
2.3:添加监听网络状态变化的方法。
2.4:添加在后台播放音乐的方法。
2.5:添加退出第一响应者的通知方法和恢复第一响应者的通知方法,便于后面使用。
2.6:添加移除通知的方法防止出现未知错误
三:视频播放器所在控制器的相关设置
3.1:设置头文件的引用
3.2:添加相关的代理方法,其实也可以使用通知方法来实现,只是我觉得使用代理方法可以把单个的方法分散开,不至于代码太臃肿,让代码看起来更有条理。
3.3:创建视频播放器,网络提醒界面,加载界面,视频播放器属性,NSTimer。
3.4:在需要展示视频播放器的的控制器文件的ViewWillAppear方法中把playerOption(视频播放器属性)中的可见参数:isBeingAppearState设置成YES。与此同时,还需要判断当前是不是存在视频播放器,如果视频播放器已经存在,只需要把视频播放器的状态恢复一下就可以,如果这个时候没有视频播放器,说明是存在网络问题的,需要显示网络提醒界面,具体代码如下图所示:
3.5:在ViewWillDisAppear方法中吧playerOption中的还是否可见的参数设置成NO。与此同时,还需要判断当前是否存在视频播放器,如果存在视频播放器,需要存储一下当前视频播放器的状态,存储在playerOption中,记录完成状态之后,把视频播放器释放掉。如果不存在视频播放器,就不需要执行后面的操作。
3.6:viewDisLoad方法中创A级你并且初始化playerOption。此时需要获取当前屏幕的方向,同时需要把是否正在播放的状态值设置成 YES,把是否处于活跃状态的状态值设置成 YES、是否处于可见界面的属性设置成YES。之后就是UI相关的操作,添加通知事件的操作。
四:添加通知方法
viewDidload方法中已经有添加通知事件方法的步骤,下面是具体的介绍:主要需要添加的通知方法有下面四种。
(1):屏幕旋转的通知方法。
(2):失去第一响应者的通知方法。
(3):成为第一响应者的通知方法
(4):网络状态发生变化的通知方法
4.1:屏幕旋转的通知方法
如果在发生屏幕旋转的时候,接收到屏幕旋转通知的控制器不可见或者不处于第一响应者的状态,就不需要做任何处理。
如果当前接收到通知事件的控制器属于第一响应者并且处于可见界面。还需要判断当前的情况是否存在视频播放器,如果不存在视频播放器,就说明存在网络问题了,需要使用网络提醒界面来填充。
如果已经存在视频播放器,需要根据旋转过来的屏幕方向来改变视频播放器的frame,同时干煸视频播放器属性值中的方向值。
4.2:失去第一响应者之后的通知方法
在失去第一响应者之后需要把playerOption中的是否成为第一响应者的参数值设置成NO。如果当前有网络提醒界面,这个时候视频的暂停状态有可能不是视频播放器真实的暂停状态(也有可能是因为系统的处理逻辑决定的当前视频需要暂停,有点混乱了是吧。。。。。。。)。如果当前有视频播放器,就需要记录当前视频播放器的状态,执行完毕之后把当前视频播放器做暂停处理,不要存储当前视频播放器的暂停状态。
4.3:成为第一响应者之后的通知方法
当接收到成为第一响应者通知事件之后,需要把playerOption中的是否是第一响应者参数设置成YES。需要执行的逻辑和成为可见界面中的逻辑是一样的,因为那个方法里面会判断是否是第一响应者以及是否是处于可见界面。
4.4:网络状态发生变化的通知方法
在接收到网络状态变化的通知方法之后,会根据网络的状态执行不同的方法。主要由以下几种网络情况:
(1):网络切换成WIFI状态。
(2):网络切换成流量状态。
(3):网络切换成无网状态。
(4):网络变成未知状态。
网络切换成无线网络状态的时候,需要判断接收到网络变化通知事件所在的控制器是哦福处于可见状态或者处于第一响应者的活跃状态。如果这两个状态无法同时满足,不作任何操作。如果同时满足这两个条件。需要执行如下步骤:判断当前状态状态下是否存在视频播放器,如果当前没有视频播放器,说明覆盖在上面的是网络提醒框。这个时候需要把网络提醒框移除掉。之后如果有视频播放器的相关信息(playerOption)。需要创建视频播放器并且恢复之前的视频状态。如果没有视频相关信息,也需要创建视频播放器,只不过,这个时候视频是从头开始播放,创建完成之后还需要对playerOption进行初始化。并且赋值。在有视频播放器的时候,需要把视频播放器的状态恢复成之前的状态。
网络切换成流量状态的时候,如果这个时候没有视频播放器,需要把之前的网络提醒框系那是模式切换成流量状态。如果这个时候已经存在了视频播放器,需要把视频播放器的状态切换成暂停状态。这个暂停状态不记录,之后显示流量模式。
网络状态变成无网状态时,如果这个时候当前界面不处于可见界面,不用做任何处理(你都看不见,处理了有什么用)。在可见界面的情况下,如果没有视频播放器,需要显示网络提醒框(这个无网界面不是视频播放器的,是viewDidload里面创建的单独的那个)。把当前的网络状态记录下来。如果这个时候视频播放器是不存在的需要把视频播放器暂停(不需要记录暂停状态)。之后显示无网界面(视频播放器本身的那个无网界面)。
网络状态变成未知状态之后的处理逻辑目前还没添加,如果有处理方案的可以告诉我一下。
五:创建视频播放器方法分析
创建视频播放器的时候需要先判断当前是不是存在视频播放器所在的view,如果已经存在,需要先将这个view释放掉,因为后面还会有添加的步骤,不能重复添加。
之后需要判断当前屏幕的方向,根据不同的屏幕方向个视频播放器设置不同的frame。之后需要根据当前有没有视频信息来决定需不需要显示展位图片,如果之前有视频播放过,我们的设计是不需要显示占位图片。
再往后需要设置视频播放器的相关代理方法,再根据是否正在播放的参数来决定视频播放器创建完成之后视频时立即播放还是需要暂停。如果需要在创建完成之后就开始播放,就需要先设置prepareToplay,后面在执行play方法。
设置视频播放器中的网络提醒框按钮的点击回调方法。
返回按钮的点击处理逻辑是再点击返回按钮之后,如果当前的状态时全屏状态,需要变成小屏状态,如果当前的状态是小屏状态,需要执行小平的时候需要执行的逻辑(我目前的处理逻辑是直接退出当前界面)。
点击确定按钮的执行逻辑是:如果当前现实的是无网界面,点击确定之后需要判断一下当前的网络状态,如果当前没有网,点击了确定按钮也是不会执行任何操作的。如果有网,就需要恢复之前的状态。如果当前现实的是流量提醒界面,点击确定之后,会恢复到之前的视频状态。
六:播放器的全屏/返回按钮点击代理方法
当接收到用户的点击事件之后,需要判断当前的屏幕方向,如果是home键在下面的竖直状态,就会转换成home键在右边的横屏状态。如果之前的home键在右边的横屏状态,就会切换成home键在下面的竖屏状态。如果之前是home键在左边的横屏状态,就会切换成home键在下面的竖屏状态。如果之前是未知状态或者home键在上面的状态,就会切换成home键在下面的竖屏状态。之后通过动画把视频播放器的frame调整一下。
视频播放器返回按钮点击的时候,先判断一下当前的视频播放器是全屏状态还是小屏状态,如果当前的状态是全屏状态,需要将其变成小屏幕状态,如果本来就是小屏幕状态,需要执行释放播放器的操作,将播放器释放掉,之后返回上一级界面。
七:视频播放器加载状态发生变化的代理方法
视频播放器加载状态发生变化主要包括如下情况:
(1):缓冲完成状态
(2):缓冲数据到足够开会播放状态
(3):数据缓冲已经停止状态
(4):数据缓冲变成未知状态
7.1:缓冲完成状态
目前没有在这个方法中执行相关操作,后期会根据需求作相应的调整。
7.2:数据缓冲到足够开始播放状态
当数据缓冲到足够开始播放状态时,需要点判断当前播放器的状态:是否处于正在播放状态,是否处于可见界面,是否处于第一响应者状态。如果上面三个条件都满足,需要判断记录状态里面视频状态中的当前时间和视频播放器实际的当前时间误差是否在5秒之内。如果符合该条件,把视频播放器的状态变成播放状态,同时把视频播放器的占位图片隐藏掉。如果视频播放器中当前时间的属性状态和视频播放器的当前时间之间的误差超过5秒,需要把视频播放器的当前时间校对一下。如果视频播放器当前的状态没有处于正在播放状态,或者当前视频播放器处于可见界面,或者当前视频播放器步数与第一响应者。需要把视频播放器做暂停处理(不记录暂停状态)。
7.3:数据缓冲已经停止状态
当数据缓冲已经停止的时候,需要先记录一下当前视频播放器的播放还是暂停状态。之后做暂停操作(不记录当前视频播放器的暂停还是播放状态)。最后判断当前的网络状态,是否处于无网状态,如果当前的网络状态是无网状态,需要显示无网界面。
7.4:数据缓冲变成了未知状态
目前尚未针对数据缓冲变成位置状态做任何处理操作,后期会根据需求作相应的处理。
八:播放器播放状态发生变化代理方法
相关逻辑关系都封装在了视频播放器内部,调用方不需要做相应处理。
九:播放器发生变化的时候执行的代理方法
视频播放器发生的变化主要包括下面几种情况:
(1):视频播放完毕的原因是视频正常播放完毕。
(2):视频播放完毕的原因是播放器错误。
(3):视频播放完毕的原因是用户退出。
9.1:视频播放完毕的原因是视频正常播放完
视频正常播放完毕,目前的要求是让视频暂停,当前再次点击播放按钮的时候,视频从头开始播放。完成此效果需要如下操作:将视频暂停(记录状态的暂停)。把视频的当前时间设置成0.00。把视频的正在播放属性设置成NO。
9.2:视频播放完毕的原因是用户退出
目前还没有针对该情况做相应的操作,根据一些其他的视频播放器,大致会有如下操作:把目前视频播放器的进度记录下来。等到再次回到这个视频播放界面的时候把视频播放器的状态恢复过来。
9.3:视频播放完毕的原因是播放器错误
目前已经知道的会造成播放器错误的原因就是没网了。所以目前针对此情况做的操作都是围绕无网情况做处理。
目前的处理方式是:获取当前的屏幕方向,并且把当前的屏幕方向存储起来。把视频播放器的是否正在播放数形设置成YES。之后就是把当前的视频播放器属性状态存储起来。然后释放视频播放器。根据当前的网络状态分别作如下处理:
如果当前的网络状态是无网状态,需要显示无网界面(全局的无网界面)。
如果当前的网络状态是流量模式,需要显示流量提醒界面(全局的流量提醒界面)。
如果当前的网络状态是WIFI状态,需要再判断一下之前是否有视频播放过,如果由之前视频的状态信息,需要创建视频播放器,并且需要恢复成之前的状态。如果之前没有视频播放器相关信息,不作任何操作。
十:恢复视频播放器方法介绍
如果视频播放器属性中正在播放状态是正在播放,需要执行play方法。
判断当前屏幕的方向,根据屏幕方向设置视频播放器的frame。
判断当前视频播放器的时间和属性中记录的时间是否一致,如果不一致,需要校对一下。
十一:成为第一响应者和成为可见界面执行的方法介绍
首先需要判断当前的状态是否是活跃状态,当前界面是否可以被看到,当前的网络状态是否是WIFI状态。如果不能同时满足这两个条件,不作任何处理。当上述三个条件同时满足之后,再进行如下操作:
判断此时是否与视频播放器,如果这个时候没有视频播放器界面,先把全局的网络提醒界面移除掉。再判断是否由之前的视频信息,如果有之前的视频信息,需要创建视频播放器,并且把视频恢复成之前的状态。如果没有之前的视频信息,同样需要创建视频播放器。屏幕方向参照当前的屏幕方向,当前时间是0.00。正在播放属性设置成YES。如果之前就有视频播放器,就不需要创建视频播放器,需要隐藏掉网络提醒界面,最后把视频状态恢复成之前的状态。
最后
是不是看的眼花缭乱啦,我表达也不是很清楚,我把我的上传到Github上面了,欢迎大家拍砖:https://github.com/zhangfangtaozft/ZFTPlayer.git
最后如果有什么问题可以联系我的QQ:894918941。