按公司需求需要对音频文件进行后台播放,借此机会对音频播放做了个总结.主要针对 AVPlayer 进行详细说明.

iOS 各播放器比较

名称 使用环境 优点 确点
System Sound Services AVFoundation C语言的底层写法,节省内存 支持的格式有限,音量无法通过音量键控制,而且播放方式单一。
AVAudioPlayer AVFoundation 抒写效率更高,基本上支持所有的音频格式,对播放的控制,如循环播放,声音大小,暂停等比较方便。 对内存的消耗会多些。不支持流式,即无法播放在线音乐。
AVPlayer AVFoundation 可以播放音视频,可播放在线音乐,使用灵活
MPMoviePlayerController MediaPlayer 简单易用 不可定制
AVPlayerViewController AVKit 简单易用 不可定制
IJKPlayer IJKMediaFramework 定制度高,支持流媒体播放 使用稍复杂

AVPlayer 使用

简介

AVPlayer 是iOS上常用的视频播放器组件,支持常见的音视频格式,支持流播放,可以播放在线音乐.
支持视频格式: WMV,AVI,MKV,RMVB,RM,XVID,MP4,3GP,MPG等。
支持音频格式:MP3,WMA,RM,ACC,OGG,APE,FLAC,FLV等。

相关类

  • AVPlayer:播放器,控制播放器的播放,暂停,播放速度.
  • AVURLAsset : AVAsset 的一个子类,使用 URL 进行实例化,实例化对象包换 URL 对应视频资源的所有信息.
  • AVPlayerItem:管理资源对象,提供播放数据源.
  • AVPlayerLayer:负责显示视频,如果没有添加该类,只有声音没有画面.

简单使用

使用 url 创建 AVPlayer

let player = AVPlayer(url: URL(string: "http://www.xxxx.mp3"))

使用 AVPlayerItem 创建 AVPlayer

if let url = URL(string: "http://www.***.mp3") {let asset = AVAsset(url: url)guard asset.isPlayable else{// 检测文件是否可播放return}let playItem = AVPlayerItem(asset: asset)let player = AVPlayer(playerItem: playItem)player.play()
}

AVPlayer 控制播放

player.play() // 播放
player.pause() //暂停
player.rate = 1.0 // 播放速度

通过通知监听播放状态变化

//播放完成
AVPlayerItemDidPlayToEndTimeNotification
//播放失败
AVPlayerItemFailedToPlayToEndTimeNotification
//异常中断
AVPlayerItemPlaybackStalledNotification// eg: 播放结束通知
NotificationCenter.default.addObserver(self, selector: #selector(finish(_:)), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: nil)

监听播放进度

// 添加周期时间观察者 一秒执行一次 block
let timeObserver = player.addPeriodicTimeObserver(forInterval: CMTime(seconds: 1, preferredTimescale: 1), queue: DispatchQueue.main, using: { [weak self] (cmTime) inif let totalTime = self?.currentPlayItem?.duration {self?.delegate?.player(self!, currentTime: cmTime.seconds, totalTime: totalTime.seconds)}
})
// 不要忘记移除
player.removeTimeObserver(observer)

AVPlayerItem 创建

// 使用 AVAsset 创建
if let url = URL(string: "http://www.***.mp3") {let asset = AVAsset(url: url)guard asset.isPlayable else{// 检测文件是否可播放return}let playItem = AVPlayerItem(asset: asset)
}// 使用 URL 创建
if let url = URL(string: "http://www.***.mp3") {let playItem = AVPlayerItem(url: url)
}

监听 AVPlayerItem 状态和缓存进度

// 监听 playerItem 状态变化
playItem.addObserver(self, forKeyPath: "status", options: .new, context: nil)
// 监听缓存时间
playItem.addObserver(self, forKeyPath: "loadedTimeRanges", options: .new, context: nil)// 移除监听
currentPlayItem?.removeObserver(self, forKeyPath: "status")
currentPlayItem?.removeObserver(self, forKeyPath: "loadedTimeRanges")
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {if object is AVPlayerItem {if keyPath == "status" {if let playerItem = object as? AVPlayerItem {switch playerItem.status {case .readyToPlay:// 准备播放case .failed:// 加载失败                    default:// 未知状态}}}if keyPath == "loadedTimeRanges" {if let playerItem = object as? AVPlayerItem {if let timeRange = playerItem.loadedTimeRanges.first as? CMTimeRange {let cache = timeRange.start.seconds + timeRange.duration.seconds // 缓存总时长}}}}

音频后台播放

开启所需后台模式

选中Targets–>Capabilities–>BackgroundModes–>ON,
并勾选Audio and AirPlay选项,如下图:

或者 plist 文件添加如下字段:

利用 AVAudioSession 申请后台播放权限

let session = AVAudioSession.sharedInstance()
do {try session.setActive(true)try session.setCategory(AVAudioSessionCategoryPlayback)
} catch {print(error)
}

在播放控制界面接受远程控制(Remote Control)

开启远程控制

// 声明接收Remote Control事件
UIApplication.shared.beginReceivingRemoteControlEvents()

设置 Remote Control 响应

// 响应 Remote Control事件
MPRemoteCommandCenter.shared().playCommand.addTarget(self, action: #selector(play))
MPRemoteCommandCenter.shared().nextTrackCommand.addTarget(self, action: #selector(next))
MPRemoteCommandCenter.shared().pauseCommand.addTarget(self, action: #selector(pause))
MPRemoteCommandCenter.shared().previousTrackCommand.addTarget(self, action: #selector(previous))

移除 Remote Control 响应

// 在关闭播放页面时记得移除
MPRemoteCommandCenter.shared().playCommand.removeTarget(self, action: #selector(play))
MPRemoteCommandCenter.shared().nextTrackCommand.removeTarget(self, action: #selector(next))
MPRemoteCommandCenter.shared().pauseCommand.removeTarget(self, action: #selector(pause))
MPRemoteCommandCenter.shared().previousTrackCommand.removeTarget(self, action: #selector(previous))
// 停止响应 Remote Control
UIApplication.shared.endReceivingRemoteControlEvents()

通过重写父类方法响应外部事件

  • 开启接受远程控制

  • 使当前页面成为第一响应者

  • 重写 remoteControlReceivedWithEvent 方法. UIEvent Type 取值:

    • UIEventSubtypeRemoteControlTogglePlayPause // 暂停
    • UIEventSubtypeRemoteControlPreviousTrack // 上一首
    • UIEventSubtypeRemoteControlNextTrack // 下一首
    • UIEventSubtypeRemoteControlPlay // 播放
    • UIEventSubtypeRemoteControlPause // 暂停
  • 关闭接受远程控制

锁屏页面显示播放信息(Now Playing Center)

使用 MPNowPlayingInfoCenter 设置锁屏页面音乐信息.

func setLockScreenPlayingInfo(_ info: YTTMediaInfo) {// Now Playing Center可以在锁屏界面展示音乐的信息,也达到增强用户体验的作用。// https://www.jianshu.com/p/458b67f84f27var infoDic: [String : Any] = [:]infoDic[MPMediaItemPropertyTitle] = info.title // 歌曲名infoDic[MPMediaItemPropertyArtist] = info.singer // 歌手if let img = info.image {infoDic[MPMediaItemPropertyArtwork] = MPMediaItemArtwork(image: img) // 专辑图片}infoDic[MPMediaItemPropertyPlaybackDuration] = info.totalTime // 歌曲总时长infoDic[MPNowPlayingInfoPropertyElapsedPlaybackTime] = info.currentTime // 当前播放时间infoDic[MPNowPlayingInfoPropertyPlaybackRate] = 1.0 // 播放速度MPNowPlayingInfoCenter.default().nowPlayingInfo = infoDic
}

注意: MPNowPlayingInfoPropertyElapsedPlaybackTime 设置的并不是时时的,他是根据你设置的值进行计时的,如果想要在锁屏页面得到准确的时间,请及时刷新 MPNowPlayingInfoPropertyElapsedPlaybackTime 的值.当暂停时要暂停播放时间,只需将 MPNowPlayingInfoPropertyPlaybackRate 设置为 0.播放时设置回 1.

补充说明

iOS 对后台管理十分严格,任何 app 都有大约3分钟或者10分钟的后台执行时间.3分钟或者10分钟后, app 就会被强制挂起.使用 AVAudioSession 申请后台权限时,可以保证播放本地音乐能在后台长久播放,当播放网络音乐时就会出现不能播放情况,针对这情况使用了 beginBackgroundTask 设置后台任务 ID,通过这种方式我们大约可以获得额外的 10 分钟来执行后台任务.为了能无限后台播放网络音乐添加计时器,当即将挂起时再次申请后台任务 ID.

func applicationDidEnterBackground(_ application: UIApplication) {// 这样做,可以在按home键进入后台后 ,播放一段时间,几分钟吧。但是不能持续播放网络歌曲,若需要持续播放网络歌曲,还需要申请后台任务idbgTask = application.beginBackgroundTask(expirationHandler: nil)timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(timerAction), userInfo: nil, repeats: true)
}@objc func timerAction() {timerCount = timerCount + 1if timerCount < 500 {return}timerCount = 0let newTask = UIApplication.shared.beginBackgroundTask(expirationHandler: nil)if bgTask != UIBackgroundTaskInvalid && newTask != UIBackgroundTaskInvalid {UIApplication.shared.endBackgroundTask(bgTask)bgTask = newTask}}

遇到的坑

关于 rate 倍数播放

对于 AVPlayer 的暂停和播放是通过 rate 的值来判断的,但 rate 为 1 时.播放状态,但其为 0 时为暂停.每次调用 play() 方法时,rate 的值都将会置为 1,所以当调用 play 方法时,需要重新设置 rate 的值.

关于AVPlayerItem 切换

在 iOS9 以上系统测试时AVPlayerItem切换正常,但当在 iOS8 系统下,切换了AVPlayerItem 发现无法进行播放,针对这进行百度得到解决方式,iOS8 对于replaceCurrentItem方法支持不是很好,需要每次重新创建 AVPlayer.

其他

  • AVPlayer那些坑
  • 项目参考地址

iOS音视频播放-AVPlayer简单使用相关推荐

  1. iOS音视频播放指南(二)

    1. 让你的App支持画中画 画中画指可以让视频在小窗中播放,可以一边看视频一边刷知乎 你可以使用AVPlayerViewController或者AVPictureInPictureControlle ...

  2. iOS音视频播放指南(一)

    1. 简介 苹果目前提供两个框架用来处理音视频播放 1.AVFoundation AVFoundation用于播放.处理音视频.可以通过结构图看到AVFoundation位于UIKit之下,很好理解A ...

  3. ios nslinkattributename 自定义url_iOS音视频播放指南(二)

    没看第一篇的小伙伴可以先看第一篇 wlzz:iOS音视频播放指南(一)​zhuanlan.zhihu.com 本章主要内容 画中画支持 后台音频播放,锁屏界面显示,远程音频控制 在耳机插拔.接听电话等 ...

  4. 6、Qt Project之音视频播放

    音视频播放  这里简单的制作了一个音乐播放器,播放器的界面设计如下所示: Step1:这里是界面对应的HTML文件: <?xml version="1.0" encoding ...

  5. 【iOS】视频播放之AVPlayer

    [iOS]视频播放之AVPlayer iOS平台使用播放视频,可用的选项一般有这四个,他们各自的作用和功能如下: 使用环境 优点 缺点 AVPlayerViewController AVKit 简单易 ...

  6. iOS 视频播放 - AVPlayer

    iOS实现视频播放,原生代码播放视频更多的使用AVPlayer和AVPlayerViewController进行播放. 其中, AVPlayer不能单独进行播放,仅使用AVPLayer的话,还需要将其 ...

  7. IOS音视频(一)AVFoundation核心类

    IOS音视频(一)AVFoundation核心类 1. AVFoundation框架架构简介 1.1 AVFoundation框架 1.2 AVFoundation 之 Assets 1.3 AVFo ...

  8. IOS音视频(三)AVFoundation 播放和录音

    IOS音视频(三)AVFoundation 播放和录音 1. 音频理论知识 1.1 声音的物理性质 1.2 数字音频 1.2.1 采样.量化和编码 1.2.2 音频编码 1.3 音频编解码 2. 播放 ...

  9. 入门启发:音视频的简单理解

    算机技术领域中,『音视频技术』应该说算是较复杂的小门类.较复杂的东西有个简单的入门指引,或者有前辈带路是很重要的. 前阵子,因为项目中急需音视频技术,虽然网上资料看似很丰富,但对初学者来说,很多资料都 ...

最新文章

  1. Android adb你真的会用吗?
  2. eoLinker-API_Shop_验证码识别与生成类API调用的代码示例合集:六位图片验证码生成、四位图片验证码生成、简单验证码识别等...
  3. 安卓系统换成linux系统软件,将旧安卓手机打造成“简易linux”机器,并部署AdGuardHome...
  4. Kubernetes 是如何调度的?
  5. 消息中间件学习总结(11)——Kafka与RocketMQ的Topic数量对单机性能的影响比较分析
  6. 基于TCP/UDP的socket编程
  7. wine装通达信_linux下安装虚拟机,完美在linux系统下运行通达信软件
  8. joc杂志影响因子2019_化学sci期刊影响因子排名_国际化学期刊2018最新影响因子_分析测试学报影响因子...
  9. 利用公共手机获取短信验证码
  10. div半透明背景,文字不透明
  11. 【武汉加油!中国加油!】挑战七天 实现机器视觉检测有没有戴口罩系统——第四五六七天
  12. DellR720安装系统不能正常进入系统
  13. 面对新的挑战,成为更好的自己--进击的技术er
  14. SCS【13】单细胞转录组之识别细胞对“基因集”的响应 (AUCell)
  15. android 编译libjpeg-turbo
  16. 【机器学习】为什么机器学习难于应用
  17. 拓扑容差如何修改_如何在CAD中通过设置容差参数对多段线进行自动修复重构
  18. html本地化软件,如何为本地化做准备 (HTML)
  19. android ndk x86 arm,NDK r21编译FFmpeg 4.2.2(x86、x86_64、armv7、armv8)
  20. AP_应付税务预扣税Withholding Tax中付款时产生预扣税(案例)

热门文章

  1. 计算机微博实验报告,网络信息交流的工具与模式(实验报告).doc
  2. Django项目处女作
  3. AQS同步器的实现原理
  4. requests库爬取百度首页
  5. 台湾清华大学计算机网络--001
  6. 三菱 FX5U PLC结构化4轴伺服机器人程序
  7. Axure与Mockplus的区别
  8. 长春有学计算机的中专吗,长春比较好的中专学校
  9. 解决jmeter5.4.3在高分辨率下的显示问题
  10. java中web错误返回码,关于在java程序里调用webservice报500返回码的有关问题