由于最近项目需求,需要实现大音频播放,类似听书类软件,于是网上搜集了很多这块的资料,但发现真正全面的少之又少,由于音频播放这块需求复杂,很难有直接能拿来用的,在历经波折与各种坎坷后除了边缓边播(这块暂时仍没有太好的解决方案)终于完善了大部分需求,在这里记录与分享一下实现各种功能以及遇到的各种问题。
首先要看你的项目需要都实现什么样的功能,本地音频播放不做讨论,此处只针对AVPlayer实现网络播放的问题,AVPlayer是oc的一个支持音视频播放的系统播放器,很多第三方播放器都是基于它实现的,其实,熟悉了这个框架后,我们完全可以自己去写一个功能齐全音频播放器,像什么豆瓣FM啊,AudioStreamer啊,虽然都有所耳闻,功能实现等也都不错,但是太复杂,初学者很难一下子就看得懂,更别说拿来使用,那么如何通过简单学习了解它来满足自己使用的需求呢,废话不说了,本篇文章将手把手教你一步一步实现一个完整的音频播放器,下面上干货。
1. 功能需求
2. 架构
3. 代码实现
1. 首先确定好需要实现什么功能,音频播放中设计的功能非常的多,包括:
- 上下首音频切换
- 播放暂停
- 拖动快进
- 缓冲进度
- 锁屏播放
- 后台播放
- 循环播放
- 锁屏状态下的操作
- 自动播放
以上功能基本满足了音频播放类的所有需求,除了歌曲类播放是否显示歌词外,(项目中没用,所以暂没做研究),具体可参考网上一些其他博客,均实现有,在这里就不做多说。
2. 确定好功能,开始架构怎么实现,由于音频播放一般需要后台播放和锁屏播放,所以这涉及到很多地方,首先播放器这个类要单独出来,创建一个全局都能使用的,方便各处使用调用。当然包括音频播放页,这个页面是不能被释放的,所以就不能使用正常的跳转方式。
- 播放器管理类全局
- 注意页面跳转问题
3. 确定好以上东西,就可以写代码了。
- 首先,创建一个全局单例类,用来管理播放器相关操作,如创建播放器,暂停开始,上一首下一首,锁屏,后台等等所有的相关操作都在这里面完成。
在这里边把播放页的上下曲,开始暂停,背景图片和中心旋转图片和音频标题等声明一下传过来,在这里统一进行切换上下曲的时候进行更新,先不用管这些东西,这些主要是根据页面需求来,不过基本的应该都会有,标题,封面,开始暂停,上下曲。
我们先搁置这些东西暂且不谈,来看看.m文件
- .m文件开始正式实现
先实现各种监听
DCD93602-B1B9-44AC-928A-966F22610870.png
然后是播放中断以及后台播放注册等,注释非常详细,这些都是固定的
06CAF487-442B-4A2B-9F15-A83D09F3C156.png在音频播放完成的监听里边要注意一下,要暂停播放按钮的状态,同时在这里执行一些操作,比如循环播放,自动下一首
47CD323E-0017-49F6-BB7F-E85D456912D8.png然后是锁屏播放,这里相当于创建一个系统用来管理锁屏的中心,把音频名称,图片当前播放时长和总时长等传过去,就能实时更新在锁屏了
31BFE5B4-AC2B-4FB6-A970-02A8BB40E1AD.png由于这些都是固定的个体方法,所以我先列出来,下面才开始正式的有关联的实现播放器的创建的播放。
这个方法就是每次播放新音频的时候需要调用的,在这里每次先初始化播放按钮为暂停状态,然后更新最新的音频标题和图片等信息,这里的currentSong是一个model,就是一个音频的信息,每次从一个列表点击时候就把这个音频的model传过来,保证这个是最新的就行,然后初始化一系列东西,在这里拿到音频链接,然后调用isurl方法进行链接判断,最后那里实现在每次点击播放新的音频时候就记录到本地,实现下次进来是最新的那一首。
2E325C15-1F20-4D3D-9824-3CAC697F6FF1.png进行链接有效性判断
A8BE46B2-D4FE-400A-BED7-A985FF20B69C.png如果连接没问题,那么就开始调用playering方法,这个方法就开始创建播放器了,avplayer有一个资源管理类,AVURLAsset,由于在ios8上会有问题,所以暂时去掉了,这个东西其实就是用来判断资源加载好了没,加载好了才开始执行一些操作,其实这个东西在大音频上反而不需要,谁会等你加载好才开始播放,所以我把它去掉了,只留了一个AVPlayerItem,这个又是什么东东呢,说白了这个就相当于一个资源管理工具,里边包含了音频的各种信息,这个是必须要的。
每次创建之前先移除,然后创建,设置四个监听,然后清空实时监听者,这个就是用来音频播放时候实时进度,时长,进度条的变化都在这里边实现。
然后这里要判断一下版本,是否是ios8,进行特殊处理,必须重新创建一下这个播放器,这个ios8兼容问题困扰了我好长时间,最后才找到原因所在,ios8上avplayer的兼容性很差,后边的升级做了优化,但是为了兼容8没办法。
然后调用 playTimeOBerseverManger方法,这里就是实现实时更新播放时长和进度条的方法,由于我这里有电台直播,所以都进行了两种判断,请忽略。
A40CED40-21BC-4608-BC7C-BAED112B302E.png然后就是实时监测方法,给进度条和实时播放时长实时赋值,还有只要可以播放就改变播放暂停按钮的状态。
DD45BEC1-5F9F-4538-9161-2519CDFE9F0C.png下面就是实现上边音频资源管理的四个监听方法,来执行不同情况下的处理,
- status 准备开始播放
- loadedTimeRanges 获取缓冲进度
- playbackBufferEmpty 缓冲进度不足暂停
- playbackLikelyToKeepUp 缓冲进度达到可以播放了
以上是status的状态,主要是这个状态的处理,在这里,获取到item,判断状态,可以从他当中取到当前播放时长和总时长等信息,然后显示,在这里,要调用锁屏显示,就是上边实现的锁屏方法,然后开始播放,调用播放的方法,下面会粘出来,最后更新一些列按钮的状态,另外一个fiald是失败的方法,在这里进行失败的处理。
然后就是另外三种状态,这三种状态没有太多的代码,主要是一个实现缓冲条。
C0BEE2AD-91C3-4E47-B7C2-14D76764C8FA.png这个是计算缓冲进度的方法
F47AC17B-441D-4D16-9365-C8CEF85277C7.png然后就是一系列按钮的方法了,上下首,开始暂停
D3C77DEC-2002-4A18-A696-B6B5AE6A759A.pngplay是播放,pasue是暂停,这里上下曲我们是调用接口,所以不一样,如果你们没有借口提供的话就是传来整个音频列表数组,里边是一个个model,然后声明一个index,索引,从里边取,来代替之前我声明的那个cuttsong那个最新音频model,然后再上下曲里边进行index++和--来取上下首的音频model.这块如果有不懂的再问我,这里就不再贴了,回头我会整理出来一个demo。
最后就是别忘了移除通知。
9B5AC4C2-1F9E-42D7-A48B-66BEE02216E1.png至此,这个音频播放类就完成了,你可能会说,我曹,啥啊,都没看懂,别急,这个就相当于一个工具,工具建好了,用就好用了,剩余的只剩搭界面,然后把一些按钮控件啥的传过来,调用方法控制而已,就很简单了。
下面,开始创建一个Viewcontroller,也就是播放页,搭好界面。根据具体情况,如果下边没有评论列表一类的,就直接在创建后赋值给播放类里声明的那些控件,用于实时控制。有的就在cell方法里赋,整合力就要说一下appdelegate的代理了,在APPdelegate类要县创建好这个工具类
661366E3-467A-4182-82E7-E913B94DCDFD.png实现代理
63DF19EB-BCAF-4BD3-9AD8-773FF0E9586D.png在入口类didFinishLaunchingWithOptions方法里实现这些代码
88A2FBD5-0B12-4F52-8B6C-C47A7FFCEBE4.png然后实现锁屏相关的操作
EB05D6BF-60D3-45FB-A0C0-A91CE303C373.pngAPPdelegate类至此就没有其他东西了,这样,这个播放类就可以全局使用了,
在其他类声明一下,viewDIdload实现下代理,就可以使用self.APPdelegate.player来使用这个播放类的。
其实这一切这些都做完以后,就算你能实现播放了,快进,上下切换等,就算满足了基本功能了,当然还有最恶心的也是音频播放最烦人的各种状态处理的,比如从列表页点击去播放,返回再进去,不能重复播放,还有一般导航会有一个播放按钮在外边控制播放暂停,都要各种处理,我们这个有3个播放暂停按钮都要同步。看需求自己实现即可。
这篇文章也写的比较大概,因为暂时没有整理出一个demo,所以可能有的还是一知半解,如果有什么问题,欢迎私聊我,互相讨论。
网友评论