Tauri应用视频无法播放?macOS上遇到unsupported URL 的终极解决方案
在苹果电脑上用 Tauri 开发本地应用时,如果你试图通过 <video>
播放本地视频,很可能会遇到以下报错:
[Error] Failed to load resource: unsupported URL
或者视频黑屏、音频正常、无明显错误提示。
❗常见错误路径
convertFileSrc
→ ❌ WebKit 不支持 Range 请求fetch → blob
→ ❌ 触发 CORS,资源被拦截- 修改 CSP → ❌ 无法解决底层协议问题
🧠 问题根源
- WebKit 限制:macOS 下的 Safari 引擎不支持
asset://
协议播放<video>
,但能显示图片等静态资源。 - Range 请求失败:视频默认发起 Range 请求(如
bytes=102400-
),asset://
无法返回分段内容。 - CORS 限制:
fetch("asset://...")
被视为跨域,无法设置 Access-Control-Allow-Origin。 - 协议未注册:
stream://
协议未在 Rust 注册 handler 时会报错或静默失败。 - 渲染异常:即使加载成功,有时视频黑屏,可能是 CSS 或编解码兼容性问题。
🧪 重现示例
fetch("asset://video.mp4")
.then(res => res.blob())
.then(blob => video.src = URL.createObjectURL(blob));
结果:
[Error] Failed to load resource: unsupported URL
WebKit 不支持 asset:// 是因为:
- asset:// 是 Tauri 内置的只读协议,它底层用的是 AppHandle::fs_scope();
- 这个协议的行为是固定的,你无法控制它的响应方式;
- 它不支持 Range 请求;
- 它没有标准的 MIME negotiation;
- 它不能添加正确的 CORS header;
- WebKit 对不认识的协议直接判定为 unsupported URL,尤其在 这种有强要求的组件中。
✅正确做法:自定义 stream:// 协议
✅ WebKit 支持 stream:// 是因为:
- stream:// 是由 你自己在 Tauri 中注册的自定义协议;
- 你可以在注册的时候告诉 WebKit 如何处理这个协议,包括:
- 设置 MIME 类型(告诉浏览器“这是视频”);
- 支持 Range 请求(用于 分段加载);
- 支持 跨源访问(CORS);
- 甚至你可以添加自定义 header、缓存等逻辑。
👉 本质上,stream:// 是你控制的,所以你可以让它“长得像”一个浏览器喜欢的协议。
⸻
✅ 步骤 1:在 Rust 后端注册协议处理器
tauri::Builder::default()
.register_uri_scheme_protocol("stream", |request| {
// 读取视频文件
// 处理 Range 请求
// 返回正确的 Content-Type(例如 video/mp4)和响应体
})
✅ 步骤 2:前端使用 stream 协议加载视频
<video controls src="stream://video.mp4" />
🧰 为什么图片/字体能加载但视频失败?
- 图片 / 字体 / 小脚本,体积小,一次加载(无需 Range)。
- 视频 / 音频,体积大,分段加载(需要 Range)、缓存、解码。
元素在加载时默认发起 Range 请求,例如:
Range: bytes=102400-
而 asset:// 没法返回部分内容,只能一次性返回整个文件,因此无法支持断点播放或拖动。
🧠 Tauri 应用运行原理(简要说明)
🧩 前端部分:
- 你写的 React/Vue 页面,会被打包为静态资源
- 使用 asset:// 协议在 WebView 中加载
🔧 后端部分:
- Rust 提供本地访问能力(文件、FFmpeg、数据库等)
- 可注册协议(如 stream://)模拟 HTTP 服务
🎞️ 渲染部分:
- macOS → WebKit (Safari 内核)
- Windows → WebView2 (Chromium)
⸻
🙋♂️ 常见问题答疑(FAQ)
❓为什么不能直接用 file:/// 或 asset://?
因为这些协议: • 不支持 Range 请求 • 无法处理 MIME negotiation • fetch 触发 CORS 被浏览器拦截
⸻
❓视频播放黑屏但有声音,可能是哪里的问题?
可能原因: • CSS:video 被遮挡或透明 • 编码格式:不支持某种视频流(如 H.264 10bit) • WebKit 渲染 Bug:只能播放音频轨
✅ 总结
💡 如果你在 Tauri 中需要播放本地大文件(视频/音频等),你必须实现一个 支持 Range 请求的自定义协议 handler。只有这样才能绕过 WebKit 的限制,避免 CORS 和 MIME 问题。