Android Chrome及原生WebView中WebRTC onicecandidate事件未触发问题排查
根据你描述的情况,代码在桌面浏览器、Android Firefox以及旧版本Chrome(84/87)中正常运行,但在Chrome 94.0.4606.85及对应的原生WebView里完全无法触发onicecandidate事件,降级Chrome到87后恢复正常,这大概率是Chrome 94+版本中WebRTC模块的行为变更或特定Bug导致的。结合你的代码和测试结果,我整理了几个可能的解决方向:
一、排查iceCandidatePoolSize配置的影响
你的代码中设置了iceCandidatePoolSize: 10,这个参数用于预收集ICE候选,但在Chrome 94+版本中,该配置的逻辑可能发生了变化,导致预收集逻辑失效或阻塞了后续的ICE收集流程。
尝试调整方案:
移除iceCandidatePoolSize配置,或者将其设置为默认值0,让ICE候选在需要时才主动开始收集:
const servers = { iceServers: [ { urls: ['stun:stun1.l.google.com:19302', 'stun:stun2.l.google.com:19302'], }, ], // 移除或注释掉这一行,或设置为0 // iceCandidatePoolSize: 10, };
二、调整DataChannel的创建时机
你当前在createOffer之前就创建了DataChannel,虽然这符合WebRTC标准,但新版本Chrome可能对这个流程的处理逻辑有变更。尝试将DataChannel的创建延迟到setLocalDescription完成之后:
修改后的connectPeers函数片段:
export async function connectPeers() { // ... 其他代码保持不变 ... var offerDescription = await localConnection.createOffer(); await localConnection.setLocalDescription(offerDescription); // 延迟创建DataChannel到setLocalDescription之后 dataConstraint = null; sendChannel = localConnection.createDataChannel("sendChannel", dataConstraint); sendChannel.onopen = handleSendChannelStatusChange; sendChannel.onclose = handleSendChannelStatusChange; const offer = { sdp: offerDescription.sdp, type: offerDescription.type, }; await calldoc.set({offer}); // ... 后续代码保持不变 ... }
同时注意:作为WebRTC连接的接收方,不需要主动创建DataChannel(应该通过ondatachannel事件接收对方创建的通道),你当前在listenForConnection函数中主动创建DataChannel的代码可能导致冲突,建议移除:
async function listenForConnection() { calldoc = firebase.firestore().collection('calls').doc(answerInput.value); answerCandidates = calldoc.collection('answerCandidates'); localConnection.onicecandidate = event => { event.candidate && answerCandidates.add(event.candidate.toJSON()); }; // 移除接收方主动创建DataChannel的代码 // sendChannel = localConnection.createDataChannel("receiveChannel"); // sendChannel.onopen = handleSendChannelStatusChange; // sendChannel.onclose = handleSendChannelStatusChange; localConnection.ondatachannel = receiveChannelCallback; // ... 后续代码保持不变 ... }
三、显式触发ICE收集
如果上述调整无效,可以尝试在setLocalDescription之后显式调用restartIce()来强制触发ICE候选收集:
await localConnection.setLocalDescription(offerDescription); // 显式触发ICE收集流程 localConnection.restartIce();
四、WebView特定配置检查
对于原生WebView,除了版本问题,还需要确保WebView的配置启用了WebRTC相关功能:
- 确保启用JavaScript:
webSettings.setJavaScriptEnabled(true) - 允许媒体访问(即使是DataChannel,部分版本可能依赖此配置):
webSettings.setMediaPlaybackRequiresUserGesture(false) - 检查是否开启了WebView的隐私沙箱或其他限制功能,尝试临时关闭相关限制测试
五、调试建议
可以使用Chrome开发者工具的WebRTC内部页面(在Chrome地址栏输入chrome://webrtc-internals/),查看ICE收集的状态日志,是否有错误或未触发收集的具体原因,这能帮助快速定位问题。
内容的提问来源于stack exchange,提问作者Jonathan




