4、浏览器兼容性:支持WebRTC的浏览器、getUserMedia API兼容性、适配库(adapter.js)的使用
做WebRTC开发,最头疼的问题是什么?
我个人觉得,不是信令怎么设计,也不是媒体流怎么控制——而是浏览器兼容性。你想想看,同一个getUserMedia调用,在Chrome上跑得好好的,换到Safari就报错,再换到Firefox又换了一套参数写法。嗯,这确实让人头大。
我记得刚接触WebRTC那会儿,花了一整天调试一个摄像头权限问题。最后发现,只是因为我没加适配库。从那以后,我养成了一个习惯:任何WebRTC项目,第一件事就是引入adapter.js。
核心观点:浏览器兼容性不是「要不要处理」的问题,而是「怎么处理更优雅」的问题。adapter.js就是官方给出的标准答案。
4.1 哪些浏览器支持WebRTC?
先说结论:目前主流浏览器基本都支持WebRTC了。但支持的版本和程度有差异。
| 浏览器 | 支持起始版本 | WebRTC 1.0 支持情况 | 备注 |
|---|---|---|---|
| Chrome | 28+ | 完整支持 | 最早支持,最稳定 |
| Firefox | 22+ | 完整支持 | 与Chrome实现略有差异 |
| Safari | 11+ | 基本支持 | 早期版本问题较多 |
| Edge | 12+(旧版) 79+(Chromium版) |
旧版部分支持 新版完整支持 |
建议使用Chromium版 |
| Opera | 20+ | 完整支持 | 与Chrome同内核 |
| Samsung Internet | 4+ | 基本支持 | 移动端常见 |
这里有个坑要注意:Safari在11到13版本之间,对WebRTC的支持是「半残」的。我在项目中遇到过,用户用Safari 12打开页面,视频通话直接黑屏。查了半天,发现是SDP协商格式不兼容。后来强制升级到Safari 14才解决。
避坑指南:如果你要支持iOS用户,建议最低要求Safari 14+。iOS上的第三方浏览器(如微信内置浏览器)也用的是Safari内核,所以同样受限。
4.2 getUserMedia API的兼容性
getUserMedia是WebRTC的入口。说白了,就是让浏览器帮你打开摄像头和麦克风。但这个API在不同浏览器上的表现,差别还挺大。
为什么会这样?因为getUserMedia经历了两次大的变化:
- 旧版:navigator.getUserMedia() —— 带回调函数,各浏览器前缀不同
- 新版:navigator.mediaDevices.getUserMedia() —— 返回Promise,标准写法
我建议你直接使用新版API。但要注意,Safari 11之前不支持mediaDevices对象。Firefox和Chrome虽然支持,但参数格式也有细微差别。
来看一个兼容性写法:
// 不推荐:直接调用旧版API
navigator.getUserMedia({ video: true }, success, error);
// 推荐:使用新版API + 降级处理
const constraints = {
video: {
width: { ideal: 1280 },
height: { ideal: 720 }
},
audio: true
};
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
navigator.mediaDevices.getUserMedia(constraints)
.then(stream => {
// 使用stream
})
.catch(err => {
console.error('获取媒体流失败:', err);
});
} else {
// 降级处理:提示用户升级浏览器
alert('您的浏览器不支持WebRTC,请升级到最新版本');
}
个人经验:constraints参数在不同浏览器上的支持度也不一样。比如Chrome支持width/height的ideal/exact/min/max,但Safari只支持ideal。我一般只用ideal,兼容性最好。
4.3 适配库 adapter.js 的使用
adapter.js是Google官方维护的一个垫片库。它的作用很简单:把不同浏览器的WebRTC实现差异抹平,让你写一套代码,到处运行。
说白了,adapter.js做了三件事:
- 前缀统一:把webkitRTCPeerConnection、mozRTCPeerConnection等统一成RTCPeerConnection
- API垫片:给不支持新版API的浏览器添加mediaDevices对象
- 行为修正:修复各浏览器在SDP协商、ICE候选等环节的差异
怎么用?很简单:
<!-- 方式一:CDN引入 -->
<script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
<!-- 方式二:npm安装 -->
<!-- npm install webrtc-adapter -->
import adapter from 'webrtc-adapter';
// 引入后,直接使用标准API即可
const pc = new RTCPeerConnection();
// 不需要判断前缀,adapter会自动处理
引入adapter.js之后,你就不用再写那些繁琐的浏览器判断了。比如:
// 没有adapter.js时,你需要这样写
const RTCPeerConnection = window.RTCPeerConnection ||
window.webkitRTCPeerConnection ||
window.mozRTCPeerConnection;
// 有adapter.js后,直接写
const pc = new RTCPeerConnection();
我曾经在一个项目中,因为没有用adapter.js,导致Firefox上ICE连接一直失败。后来发现是Firefox的STUN服务器配置格式跟Chrome不一样。加上adapter.js后,一行代码都没改,问题就解决了。
重要提醒:adapter.js不是万能的。它只处理WebRTC核心API的差异,不处理媒体设备枚举(enumerateDevices)、屏幕共享等扩展API的差异。这些还是需要你自己做兼容处理。
4.4 知识体系总览
下面这张图,帮你理清浏览器兼容性的核心脉络:
4.5 实战建议
说了这么多,总结几条我个人的实战经验:
- 永远引入adapter.js。不管你的目标浏览器是什么,加上它只有好处没有坏处。文件才几十KB,不值得省。
- 使用新版getUserMedia API。不要再用回调写法了。Promise写法更清晰,也更容易做错误处理。
- 测试要覆盖主流浏览器。Chrome、Firefox、Safari至少各测一遍。我见过太多「Chrome上完美,Safari上崩了」的案例。
- 注意移动端。Android上的Chrome和iOS上的Safari,行为跟桌面端不完全一样。特别是权限弹窗的交互,差异很大。
- 做好降级提示。如果浏览器不支持WebRTC,不要直接白屏。给用户一个友好的提示,告诉他怎么升级。
一个小技巧:可以用navigator.mediaDevices.enumerateDevices()来检测设备是否可用。如果返回空数组,说明浏览器虽然支持API,但没有摄像头或麦克风。这种情况在PC上很少见,但在平板上偶尔会遇到。
好了,浏览器兼容性这块就聊到这儿。记住一句话:别跟浏览器较劲,用adapter.js就对了。
公众号:蓝海资料掘金营,微信deep3321