如何从playbackStoreID获取MPMediaItem?解决Apple Music队列跨启动恢复问题
解决Apple Music歌曲队列跨启动保存与恢复的问题
嗨,这个问题我之前开发音乐播放器的时候也踩过坑!本地歌曲用persistentID确实靠谱,但Apple Music的媒体项因为是云端关联的,它的persistentID是动态生成的,跨应用启动就会失效,所以必须用playbackStoreID来持久化和恢复,下面是具体的实现思路和代码示例:
一、队列保存:区分本地与Apple Music歌曲
首先在保存队列时,我们需要给不同类型的歌曲标记不同的存储字段:
- 本地歌曲:依然保存
persistentID(UInt64类型) - Apple Music歌曲:保存
playbackStoreID(字符串类型,这是唯一的云端标识)
代码示例(Swift):
// 假设你的当前队列是[MPMediaItem]类型的数组 func saveQueue(_ queue: [MPMediaItem]) { let queueData = queue.map { item -> [String: Any] in // 判断是否为Apple Music/云媒体项 if let storeID = item.playbackStoreID, !storeID.isEmpty { return [ "itemType": "appleMusic", "identifier": storeID ] } else { return [ "itemType": "local", "identifier": item.persistentID ] } } // 这里可以选择存到UserDefaults、Core Data或者其他本地存储 UserDefaults.standard.set(queueData, forKey: "savedPlaybackQueue") }
二、队列恢复:通过playbackStoreID获取MPMediaItem
恢复时,针对保存的playbackStoreID,使用MPMediaQuery搭配对应的谓词来查询媒体项:
代码示例(Swift):
func restoreQueue() -> [MPMediaItem] { guard let savedQueue = UserDefaults.standard.array(forKey: "savedPlaybackQueue") as? [[String: Any]] else { return [] } var restoredItems = [MPMediaItem]() for itemData in savedQueue { guard let itemType = itemData["itemType"] as? String, let identifier = itemData["identifier"] else { continue } if itemType == "appleMusic" { guard let storeID = identifier as? String else { continue } // 创建基于playbackStoreID的谓词 let predicate = MPMediaPropertyPredicate( value: storeID, forProperty: MPMediaItemPropertyPlaybackStoreID ) let query = MPMediaQuery() query.addFilterPredicate(predicate) // 取查询结果的第一个(理论上唯一) if let appleMusicItem = query.items?.first { restoredItems.append(appleMusicItem) } } else { guard let persistentID = identifier as? UInt64 else { continue } // 本地歌曲用persistentID查询 let predicate = MPMediaPropertyPredicate( value: persistentID, forProperty: MPMediaItemPropertyPersistentID ) let query = MPMediaQuery() query.addFilterPredicate(predicate) if let localItem = query.items?.first { restoredItems.append(localItem) } } } return restoredItems }
三、关键注意事项
- 权限检查:在查询媒体库前,必须确保已经获取了媒体库访问权限,否则查询会返回空。记得在启动时调用
MPMediaLibrary.requestAuthorization()来请求权限。 - 异常处理:如果用户之后从Apple Music库中移除了某首歌,查询会返回
nil,这时候你需要从恢复的队列中移除该条目,或者给用户提示。 - 避免误用persistentID:Apple Music媒体项的
persistentID是本地临时标识,每次应用重启或系统同步后都可能变化,绝对不能用它来持久化云端歌曲。
这样处理后,你的应用就能稳定地跨启动保存和恢复包含Apple Music歌曲的播放队列了!
内容的提问来源于stack exchange,提问作者Thomas




