基于PeerJS的WebRTC音视频App在Android 11上无音视频问题求助
适配Android 11及以上版本PeerJS音视频通话问题解决方案
安卓原生端配置修复
- 针对SDK 31及以上版本,需要在
AndroidManifest.xml中新增WebRTC相关权限声明:
<!-- 原有基础权限 --> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" /> <!-- SDK31+新增必要权限 --> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /> <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
- 相机、麦克风权限必须在加载WebView之前动态申请,不能仅在清单文件声明,也不要等到JS调用媒体接口时再申请,否则会出现权限获取成功但媒体流无法传输的问题。
- 如果你的PeerJS服务使用HTTP而非HTTPS,需要在
AndroidManifest.xml的<application>标签下添加android:usesCleartextTraffic="true",SDK31+默认禁止明文流量,会导致媒体流传输被拦截。
WebView配置调整
WebView初始化阶段需要开启WebRTC相关配置:
WebSettings webSettings = webView.getSettings(); webSettings.setJavaScriptEnabled(true); webSettings.setAllowFileAccess(true); webSettings.setAllowContentAccess(true); // 允许媒体自动播放,无需用户手势触发 webSettings.setMediaPlaybackRequiresUserGesture(false); // 授权WebRTC所需权限 webView.setWebChromeClient(new WebChromeClient() { @Override public void onPermissionRequest(PermissionRequest request) { // 提前完成原生权限申请后,此处直接授权即可,无需弹出系统授权框 request.grant(request.getResources()); } }); // 禁用缓存避免跨版本兼容问题 webSettings.setCacheMode(WebSettings.LOAD_NO_CACHE); // 开启DOM存储 webSettings.setDomStorageEnabled(true); // Android 11及以上专属兼容配置 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { webSettings.setAllowFileAccessFromFileURLs(true); webSettings.setAllowUniversalAccessFromFileURLs(true); }
JS代码适配修改
原有代码使用的废弃API和非标准字段是高版本内核兼容问题的核心诱因,修改后代码如下:
let localVideo = document.getElementById("local-video") let remoteVideo = document.getElementById("remote-video") let peer var enableVideo async function init(userId, isVideoCall) { enableVideo = isVideoCall === "true" peer = new Peer(userId, { host: '<My GCP server IP>', port: 9000, key: "myKey", path: '/calls', config: { // iceServers标准字段为urls,原有的url字段为非标准写法,高版本Chromium会忽略 'iceServers': [ { urls: 'stun:stun.ekiga.net' }, { urls: 'stun:stun.schlund.de' }, { urls: 'stun:stun.voipbuster.com' }, { urls: 'stun:stun.voipstunt.com' }, { urls: 'stun:stun.xten.com' }, { urls: 'stun:stun.l.google.com:19302' }, { urls: 'stun:stun1.l.google.com:19302' }, { urls: 'stun:stun2.l.google.com:19302' }, { urls: 'stun:stun3.l.google.com:19302' }, { urls: 'stun:stun4.l.google.com:19302' }, { urls: 'turn:numb.viagenie.ca', username: "<myUsername>", credential: '<myPassword>' } ] } }) peer.on('open', () => { Android.onPeerConnected() }) peer.on('error', (err) => { console.log('Peer连接错误:', err) Android.onError() }) listen() } let localStream; function listen() { peer.on('call', async (call) => { try { // 替换废弃的navigator.getUserMedia为标准API const stream = await navigator.mediaDevices.getUserMedia({ audio: true, video: enableVideo }) localVideo.srcObject = stream localStream = stream call.answer(stream) call.on('stream', (remoteStream) => { Android.onCallConnected() remoteVideo.srcObject = remoteStream remoteVideo.className = "primary-video" localVideo.className = "secondary-video" }) call.on('error', (err) => { console.log('通话错误:', err) }) } catch (e) { console.log('媒体流获取失败:', e) } }) } async function startCall(otherUserId) { try { // 替换废弃的navigator.getUserMedia为标准API const stream = await navigator.mediaDevices.getUserMedia({ audio: true, video: enableVideo }) localVideo.srcObject = stream localStream = stream const call = peer.call(otherUserId, stream) call.on('stream', (remoteStream) => { Android.onCallConnected() remoteVideo.srcObject = remoteStream remoteVideo.className = "primary-video" localVideo.className = "secondary-video" }) call.on('error', (err) => { console.log('通话错误:', err) }) } catch (e) { console.log('媒体流获取失败:', e) } }
说明:ICE服务器配置使用非标准的
url字段会导致高版本Chromium内核无法正常完成ICE协商,是你网络收发速率为0的核心原因之一。
其他验证点
- 确认PeerJS服务端版本与客户端版本匹配,旧版本服务端不兼容高版本Chromium的WebRTC协议。
- 如果使用HTTPS部署,确认SSL证书为受信任的有效证书,自签名证书在SDK31+的WebView中会被拦截,导致媒体流传输失败。
- 部分三星设备的系统优化会限制后台应用的网络流量,需要为应用开启“允许后台使用流量”权限。
内容的提问来源于stack exchange,提问作者Sujith S Manjavana
相关产品推荐
相关产品推荐

