Objective-C使用kMRMediaRemoteNowPlayingInfoArtworkData获取Spotify TouchBar专辑封面异常
核心根因
你之前的判断完全正确,用kMRMediaRemoteNowPlayingInfoArtworkData取封面的方式本身就存在长期有效性的硬伤:
- 这个字段从设计之初就不是用来持久存储封面的:它返回的是MediaRemote跨进程透传的临时内存映射块,只要回调函数执行完,对应内存就会被系统直接回收,没有任何内存持有保障,这就是为什么数据只在歌曲刚启动的0.5秒内可读,之后就失效的根本原因。
- 再叠加Spotify的上报逻辑特性:macOS版Spotify在上报播放信息时,只会在播放刚启动的极短窗口内,临时把封面数据塞进这个字段,进入稳定播放阶段就会主动清空这个字段,减少不必要的IPC传输开销。
修复实现方案
直接绕开原有的ArtworkData字段,改用MediaRemote专门提供的封面获取接口。这个接口内部会自动完成跨进程数据的深拷贝,返回的资源生命周期完全由当前应用管控,不会出现短时间失效的问题。
替换后的核心代码
- (void)updateInfo { // 常规元数据获取逻辑保持不变 MRMediaRemoteGetNowPlayingInfo(dispatch_get_main_queue(), ^(NSDictionary *info) { NSString *album = [info objectForKey:kMRMediaRemoteNowPlayingInfoAlbum]; NSString *artist = [info objectForKey:kMRMediaRemoteNowPlayingInfoArtist]; NSString *title = [info objectForKey:kMRMediaRemoteNowPlayingInfoTitle]; // 单独调用专用封面接口,不要从元数据字典里硬抠ArtworkData MRMediaRemoteGetArtwork(dispatch_get_main_queue(), ^(CGImageRef artworkRef) { NSImage *albumart = nil; if (artworkRef) { // 尺寸按TouchBar小组件的展示要求初始化即可 albumart = [[NSImage alloc] initWithCGImage:artworkRef size:NSMakeSize(60, 60)]; } // 沿用原有差异判断逻辑,避免无意义的通知重复发送 if (self.album != album || self.artist != artist || self.title != title || self.albumArt != albumart) { self.album = album; self.artist = artist; self.title = title; self.albumArt = albumart; self.appIcon = albumart ?: [NSImage imageNamed:NSImageNameMusic]; [[NSNotificationCenter defaultCenter] postNotificationName:NowPlayingInfoNotification object:self]; } }); }); }
实际落地的兼容注意点
- 不需要手动对拿到的封面数据做拷贝操作,
MRMediaRemoteGetArtwork内部已经处理好了跨进程数据的完整拷贝,返回的CGImage资源完全受当前应用的内存管理逻辑约束。 - Spotify上报的TouchBar适配封面分辨率刚好匹配小组件的展示尺寸,不需要额外发起网络请求拉取高分辨率版本,能大幅降低运行时的CPU和网络开销。
- 如果碰到个别版本的Spotify不主动触发封面更新的情况,可以注册
kMRMediaRemoteNowPlayingInfoDidChangeNotification通知,在播放元数据变更时自动重新拉取封面,不要用固定频率的定时器轮询,避免不必要的IPC性能损耗。
内容的提问来源于stack exchange,提问作者snapraze
相关产品推荐
相关产品推荐

