Electron自定义协议加载本地视频失败:渲染层黑屏求助
Electron自定义协议加载本地视频黑屏问题排查
问题说明
使用Electron开发简易视频展示应用,通过registerSchemesAsPrivileged定义appfile协议加载本地视频时,渲染层显示黑屏,开发者工具无内容输出。控制台未出现文件找不到的错误,但存在沙箱相关报错。
相关代码片段
main.ts
import path from 'path'; import { app, BrowserWindow, shell, ipcMain, protocol, net } from 'electron'; import { autoUpdater } from 'electron-updater'; import log from 'electron-log'; import MenuBuilder from './menu'; import { resolveHtmlPath } from './util'; import fs from 'fs' protocol.registerSchemesAsPrivileged([ { scheme: 'appfile', privileges: { standard: true, secure: true, supportFetchAPI: true, bypassCSP: true, }, }, ]); app.whenReady().then(() => { protocol.handle('appfile', (request) => { // Get the file path from the request url const filePath = request.url.replace('appfile://', ''); // Resolve the file path to the absolute file path //const absoluteFilePath = path.resolve(filePath); // Fetch the file console.log(filePath); return net.fetch(`file:///${filePath}`); }); });
App.tsx
import { MemoryRouter as Router, Routes, Route } from 'react-router-dom'; import icon from '../../assets/icon.svg'; import './App.css'; import { useState, useEffect } from 'react'; function Hello() { //const [videoSource, setVideoSource] = useState<string | null>(null); return ( <body> <video id="videoPlayer" width="100%" height="100%" autoPlay muted loop> <source src="appfile:///home/user/Desktop/project/videos/video1.mp4" /> </video> </body> ); } export default function App() { return ( <Router> <Routes> <Route path="/" element={<Hello />} /> </Routes> </Router> ); }
控制台输出
home/user/Desktop/project/videos/video1.mp4 [14091:0823/181240.250752:ERROR:CONSOLE(2)] "Electron sandboxed_renderer.bundle.js script failed to run", source: node:electron/js2c/sandbox_bundle (2) [14091:0823/181240.250873:ERROR:CONSOLE(2)] "TypeError: object null is not iterable (cannot read property Symbol(Symbol.iterator))", source: node:electron/js2c/sandbox_bundle (2)
排查建议
修复React组件结构问题:Hello组件直接返回
<body>标签不符合React规范,改为用<div>包裹内容,同时给<source>添加type="video/mp4"属性帮助识别视频格式:function Hello() { return ( <div> <video id="videoPlayer" width="100%" height="100%" autoPlay muted loop> <source src="appfile:///home/user/Desktop/project/videos/video1.mp4" type="video/mp4" /> </video> </div> ); }添加协议处理的错误捕获:给
protocol.handle添加异步错误捕获,确认文件读取是否存在未被捕获的异常:app.whenReady().then(() => { protocol.handle('appfile', async (request) => { const filePath = request.url.replace('appfile://', ''); console.log(filePath); try { const response = await net.fetch(`file:///${filePath}`); console.log('文件读取状态:', response.status); return response; } catch (err) { console.error('文件读取错误:', err); return new Response('文件未找到', { status: 404 }); } }); });检查渲染进程沙箱配置:控制台的沙箱报错可能导致协议无法正常工作,临时关闭BrowserWindow的沙箱功能测试(生产环境不推荐,仅用于排查):
// 在创建BrowserWindow的代码中添加 const mainWindow = new BrowserWindow({ webPreferences: { sandbox: false, // 其他原有配置 } });验证文件路径与权限:确保
/home/user/Desktop/project/videos/video1.mp4路径正确,且Electron进程拥有该文件的读取权限。可在main.ts中用fs.access验证:fs.access('/home/user/Desktop/project/videos/video1.mp4', fs.constants.R_OK, (err) => { if (err) console.error('文件无读取权限:', err); else console.log('文件可正常读取'); });
内容的提问来源于stack exchange,提问作者Michael
相关产品推荐
相关产品推荐

