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

Mac端Safari 15.5中navigator.permissions为undefined的相机权限问题

Safari 15.5 摄像头权限检测兼容方案

问题根因

Mac端Safari 15.5存在原生实现缺陷:该版本的Permissions API未完整支持摄像头权限查询能力,未触发过媒体设备申请时navigator.permissions会直接返回undefined;即使用户已经完成摄像头授权,也无法通过permissions.query({ name: 'camera' })获取正确状态。该bug仅存在于桌面端Safari 15.x系列版本,移动端同版本Safari、更高/更低版本的桌面Safari均无此问题。

实现逻辑

不要单独依赖Permissions API做摄像头权限判断,结合navigator.mediaDevices.getUserMedia做降级探测是该场景下唯一可靠的方案:

  • 对非Safari 15桌面端的环境,优先使用原有Permissions API查询逻辑,性能更好也不会触发权限弹窗
  • 对命中问题版本、或Permissions API查询失败/不存在的场景,用getUserMedia做轻量探测,根据调用结果映射权限状态
  • 探测完成后立刻关闭拿到的媒体流轨道,避免长期占用摄像头硬件

兼容代码

// 判断是否为存在缺陷的Mac端Safari 15版本
const isMacSafari15 = () => {
  const ua = navigator.userAgent;
  const isMac = ua.includes('Mac OS X');
  const isSafari = ua.includes('Safari') && !ua.includes('Chrome') && !ua.includes('Firefox');
  const versionMatch = ua.match(/Version\/(\d+)\.(\d+)/);
  if (!isMac || !isSafari || !versionMatch) return false;
  const majorVersion = parseInt(versionMatch[1], 10);
  return majorVersion === 15;
};

// 降级探测方法:通过getUserMedia判断权限状态
const detectCameraPermissionByGetUserMedia = (resolve: (state: CameraPermissionState) => void) => {
  if (!navigator.mediaDevices?.getUserMedia) {
    resolve(CameraPermissionState.UNKNOWN);
    return;
  }
  navigator.mediaDevices.getUserMedia({ video: true })
    .then((stream) => {
      // 成功拿到流说明已授权,立刻释放摄像头占用
      stream.getTracks().forEach(track => track.stop());
      resolve(CameraPermissionState.GRANTED);
    })
    .catch((err) => {
      // 根据错误类型映射权限状态
      if (err?.name === 'NotAllowedError' || err?.name === 'PermissionDeniedError') {
        resolve(CameraPermissionState.DENIED);
      } else if (err?.name === 'NotFoundError') {
        // 设备未搭载摄像头,返回未知状态
        resolve(CameraPermissionState.UNKNOWN);
      } else {
        resolve(CameraPermissionState.PROMPT);
      }
    });
};

public getCameraPermission = (): Promise<CameraPermissionState> => new Promise((resolve) => {
  // 非问题版本优先走原有Permissions API逻辑
  if (!isMacSafari15() && (navigator as any).permissions) {
    (navigator as any).permissions.query({ name: 'camera' })
      .then(({ state }: { state: CameraPermissionState }) => resolve(state))
      .catch(() => {
        // API查询失败走降级探测
        detectCameraPermissionByGetUserMedia(resolve);
      });
    return;
  }
  // 问题版本或API不可用时走降级探测
  detectCameraPermissionByGetUserMedia(resolve);
});

注意事项

  • 降级探测的getUserMedia调用必须放在用户点击、触摸等主动交互事件的执行链路里,否则Safari会直接拦截请求,既不会弹出权限提示,也会返回错误的权限结果
  • 如果用户已经完成授权,getUserMedia调用不会重复弹出权限提示,用户无感知,不会影响使用体验
  • 不要尝试通过本地缓存记录权限状态,用户随时可能在浏览器设置里修改站点权限,缓存结果不可靠
  • 如果不想写UA判断逻辑,也可以全量使用getUserMedia探测逻辑,该逻辑在所有支持摄像头调用的现代浏览器上都能正常运行,不会和原有Permissions API逻辑冲突

内容的提问来源于stack exchange,提问作者Ahmet B. Simsek

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 19:48:30