Electron实现文件复制到剪切板的方案
作者:smallzip
前言
electron的剪切板没有提供文件、音频、视频等等类型的支持。
技术调研
我们在mac、windows系统中,右键本地文件是支持复制的,并写入到剪切板的速度很快。
基于这个方向,我们查找到了如下方法:
window:使用powershell脚本命令,可以实现文件复制
`powershell -command "& {Set-Clipboard -Path '${filePath}'}"`
mac:使用osascript脚本指令,可以实现文件复制
`osascript -e 'set the clipboard to POSIX file "${filePath}"'`
注意点
powershell和asascript在两个平台支持复制文件、音频、视频等等,前提条件都是需要文件已经存在于本地。
所以,我们复制的内容必须先现在到本地,再进行复制到剪切板。
实现方案
渲染层提供preload
contextBridge.exposeInMainWorld("mainWindowAPI", { copyFile: (filePath:string) => ipcRenderer.invoke('copy-file', filePath) });
复制的实际,需要传递已经缓存到本地的文件路径;
主进程接收ipc
// 复制文件到剪切板 ipcMain.on("copy-file", (event: Electron.IpcMainEvent, filePath: string) => { // 检查filePath是否存在,不存在则退出 if(!filePath) { event.reply("copy-file", false); return; } // 处理base64 if (filePath.startsWith('data:')) { try { const image = Buffer.isBuffer(filePath) ? nativeImage.createFromBuffer(filePath) : nativeImage.createFromDataURL(url); clipboard.writeImage(image) Logger.log(`【copy-file】复制base64成功`) event.reply("copy-file", true); } catch (error) { Logger.log(`【copy-file】复制base64失败 ${error}`) event.reply("copy-file", false); } return } // 检查是否为本地路径,如果不是本地路径则退出 if(filePath.includes('file://')) { event.reply("copy-file", false); return; } // 执行复制操作 copyFile(filePath.replace("file:///", "")).then((res: boolean) => { event.reply("copy-file", res); }).catch(() => { event.reply("copy-file", false); }) });
1.检查filePath是否存在,不存在则退出
2.如果是base64图片,则使用electron的nativeImage转换成为PNG图片(或者jpg等,可以看官网)
3.检查是否为本地路径,如果不是本地路径则退出,因为复制到剪切板必须是本地文件,网络连接是不支持的
4.是本地连接,去除file:///头,只需要后面的文件路径,路径如下:/Users/自己设备的账户名/Library/Application Support/应用名称/Cache/test.dmg
检查不同平台
/** * 复制文件到剪贴板 * * @param localFileUrl 本地文件URL * @returns 复制结果,成功为true,失败为false */ export function copyFile(localFileUrl: string) { if (process.platform === 'darwin') { return copyFileForMac(localFileUrl); } else if (process.platform === 'win32') { return copyFileForWindows(localFileUrl) } }
mac系统复制到剪切板
/** * 将文件复制到Mac的剪贴板 * * @param localFileUrl 本地文件的URL路径 * @returns 返回一个Promise,成功时返回true,失败时返回错误消息 */ function copyFileForMac(localFileUrl: string) { return new Promise((resolve, reject) => { // 文件的路径 const filePath = path.resolve(localFileUrl); Logger.log(`【copyFileForMac】Copying file to clipboard: ${filePath}`) // 使用AppleScript将文件复制到剪贴板 const copyFileToClipboardScript = `osascript -e 'set the clipboard to POSIX file "${filePath}"'`; // 执行AppleScript try { // 检查文件是否存在本地 if (!fs.existsSync(filePath)) { reject(false) Logger.error(`【copyFileForMac】Error: File not found at path ${filePath}`); } exec(copyFileToClipboardScript, (error: { message: any; }, stdout: any, stderr: any) => { if (error) { reject(false) Logger.error(`【copyFileForMac】Error: ${error.message}`); return; } if (stderr) { reject(false) Logger.error(`【copyFileForMac】Error: ${stderr}`); return; } resolve(true) Logger.log('【copyFileForMac】文件已经被写入剪切板'); }); } catch (error) { Logger.error(`【copyFileForMac】Error: ${error}`); reject(false) } }); }
windows系统复制到剪切板
/** * 将文件复制到Windows系统的剪贴板 * * @param localFileUrl 文件路径 * @returns 返回一个Promise,如果成功复制到剪贴板,则resolve为true;如果失败,则reject为错误信息 */ function copyFileForWindows(localFileUrl: string) { return new Promise((resolve, reject) => { // 文件的路径 const filePath = path.resolve(localFileUrl); Logger.log(`【copyFileForWindows】Copying file to clipboard: ${filePath}`) // 使用powershell命令将文件复制到剪贴板 const copyFileToClipboardScript = `${powershellBin} -command "& {Set-Clipboard -Path '${filePath}'}"`; // 执行powershell命令 try { // 检查文件是否存在本地 if (!fs.existsSync(filePath)) { reject(false) Logger.error(`【copyFileForMac】Error: File not found at path ${filePath}`); } exec(copyFileToClipboardScript, (error: { message: any; }, stdout: any, stderr: any) => { if (error) { reject(error) Logger.error(`【copyFileForWindows】Error: ${error.message}`); return; } if (stderr) { reject(stderr) Logger.error(`【copyFileForWindows】Error: ${stderr}`); return; } resolve(true) Logger.log('【copyFileForWindows】文件已经被写入剪切板'); }); } catch (error) { reject(error) Logger.error(`【copyFileForWindows】Error: ${error}`); } }); }
总结
electron的clipboard剪切板只支持text、html、rtf、bookmark、writeImage
等,5种类型写入到剪切板,并不支持其他文件类型、如file、video、audio等等
const { clipboard } = require('electron') clipboard.write({ text: 'test', html: '<b>Hi</b>', rtf: '{\rtf1\utf8 text}', bookmark: 'a title' }) console.log(clipboard.readText()) // 'test' console.log(clipboard.readHTML()) // <meta charset='utf-8'><b>Hi</b> console.log(clipboard.readRTF()) // '{\rtf1\utf8 text}' console.log(clipboard.readBookmark()) // { title: 'a title', url: 'test' }
我们参考系统级别的复制体性,最终实现了的文件复制到剪切板功能。
能够实现的前提是,文件已经存储在用户本地设备。
补充
业务层面,如何将文件缓存到本地,则需要用到electron的WebRequest网络拦截功能,再业务层资源下拉的时候拦截对应的请求,并将资源缓存到我们指定的文件夹位置,后续复制的时候,则直接读取缓存的文件路径提供给 copy-file。
以上就是Electron实现文件复制到剪切板的方案的详细内容,更多关于Electron文件复制到剪切板的资料请关注脚本之家其它相关文章!