必须通过原生插件调用ios的mpnowplayinginfocenter和android的mediasession实现锁屏控制,uni-app js层无法直接操作;需启用后台音频、使用真实音频播放器、条件编译对接原生api,并通过全局事件监听上一首/下一首。

uni-app 中如何监听锁屏状态并控制媒体播放
锁屏界面的上一首/下一首控制,本质是让系统媒体中心(iOS 的 Now Playing Info Center / Android 的 MediaSession)响应用户操作。uni-app 本身不直接支持该能力,必须通过原生插件或条件编译调用原生 API 实现。
纯 vue 页面 + uni-app API 无法触发锁屏控件,这是常见误解。你看到的“锁屏控制”实际依赖原生层注册 MPNowPlayingInfoCenter(iOS)或 MediaSession(Android),并在后台持续运行音频上下文。
- 必须启用后台音频能力:iOS 需在
manifest.json中勾选「后台音频」;Android 需确保AudioManager.STREAM_MUSIC播放且未被静音 - 必须使用真实音频播放(
uni.createInnerAudioContext()不足以激活锁屏控件,需native audio player或weex-stream类插件) - uni-app H5 端完全不支持锁屏控制——该功能仅存在于 App 端(iOS/Android)
uni-app 条件编译下对接 iOS Now Playing Info Center
iOS 锁屏控件响应依赖 MPNowPlayingInfoCenter,需原生插件桥接。推荐使用社区插件 uni-native-js 或自定义原生模块,而非试图用 JS 模拟。
关键点:JS 层不能直接写入 MPNowPlayingInfoCenter,必须由原生方法暴露接口。例如插件提供:
uni.setNowPlayingInfo({
title: '歌名',
artist: '歌手',
album: '专辑',
elapsedTime: 120,
duration: 240,
playbackRate: 1.0,
playbackBufferEmpty: false
})
上一首/下一首事件则通过原生监听 MPRemoteCommandCenter 的 skipForwardCommand 和 skipBackwardCommand,再回调 JS。
- 跳过命令默认无时间间隔限制,需在原生层加防抖(如 500ms 内重复点击忽略)
-
playbackRate必须设为非零值(如1.0),否则锁屏控件显示暂停态,无法响应播放/暂停指令 - iOS 15+ 要求音频会话 category 为
AVAudioSessionCategoryPlayback,否则锁屏控件不出现
Android MediaSession 实现上一首/下一首监听
Android 端需创建 MediaSession 并设置 callback,同时将 MediaSessionCompat 与播放器绑定。uni-app 中无法直接操作,必须通过原生插件封装。
典型插件调用方式:
uni.setMediaSession({
metadata: {
title: '歌名',
artist: '歌手',
album: '专辑',
duration: 240000 // 单位毫秒
},
callbacks: {
onPlay: () => { /* 播放逻辑 */ },
onPause: () => { /* 暂停逻辑 */ },
onSkipToNext: () => { uni.$emit('media-next') },
onSkipToPrevious: () => { uni.$emit('media-prev') }
}
})
注意:Android 锁屏控件图标和文案受系统主题影响,无法完全自定义;部分厂商(如华为、小米)会拦截或限制 MediaSession 行为,需测试真机。
- 必须调用
setActive(true)才能激活控件,否则锁屏不显示按钮 - 若应用进入后台后音频中断(如被微信抢占),需监听
onAudioFocusChange并重置MediaSession - Android 8.0+ 要求前台服务(Foreground Service)配合
startForeground(),否则媒体控件可能闪退或失效
uni-app 中监听上一首/下一首事件的实际写法
不要在 onLoad 或 mounted 里直接写监听,而应在原生插件初始化成功后订阅事件。推荐用全局事件总线解耦:
uni.$on('media-prev', () => {
// 切换到上一首
const currentIndex = this.currentIndex - 1
if (currentIndex >= 0) {
this.playSong(this.playlist[currentIndex])
}
})
uni.$on('media-next', () => {
// 切换到下一首
const currentIndex = this.currentIndex + 1
if (currentIndex <p>容易忽略的是:锁屏控件点击时,App 可能处于后台甚至被系统挂起,因此播放逻辑必须能从任意状态恢复(比如检查 <code>audioContext</code> 是否已销毁、是否需要重新 init)。</p>
- 避免在事件回调中直接调用异步 API(如
uni.downloadFile),应先校验资源可用性 - 同一首歌多次触发
media-next时,要防止重复加载或重复 emit - Android 上部分设备会把双击播放键识别为「下一首」,需在原生层区分单双击,或统一按单击处理
锁屏控制不是纯前端逻辑,它卡在原生能力和 JS 生命周期之间。最常出问题的地方,是以为设置了 title 就能显示控件,却漏掉了音频会话激活、后台权限、插件初始化顺序这三个硬性门槛。











