Apple Music歌曲播放异常排查:MPMusicPlayerController调用问题
问题排查与解决方案
看起来你遇到的核心问题是使用了错误的队列描述符类型,再加上对用户库歌曲的播放逻辑处理不当,导致播放器无法正确构建播放队列,进而出现超时和命令发送失败的错误。下面一步步拆解问题并给出修复方案:
1. 核心错误:误用Queue Descriptor
你当前使用的MPMusicPlayerStoreQueueDescriptor是专门为Apple Music Store中的非用户库歌曲设计的,但你的歌曲属于用户iCloud媒体库(从返回的isLibrary = 1和type = "library-songs"可以确认),这类歌曲需要使用MPMusicPlayerMediaItemQueueDescriptor来构建播放队列——因为它依赖本地/云端同步的MPMediaItem实例,而非Store ID。
你传入的i.B0VN4GGf7Eldk是Apple Music API返回的iCloud库歌曲ID,这个ID对应MPMediaItem的MPMediaItemPropertyCloudItemID属性,而不是Store ID,所以用它来初始化MPMusicPlayerStoreQueueDescriptor完全不匹配,这就是播放器无法识别队列、出现超时和错误的根本原因。
2. 修复后的代码实现
首先需要通过iCloud库ID查询对应的MPMediaItem,再用它来构建播放队列:
import MediaPlayer let musicPlayerController = MPMusicPlayerController.systemMusicPlayer func beginPlayback(cloudItemID: String) { // 1. 创建查询条件,匹配iCloud库歌曲ID let predicate = MPMediaPropertyPredicate(value: cloudItemID, forProperty: MPMediaItemPropertyCloudItemID) let query = MPMediaQuery(songs: [predicate]) guard let mediaItems = query.items, !mediaItems.isEmpty else { print("未找到对应库歌曲") return } // 2. 使用媒体项创建队列描述符 let descriptor = MPMusicPlayerMediaItemQueueDescriptor(mediaItems: mediaItems) descriptor.startItem = mediaItems.first // 设置开始播放的歌曲 // 3. 设置队列并准备播放 musicPlayerController.setQueue(with: descriptor) musicPlayerController.prepareToPlay { error in if let error = error { print("准备播放失败:\(error.localizedDescription)") return } self.musicPlayerController.play() } } // 调用时传入API返回的id beginPlayback(cloudItemID: "i.B0VN4GGf7Eldk")
3. 额外注意事项
- 权限配置:确保在
Info.plist中添加NSAppleMusicUsageDescription键,说明你需要访问Apple Music和媒体库的原因,否则会导致权限不足无法查询媒体项。 - 播放器类型:
systemMusicPlayer是系统全局播放器,可能会和其他音乐APP的播放状态冲突,如果问题仍存在,可以尝试改用applicationMusicPlayer(仅在你的APP内生效)。 - 错误处理:在
prepareToPlay的回调中一定要处理错误,比如网络问题导致云端歌曲无法加载的情况。
4. 解释你遇到的错误日志
[MPMusicPlayerController prepareToPlay] timeout:因为你用了错误的Descriptor,播放器无法解析队列,导致准备播放的操作超时。MPCPlayerRequestErrorDomain Code=1 "No commands provided.":播放队列无效,播放器没有可执行的播放命令。Code=1000 "Failed to send command 0":队列未正确初始化,发送播放命令时失败。
内容的提问来源于stack exchange,提问作者NickDK




