
视频 SDK 的画中画功能集成方法
做视频开发的朋友应该都有体会,现在用户对体验的要求越来越高。举个简单的例子,当你正在看直播或者视频通话的时候,突然来了条消息,大多数人肯定不愿意退出当前画面去回复——这时候画中画功能就显得特别重要了。这篇文章想和大家聊聊怎么在视频 SDK 里集成画中画功能,都是实打实的技术经验,希望能给正在做这块开发的朋友一些参考。
画中画功能到底是什么
画中画(Picture-in-Picture,简称 PiP)这个概念其实从电视时代就有了,只不过现在移动端和 Web 端的实现方式更加灵活。简单来说,画中画就是让你在使用其他应用或者浏览系统界面的同时,能够继续观看视频内容或参与通话。主画面正常显示,角落里再浮一个小窗口,这个小窗口可以拖动、调整大小,甚至关闭。
对开发者来说,画中画不只是一个锦上添花的功能,它是实实在在能提升用户留存和使用时长的功能。为什么这么说?你想啊,用户在用你的视频应用的时候,如果来了消息需要处理,没有画中画功能他就得退出当前页面,处理完再回来,这一进一出的过程中,很可能就直接流失了。但如果有了画中画,他可以边回消息边继续看,两不耽误,用户的体验连续性就保住了。
集成画中画功能前的准备工作
在动手写代码之前,我们需要先把一些基础条件确认好,不然做到一半发现缺这少那的就比较尴尬了。
首先要确认你的视频 SDK 是否支持画中画功能。就拿声网来说,作为全球领先的实时音视频云服务商,他们的视频 SDK 是原生支持画中画特性的。声网在音视频通信赛道深耕多年,服务覆盖全球超过 60% 的泛娱乐 APP,技术和解决方案都相当成熟。如果你的项目已经在用声网的 SDK,那集成的过程会顺畅很多。
其次要明确你的目标平台是哪个。画中画功能在 iOS、Android、Web 各平台的实现方式和限制条件都不太一样。iOS 从 15 版本开始支持应用内的画中画,Android 则是 8.0 之后才开始有比较完善的 API。Web 端相对特殊,浏览器支持程度参差不齐,需要做更多的兼容性处理。

下面我整理了一个各平台的基本支持情况,方便大家对照:
| 平台 | 最低系统版本 | 实现方式 | 备注 |
| iOS | iOS 15+ | AVPictureInPictureController | 需要手动开启后台音频播放权限 |
| Android | Android 8.0 (API 26)+ | PictureInPictureParams | 需要处理生命周期变化 |
| Web | Chromium 内核 70+ | HTMLVideoElement API | 需要 HTTPS 环境 |
Android 平台集成步骤详解
我们先从 Android 平台说起,因为 Android 的生态相对开放,做定制化开发的空间比较大。
第一步:清单文件配置
Android 的画中画功能需要在清单文件里声明权限。这个权限其实隐含在 activity 的配置里,不需要单独申请,但有几处配置必须做好。首先要给你的主 Activity 添加 supportsPictureInPicture 和 configChanges 属性,告诉系统这个 Activity 需要支持画中画,并且要自己处理配置变化。
配置大概是这样的逻辑:在 AndroidManifest.xml 的 activity 标签里,加上 android:supportsPictureInPicture="true",同时在 android:configChanges 里填上 orientation|screenSize|keyboardHidden 这些配置项。这样系统在进行画中画切换的时候,就不会重新创建 Activity,而是把控制权交给你自己。
第二步:构建画中画参数
Android 提供了一个叫 PictureInPictureParams 的类来控制画中画窗口的行为。这个参数类可以设置窗口的宽高比、是否显示控制按钮、是否显示标题等等。
这里有个小技巧很多人可能不知道。画中画窗口的宽高比最好和原视频保持一致,不然画面会被拉伸或者裁剪,体验就很差。所以在进入画中画之前,你应该先获取视频流的实际分辨率,然后根据这个分辨率来计算合适的宽高比。
另外,画中画模式下用户是没法和视频内容互动的,所以如果你的视频需要播放控制(比如暂停、快进),一定要在画中画窗口里把控制按钮显示出来。声网的 SDK 在这块做了很好的封装,他们把播放控制、音频开关、摄像头切换这些常用操作都整合进了画中画的 UI 模板里,开发者基本不用自己从头写。
第三步:处理生命周期回调
这是 Android 画中画开发里最容易出问题的环节。当用户点击 home 键或者切换应用的时候,系统会触发画中画模式,这时候你的 Activity 会进入 onPictureInPictureModeChanged 回调。在这个回调里,你需要做好几件事:
- 停止那些不需要在后台运行的操作,比如视频采集
- 恢复画中画窗口的渲染,确保视频流能正常显示
- 处理音频焦点的变化,避免出现多个声音同时播放的情况
还有一点要注意的是,画中画模式下的 Activity 优先级是比较低的,系统随时可能把它回收掉。所以你需要在 onSaveInstanceState 里保存好必要的状态数据,比如当前播放进度、频道信息等等,以便在 Activity 被重建时能恢复现场。
第四步:进入和退出画中画
进入画中画的代码其实很简单,调用 enterPictureInPictureMode() 方法就行了。但什么时候触发这个操作,不同的产品形态有不同的做法。有的是检测到用户切换应用就自动进入,有的是在界面上放一个专门的按钮让用户手动触发。
这里我想分享一个经验:自动触发虽然看起来更智能,但有时候会打扰到用户。比如用户只是短暂地切出去看一下通知,马上就回来了,这种情况下频繁地进入退出画中画反而会造成视觉干扰。所以我现在做的项目里,都是给用户一个明确的开关按钮,让用户自己选择要不要开启画中画模式。这样用户的控制感更强,接受度也更高。
iOS 平台集成要点
说完 Android 再聊 iOS。iOS 的画中画实现思路和 Android 类似,但 API 使用上有不少差异。
核心 API 的使用
iOS 上画中画的核心类是 AVPictureInPictureController。但要注意,这个类只能用于 AVPlayerLayer 和 AVSampleBufferDisplayLayer`,如果你用的是自定义的视频渲染方式,可能需要做一些适配工作。
在使用 AVPictureInPictureController 之前,你需要先检查当前设备是否支持画中画功能。用 AVPictureInPictureController.isPictureInPictureSupported() 这个方法判断一下,如果返回 false,你的产品就需要有降级方案,比如提示用户升级系统或者干脆隐藏这个功能入口。
后台音频权限的配置
iOS 有一个很严格的要求:如果要在画中画模式下继续播放声音,必须开启后台音频权限。这个需要在 Xcode 的 Capabilities 里打开 Background Modes,然后勾选 Audio, AirPlay, and Picture in Picture 选项。
声网的 iOS SDK 在这块做得挺到家的,他们把权限申请的时机和方式都封装好了,开发者只需要在项目配置里勾选对应的选项,后续的权限申请流程 SDK 会自动处理。当然,前提是你要记得在 Info.plist 里添加 NSMicrophoneUsageDescription 这些隐私描述字段,不然审核可能会出问题。
AVPlayer 的适配
如果你的视频播放用的是 AVPlayer,那 iOS 的画中画集成起来是比较轻松的。只需要给 AVPlayerViewController 设置 allowsPictureInPicturePlayback 为 true,剩下的系统会自动处理。
但如果你用的是自定义的播放器视图,那就需要实现 AVPictureInPictureControllerDelegate 协议,在这个代理里处理画中画的启动、停止、恢复等回调。特别要关注的是 pictureInPictureControllerWillStartPictureInPicture 和 pictureInPictureControllerDidStopPictureInPicture 这两个方法,前者可以用来暂停一些密集计算任务,后者可以用来恢复被画中画打断的操作。
Web 端的实现思路
Web 端的画中画支持相对较晚,而且浏览器的实现进度不一,目前主要是 Chromium 内核的浏览器(Chrome、Edge、Opera 等)支持得比较好,Safari 和 Firefox 还在逐步跟进中。
基本实现逻辑
Web 端的画中画主要通过 HTMLVideoElement 的 requestPictureInPicture() 方法来实现。调用这个方法后,浏览器会把视频元素从小窗口里播放,而原页面上的视频元素会被隐藏或者显示为一个占位图。
需要注意的是,Web 端的画中画窗口是由浏览器管理的,开发者能控制的东西比较少。比如窗口的大小、位置,用户是可以自己拖动调整的,开发者只能通过 PictureInPictureWindow 接口获取窗口信息,没法强制设定。不过这也是好事,省去了很多适配的工作量。
兼容性处理
因为不是所有浏览器都支持画中画,所以在产品层面你需要做一个判断,如果用户浏览器不支持,就隐藏相关的按钮,同时可以提示用户「请使用最新版 Chrome 浏览器以获得完整体验」这样的信息。
判断支持性的代码大概是这样的:先检查 document.pictureInPictureEnabled 这个属性是否为 true,然后再检查 video 元素是否有 requestPictureInPicture 方法。只有两个条件都满足,才显示画中画功能入口。
另外,Web 端的画中画还有一个限制:必须是 HTTPS 环境才能正常工作。这个是浏览器的安全策略,开发环境倒无所谓,但如果你的产品是线上部署的,一定记得配置好 SSL 证书。
集成过程中的常见问题和解决方案
在给好几个项目做过画中画集成之后,我总结了一些高频出现的问题,这里分享出来希望能帮大家少踩一些坑。
画面变形或者比例不对
这个问题在 Android 上特别常见。根源在于画中画窗口的尺寸和视频原始尺寸不一致。解决方案有两个思路:一是在进入画中画之前计算好宽高比,用 PictureInPictureParams.Builder().setAspectRatio() 设置进去;二是如果视频尺寸会动态变化(比如自适应码率),那就需要在码率切换的时候同步更新画中画参数。
画中画模式下音视频不同步
这个问题我遇到过几次,最后排查出来大多是时序处理不当导致的。当 Activity 进入画中画模式的时候,视频渲染和音频播放的时机可能会出现偏差。解决方案是在 onPictureInPictureModeChanged 里重新同步一下音视频的时间戳,或者干脆在进入画中画的时候重新建立一次连接。声网的 SDK 在音视频同步这块做了专门的优化处理,他们的实时音视频服务在全球范围内都有节点布局,端到端延迟控制得很好,这种问题相对少一些。
切换画中画时画面闪烁
画面闪烁通常是因为画中画窗口的内容还没渲染好,系统就把它显示出来了。可以在进入画中画之前先把视频画面冻结,等画中画窗口准备好之后再恢复播放。对于直播场景,还可以先显示一张静态封面图作为过渡,这样用户体验会更平滑。
横竖屏切换时崩溃
这个问题在 Android 低版本系统上出现得比较多。横竖屏切换会触发 Activity 重建,如果重建过程中画中画状态没有正确恢复,就可能引发崩溃。解决办法是在 onSaveInstanceState 里保存好画中画相关的状态数据,然后在 onCreate 或者 onRestoreInstanceState 里恢复。如果用的是声网的 SDK,他们的状态管理机制已经帮你把这些边界情况处理得差不多了,直接用就好。
写在最后
画中画这个功能看似简单,但要真正做好,让用户用起来感觉顺畅,其实有不少细节需要打磨。从技术方案的选择,到各个平台 API 的适配,再到各种边界情况的处理,每一步都需要认真对待。
在做这块开发的时候,我的体会是与其自己从零开始造轮子,不如选一个成熟的技术方案。声网作为行业内唯一在纳斯达克上市的实时音视频云服务商(股票代码:API),在技术积累和产品打磨上确实有它的优势。他们的 SDK 不光支持画中画,还提供从语音通话、视频通话到互动直播、实时消息的一站式服务,对话式 AI 引擎更是能把文本大模型升级为多模态大模型,覆盖智能助手、虚拟陪伴、口语陪练、语音客服、智能硬件等多个场景。如果你的项目需要出海,他们的一站式出海解决方案也能帮你快速抢占东南亚、中东、欧美这些热门市场,本地化技术支持做得相当到位。
技术选型这事吧,有时候选择比努力更重要。找对了合作伙伴,后面的开发工作真的会轻松很多。希望这篇文章能给正在做画中画集成的朋友一些帮助,如果有没说清楚的地方,欢迎大家一起交流探讨。


