You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决MediaRecorder API在移动端浏览器无法存储录制流的问题

移动端MediaRecorder录屏失效常见原因及修复方案

核心问题排查点

  • getDisplayMedia兼容性限制
    iOS Safari仅14及以上版本支持屏幕共享,安卓端大部分第三方浏览器(微信内置、QQ浏览器等)默认禁用getDisplayMedia权限,且iOS端getDisplayMedia不支持audio: true参数,传入会直接抛出异常。
  • MimeType不匹配
    你代码中硬指定Blob类型为video/mp4,但绝大多数安卓移动浏览器默认支持的录制格式为video/webm,只有高版本Safari支持mp4格式录制,MediaRecorder初始化时如果传入不支持的格式会直接静默失败。
  • AudioContext被自动暂停
    移动端浏览器存在音频自动播放限制,非用户交互(点击/触摸)触发的AudioContext会默认处于suspended状态,你当前在componentDidMount生命周期中创建AudioContext,没有用户触发的前提下无法正常输出音频流,导致合并后的MediaStream异常。
  • ondataavailable未触发
    桌面端MediaRecorder不传时间分片参数也会自动触发ondataavailable,但移动端必须显式传入timeslice参数才会按周期返回录制分片,你代码中未传该参数,只有调用mediaRecorder.stop()时才会返回一次数据,不主动停止的话永远拿不到录制内容。
  • 逻辑漏洞问题
    你当前在每次ondataavailable触发时就调用download生成Blob,会导致每次生成的Blob仅包含当前分片,且频繁生成大体积Blob会触发移动端内存限制导致进程崩溃。另外如果本地/远端流没有音频轨,mergeAudioStreams中调用undefined的connect方法会直接报错。

修复代码示例

// 提前检测支持的MimeType
const getSupportedMimeType = () => {
  const types = [
    'video/webm;codecs=vp8,opus',
    'video/mp4;codecs=h264,aac',
    'video/webm',
    'video/mp4'
  ]
  return types.find(type => MediaRecorder.isTypeSupported(type))
}

// 录制逻辑必须绑定到用户点击/触摸事件触发,不要放在componentDidMount自动执行
handleStartRecord = async () => {
  // 先恢复AudioContext,避免被暂停
  const audioCtx = new (window.AudioContext || window.webkitAudioContext)()
  if (audioCtx.state === 'suspended') {
    await audioCtx.resume()
  }

  // 移动端不要给getDisplayMedia传audio: true
  recordingStream =  await navigator.mediaDevices.getDisplayMedia({
    video: true,
    audio: /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ? false : true,
  });

  const mergedAudio = await this.mergeAudioStreams(audioCtx);
  const tracks = [
    ...recordingStream.getVideoTracks(),
    ...mergedAudio,
  ];

  captureStream = new MediaStream(tracks);
  // 传入支持的编码格式
  const options = { mimeType: getSupportedMimeType() }
  mediaRecorder = new MediaRecorder(captureStream, options);
  mediaRecorder.ondataavailable = this.handleDataAvailable;
  // 录制结束时再生成文件
  mediaRecorder.onstop = this.download;
  // 传入1000ms分片,保证每1秒返回一次数据
  mediaRecorder.start(1000);
}

handleDataAvailable = async event => {
  if (event.data.size > 0) {
    recordedChunks.push(event.data);
  }
};

download = async () => {
  const mimeType = getSupportedMimeType()
  var blob = new Blob(recordedChunks, {
    type: mimeType,
  });
  // 调用API存储视频
}

mergeAudioStreams = async (ctx) => {
  const dest = ctx.createMediaStreamDestination();
  let localSource, remoteSource;

  const localGain = ctx.createGain();
  const remoteGain = ctx.createGain();
  localGain.gain.value = 0.7;
  remoteGain.gain.value = 0.7;

  if (this.state.localStream?.getAudioTracks().length > 0) {
    localSource = ctx.createMediaStreamSource(this.state.localStream);
    localSource.connect(localGain).connect(dest);
  }

  if (this.state.selectedVideo?.stream?.getAudioTracks().length > 0) {
    remoteSource = ctx.createMediaStreamSource(
      this.state.selectedVideo.stream
    );
    remoteSource.connect(remoteGain).connect(dest);
  }

  return dest.stream.getAudioTracks();
};

额外注意事项

  • iOS端页面切后台后录制会自动终止,需要引导用户录制期间保持页面在前台
  • 部分安卓浏览器不支持多音轨合并,测试时需要单独验证音视频是否正常同步
  • 录制前需要提前申请屏幕录制、麦克风、摄像头权限,避免权限被拒导致流程中断

内容的提问来源于stack exchange,提问作者Jayna Tanawala

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 17:57:02