iOS通知栏自定义音频播放器控件:URL流式播放及通知控制实现
我来帮你搞定iOS通知栏的媒体控件问题!要实现像Gaana、Saavn那样的通知栏播放控制,你需要用到Apple的几个核心框架:AVFoundation(处理音频播放)和MediaPlayer(负责通知栏控件和远程命令响应)。下面是一步步的实现指南:
1. 先配置音频会话,确保后台播放权限
iOS需要知道你的App的音频用途,才能允许后台播放并显示通知控件。首先要做这两步:
- 导入AVFoundation框架,然后在App启动或者播放前配置音频会话:
import AVFoundation func setupAudioSession() { let audioSession = AVAudioSession.sharedInstance() do { // 设置类别为.playback,支持后台播放、锁屏播放 try audioSession.setCategory(.playback, mode: .default) try audioSession.setActive(true) } catch { print("音频会话配置失败: \(error.localizedDescription)") } }
- 修改Info.plist添加后台模式:添加
Required background modes项,勾选App plays audio or streams audio/video using AirPlay,这样App在后台也能持续播放音频。
2. 用MPRemoteCommandCenter处理通知栏的控制命令
这个类专门负责处理通知栏、锁屏甚至耳机线控的播放指令,你需要给每个操作(播放、暂停、下一曲、快退)绑定响应逻辑:
- 导入MediaPlayer框架,然后初始化命令中心并添加事件监听:
import MediaPlayer func setupRemoteCommands() { let commandCenter = MPRemoteCommandCenter.shared() // 播放命令响应 commandCenter.playCommand.addTarget { [weak self] _ in self?.audioPlayer?.play() self?.updateNowPlayingInfo() // 更新通知栏状态 return .success } // 暂停命令响应 commandCenter.pauseCommand.addTarget { [weak self] _ in self?.audioPlayer?.pause() self?.updateNowPlayingInfo() return .success } // 下一曲命令响应 commandCenter.nextTrackCommand.addTarget { [weak self] _ in self?.playNextTrack() // 这里替换成你的下一曲逻辑 self?.updateNowPlayingInfo() return .success } // 快退/上一曲命令响应:这里做快退10秒的示例,你也可以改成跳转到上一曲 commandCenter.previousTrackCommand.addTarget { [weak self] _ in guard let player = self?.audioPlayer else { return .commandFailed } player.currentTime = max(player.currentTime - 10, 0) // 快退10秒,避免负数 self?.updateNowPlayingInfo() return .success } // 可选:添加快进命令(比如快进10秒) commandCenter.skipForwardCommand.preferredIntervals = [10] commandCenter.skipForwardCommand.addTarget { [weak self] _ in guard let player = self?.audioPlayer else { return .commandFailed } player.currentTime = min(player.currentTime + 10, player.duration) self?.updateNowPlayingInfo() return .success } }
注意用[weak self]避免循环引用,处理完命令后一定要调用updateNowPlayingInfo()同步通知栏状态。
3. 更新MPNowPlayingInfoCenter显示歌曲信息
这个类负责在通知栏和锁屏展示歌曲的封面、标题、艺术家、播放进度等内容,每次播放状态变化或切换歌曲都要更新它:
func updateNowPlayingInfo() { guard let player = audioPlayer else { return } var nowPlayingInfo = [String: Any]() // 填充歌曲基本信息 nowPlayingInfo[MPMediaItemPropertyTitle] = "当前歌曲标题" nowPlayingInfo[MPMediaItemPropertyArtist] = "艺术家名称" // 添加封面图:如果是网络图片,先下载转成UIImage再传入 if let coverImage = UIImage(named: "song_cover") { nowPlayingInfo[MPMediaItemPropertyArtwork] = MPMediaItemArtwork(boundsSize: coverImage.size) { size in return coverImage } } // 同步播放进度和状态 nowPlayingInfo[MPNowPlayingInfoPropertyElapsedPlaybackTime] = player.currentTime nowPlayingInfo[MPMediaItemPropertyPlaybackDuration] = player.duration nowPlayingInfo[MPNowPlayingInfoPropertyPlaybackRate] = player.isPlaying ? 1.0 : 0.0 // 刷新通知栏信息 MPNowPlayingInfoCenter.default().nowPlayingInfo = nowPlayingInfo }
如果是流式音频,一开始duration可能是NaN,等音频加载完成后再更新即可。
4. 生命周期和内存管理注意事项
- 后台播放保持:只要音频会话配置正确、后台模式开启,AVPlayer默认支持后台播放,通知栏控件会自动显示。
- 清理资源:在App退出或停止播放时,记得移除命令监听避免内存泄漏:
func cleanupRemoteCommands() { let commandCenter = MPRemoteCommandCenter.shared() commandCenter.playCommand.removeTarget(nil) commandCenter.pauseCommand.removeTarget(nil) commandCenter.nextTrackCommand.removeTarget(nil) commandCenter.previousTrackCommand.removeTarget(nil) }
5. 测试要点
- 必须用真机测试:模拟器的通知栏媒体控件有时候不会正常显示。
- 流式播放初始化:用AVPlayer加载音频URL很简单:
guard let audioURL = URL(string: "你的音频流地址") else { return } audioPlayer = AVPlayer(url: audioURL)
内容的提问来源于stack exchange,提问作者Alok Maurya
相关产品推荐
相关产品推荐

