uni-app video组件不支持原生画中画,iOS/Android均需模拟实现:iOS须用原生video标签+特定属性且手动触发,App端需manifest配置;Android需原生插件;跨平台推荐CSS固定定位+生命周期控制的伪PiP方案。

uni-app 中 video 组件不支持原生画中画(PiP)
iOS 和 Android 原生 WebView 对 picture-in-picture 的支持非常有限,uni-app 的 video 组件底层依赖 WebView 或小程序 video 能力,**默认无法触发系统级 PiP 模式**。所谓“悬浮播放”,实际是模拟实现:靠自定义容器 + 动态定位 + 生命周期控制来维持小窗状态。
真机上启用 iOS 原生 PiP 的前提条件
iOS 14+ 系统下,只有使用 webview(非 video 组件)并满足严格条件时,才可能唤起系统 PiP 按钮。但 uni-app 的 web-view 组件不暴露 allowsPictureInPicture 控制权,且无法监听 PiP 状态变化 —— 所以不要指望在 uni-app H5 或 App 端通过标准方式开启原生 PiP。
- 必须用
标签(非组件),且设置webkit-playsinline、playsinline、controls - 需用户手动点击系统 PiP 按钮(Safari 下右下角小按钮),不能自动触发
- App 端(iOS)需在
manifest.json中开启UIBackgroundModes: audio,否则切后台后直接中断 - H5 在微信内完全不可用(微信禁用 PiP)
安卓端「悬浮窗」需原生插件配合
uni-app 自身无权限申请 Android 悬浮窗(SYSTEM_ALERT_WINDOW),纯前端 JS 无法绕过系统限制。要实现类似效果,必须:
- 使用原生插件(如
uni_modules/uni-pip-android或自研插件),在AndroidManifest.xml中声明权限,并在运行时动态申请 - 插件需接管视频渲染(通常用
TextureView或SurfaceView),而非走 WebView 的video标签 - uni-app 侧只负责发指令(如
uni.$emit('pip-start', {src: 'xxx.mp4'})),画面和拖拽逻辑全由原生控制 - 注意:Android 12+ 对后台启动 Activity 限制更严,插件需适配
startActivityAsUser或改用WindowManager直接添加 View
最稳妥的跨平台「伪画中画」方案
放弃原生 PiP,用 CSS + 状态管理 + 生命周期钩子模拟。核心是:让视频区域脱离页面流、可拖动、切后台/切页时不销毁、回来时恢复播放。
- 用
position: fixed+z-index容器包裹video组件,宽高设为120px × 68px(适配常见比例) - 监听
onHide和onShow,在onHide中暂停播放、缓存currentTime;onShow后调用play()并seekTo - 拖拽用
touchstart/touchmove+transform: translate(避免重排),记录偏移量存uni.setStorageSync - 注意:iOS 微信内
video组件切后台必 pause,且无法 resume,此时建议降级为封面图 + 播放按钮 - 示例关键代码:
<video :src="currentSrc" ref="videoRef" :autoplay="isPipActive"></video>
搭配onHide中执行this.$refs.videoRef.pause()
真正难的不是拖动或定位,而是各端对 video 生命周期的差异化处理 —— 尤其是微信、QQ、钉钉这些壳,它们会主动 kill 视频资源。别试图统一 API,按渠道做判断才是现实解法。











