23、移动端适配:移动浏览器兼容性、Android WebRTC、iOS WebRTC、移动端性能调优
移动端做 WebRTC,说白了就是「戴着镣铐跳舞」。
我在刚接触这个领域时,以为 PC 上能跑通的代码,手机端顶多改改 UI 尺寸就行。结果呢?iOS 的 Safari 直接不显示视频,Android 的 Chrome 频繁断连,CPU 温度飙到烫手……嗯,那段时间我几乎每天都在跟各种「玄学」问题搏斗。
今天这篇,我就把这几年的踩坑经验掰开揉碎,跟你聊聊移动端适配到底该怎么搞。
核心观点:移动端 WebRTC 不是「缩小版」的 PC 端,而是一个全新的战场。浏览器差异、系统限制、硬件瓶颈,每一项都能让你抓狂。
移动浏览器兼容性:Safari 与 Chrome 的「爱恨情仇」
先说说浏览器。移动端主流就两个:iOS 的 Safari 和 Android 的 Chrome。但它们的 WebRTC 实现,差异大得离谱。
Safari 的「特殊癖好」
我个人习惯在 iOS 上先用 Safari 测试,因为它的问题最多。最典型的一个:Safari 不允许自动播放音频/视频。你想想看,用户点进页面,你直接 getUserMedia 打开摄像头,在 Safari 上大概率会失败。
避坑指南:我曾经因为这个问题被客户投诉了三次。解决方案是在用户点击「开始通话」按钮后,再调用 getUserMedia。不要试图在页面加载时自动触发。
另一个坑是 Safari 的 ICE 候选者收集策略。它默认只收集 host 类型的候选者,srflx 和 relay 需要额外配置。我遇到过的情况是:内网通话没问题,一到外网就卡死。后来发现是 Safari 没把公网 IP 发出去。
// Safari 上强制收集 srflx 候选者
const pc = new RTCPeerConnection({
iceTransportPolicy: 'all', // 不要用 'relay'
iceServers: [
{ urls: 'stun:stun.l.google.com:19302' }
]
});
Chrome 的「性能陷阱」
Android 上的 Chrome 相对友好,但有个问题:内存占用高。我测试过,一个 720p 的视频通话,Chrome 能吃掉 300MB+ 的内存。低端机型直接闪退。
为什么会这样?因为 Chrome 的 WebRTC 实现更完整,但代价是资源消耗大。我的建议是:在 Android 上主动降低分辨率,不要用默认的 1080p。
| 浏览器 | 常见问题 | 我的解决方案 |
|---|---|---|
| Safari (iOS) | 自动播放被拦截、ICE 候选者不全 | 用户手势触发、强制 iceTransportPolicy: 'all' |
| Chrome (Android) | 内存占用高、低端机型闪退 | 限制分辨率到 480p、关闭 simulcast |
Android WebRTC:碎片化是最大的敌人
Android 的碎片化,做移动开发的都懂。WebRTC 在 Android 上,主要分两种场景:WebView 内嵌和原生 App 集成。
WebView 的「兼容性黑洞」
很多团队图省事,直接用 WebView 加载 WebRTC 页面。但不同厂商的 WebView 实现天差地别。华为、小米、OPPO 的 WebView,对 WebRTC 的支持程度完全不同。
我记得有一次,在小米手机上 getUserMedia 返回的音频轨道是空的,但同样的代码在三星上完全正常。查了两天,发现是小米的 WebView 默认禁用了音频输入权限。
警告:不要依赖 WebView 的默认行为。一定要在 AndroidManifest.xml 中显式声明权限:CAMERA、RECORD_AUDIO、INTERNET。并且要在运行时动态申请。
原生集成:Google 的官方库
如果你做原生 App,直接用 Google 的 org.webrtc:google-webrtc 库。但要注意版本号。我踩过的坑是:1.0.32006 版本在 Android 12 上有视频渲染崩溃的问题,升级到 1.0.33001 才解决。
// Android 原生 WebRTC 初始化示例
PeerConnectionFactory.initialize(
PeerConnectionFactory.InitializationOptions.builder(context)
.setFieldTrials("WebRTC-H264HighProfile/Enabled/")
.createInitializationOptions()
);
iOS WebRTC:Safari 之外的「隐藏关卡」
iOS 上除了 Safari,还有 WKWebView 和原生 App 两种方式。但 iOS 有个「隐藏关卡」:App Store 审核。
你想想看,如果你的 App 用了 WebRTC,但没在 Info.plist 中声明「使用摄像头和麦克风」,审核会被直接拒绝。我有个朋友就因为这个被拒了三次,每次修改后重新提交都要等一周。
WKWebView 的「性能瓶颈」
WKWebView 在 iOS 14 之后才完整支持 WebRTC。但即使支持,性能也远不如原生。我测试过,同样的 720p 视频流,WKWebView 的 CPU 占用比原生高 30%。
我的建议是:如果对性能有要求,直接走原生。用 Google 的 WebRTC iOS 框架,或者用 Agora 等第三方 SDK。
个人经验:在 iOS 上,我习惯用 RTCCameraVideoCapturer 而不是 AVCaptureSession。前者是 WebRTC 官方封装的,对视频旋转、缩放处理得更好。
移动端性能调优:从「能用」到「流畅」
性能调优,说白了就是跟 CPU、内存、网络较劲。我总结了三个核心方向:视频编码、网络策略、硬件加速。
视频编码:别用 VP8,用 H.264
移动端硬件编码器对 H.264 的支持最好。VP8 虽然开源,但在移动端解码效率低。我做过对比:同样 480p 的视频,H.264 的 CPU 占用比 VP8 低 40%。
// 强制使用 H.264 编码
const sdp = pc.localDescription.sdp;
const modifiedSdp = sdp
.replace('VP8/90000', 'H264/90000')
.replace('VP9/90000', 'H264/90000');
pc.setLocalDescription(new RTCSessionDescription({
type: pc.localDescription.type,
sdp: modifiedSdp
}));
网络策略:动态调整码率
移动网络不稳定,4G 和 Wi-Fi 切换时,码率必须动态调整。我习惯用 RTCRtpSender.setParameters 来实时控制。
// 动态降低码率
const sender = pc.getSenders()[0];
const params = sender.getParameters();
params.encodings[0].maxBitrate = 300000; // 300kbps
sender.setParameters(params);
硬件加速:别让 CPU 干 GPU 的活
移动端一定要开启硬件加速。Android 上通过 setVideoHardwareAccelerationEnabled(true),iOS 上通过 RTCDefaultVideoDecoderFactory 和 RTCDefaultVideoEncoderFactory。
关键指标:性能调优后,CPU 占用应低于 30%,内存占用低于 200MB,帧率稳定在 24fps 以上。达不到这个标准,用户就会觉得「卡」。
知识体系总览
下面这张图,是我梳理的移动端 WebRTC 适配核心逻辑。你可以把它当作「检查清单」,每次遇到问题就对照着看。
嗯,移动端适配就是这么回事。没有银弹,只有一个个具体问题去解决。你只要记住:先保证能用,再追求流畅。别一开始就想着 4K 60fps,那在移动端基本不现实。
最后一句:我每次做移动端 WebRTC 项目,都会准备一台低端 Android 机(比如红米 9A)和一台旧 iPhone(比如 iPhone 8)。在这两台机器上跑通了,基本就稳了。别只拿旗舰机测试,那会给你「一切完美」的错觉。