electron 实现文件下载管理器
文件下载是我们开发中比较常见的业务需求,比如:导出 excel。
web 应用文件下载存在一些局限性,通常是让后端将响应的头信息改成 Content-Disposition: attachment; filename=xxx.pdf
,触发浏览器的下载行为。
在 electron 中的下载行为,都会触发 session 的 will-download 事件。在该事件里面可以获取到 downloadItem 对象,通过 downloadItem 对象实现一个简单的文件下载管理器:
1. 如何触发下载
由于 electron 是基于 chromium 实现的,通过调用 webContents 的 downloadURL 方法,相当于调用了 chromium 底层实现的下载,会忽略响应头信息,触发 will-download 事件。
// 触发下载
win.webContents.downloadURL(url)
// 监听 will-download
session.defaultSession.on('will-download', (event, item, webContents) => {})
2. 下载流程
3. 功能设计
实现一个简单的文件下载管理器包含以下功能:
- 设置保存路径
- 暂停/恢复和取消
- 下载进度
- 下载速度
- 下载完成
- 打开文件和打开文件所在位置
- 文件图标
- 下载记录
3.1 设置保存路径
如果没有设置保存路径,electron 会自动弹出系统的保存对话框。不想使用系统的保存对话框,可以使用 setSavePath 方法,当有重名文件时,会直接覆盖下载。
item.setSavePath(path)
为了更好的用户体验,可以让用户自己选择保存位置操作。当点击位置输入框时,渲染进程通过 ipc 与主进程通信,打开系统文件选择对话框。
主进程实现代码:
/**
* 打开文件选择框
* @param oldPath - 上一次打开的路径
*/
const openFileDialog = async (oldPath: string = app.getPath('downloads')) => {
if (!win) return oldPath
const { canceled, filePaths } = await dialog.showOpenDialog(win, {
title: '选择保存位置',
properties: ['openDirectory', 'createDirectory'],
defaultPath: oldPath,
})
return !canceled ? filePaths[0] : oldPath
}
ipcMain.handle('openFileDialog', (event, oldPath?: string) => openFileDialog(oldPath))
渲染进程代码:
const path = await ipcRenderer.invoke('openFileDialog', 'PATH')
3.2 暂停/恢复和取消
拿到 downloadItem 后,暂停、恢复和取消分别调用 pause
、resume
和 cancel
方法。当我们要删除列表中正在下载的项,需要先调用 cancel 方法取消下载。
3.3 下载进度
在 DownloadItem 中监听 updated 事件,可以实时获取到已下载的字节数据,来计算下载进度和每秒下载的速度。
// 计算下载进度
const progress = item.getReceivedBytes() / item.getTotalBytes()
在下载的时候,想在 Mac 系统的程序坞和 Windows 系统的任务栏展示下载信息,比如:
- 下载数:通过 app 的 badgeCount 属性设置,当为 0 时,不会显示。也可以通过 dock 的 setBadge 方法设置,该方法支持的是字符串,如果不要显示,需要设置为 ''。
- 下载进度:通过窗口的 setProgressBar 方法设置。
由于 Mac 和 Windows 系统差异,下载数仅在 Mac 系统中生效。加上 process.platform === 'darwin' 条件,避免在非 Mac、Linux 系统下出现异常错误。
下载进度(Windows 系统任务栏、Mac 系统程序坞)显示效果:
// mac 程序坞显示下载数:
// 方式一
app.badgeCount = 1
// 方式二
app.dock.setBadge('1')
// mac 程序坞、windows 任务栏显示进度
win.setProgressBar(progress)
3.4 下载速度
由于 downloadItem 没有直接为我们提供方法或属性获取下载速度,需要自己实现。
思路:在 updated 事件里通过 getReceivedBytes 方法拿到本次下载的字节数据减去上一次下载的字节数据。
// 记录上一次下载的字节数据
let prevReceivedBytes = 0
item.on('updated', (e, state) => {
const receivedBytes = item.getReceivedBytes()
// 计算每秒下载的速度
downloadItem.speed = receivedBytes - prevReceivedBytes
prevReceivedBytes = receivedBytes
})
需要注意的是,updated 事件执行的时间约 500ms 一次。
3.5 下载完成
当一个文件下载完成、中断或者被取消,需要通知渲染进程修改状态,通过监听 downloadItem 的 done 事件。
item.on('done', (e, state) => {
downloadItem.state = state
downloadItem.receivedBytes = item.getReceivedBytes()
downloadItem.lastModifiedTime = item.getLastModifiedTime()
// 通知渲染进程,更新下载状态
webContents.send('downloadItemDone', downloadItem)
})
3.6 打开文件和打开文件所在位置
使用 electron 的 shell 模块来实现打开文件(openPath)和打开文件所在位置(showItemInFolder)。
由于 openPath 方法支持返回值
Promise<string>
,当不支持打开的文件,系统会有相应的提示,而 showItemInFolder 方法返回值是void
。如果需要更好的用户体验,可使用 nodejs 的 fs 模块,先检查文件是否存在。
import fs from 'fs'
// 打开文件
const openFile = (path: string): boolean => {
if (!fs.existsSync(path)) return false
shell.openPath(path)
return true
}
// 打开文件所在位置
const openFileInFolder = (path: string): boolean => {
if (!fs.existsSync(path)) return false
shell.showItemInFolder(path)
return true
}
3.7 文件图标
很方便的是使用 app 模块的 getFileIcon 方法来获取系统关联的文件图标,返回的是 Promise<NativeImage>
类型,我们可以用 toDataURL 方法转换成 base64,不需要我们去处理不同文件类型显示不同的图标。
const getFileIcon = async (path: string) => {
const iconDefault = './icon_default.png'
if (!path) Promise.resolve(iconDefault)
const icon = await app.getFileIcon(path, {
size: 'normal'
})
return icon.toDataURL()
}
3.8 下载记录
随着下载的历史数据越来越多,使用 electron-store 将下载记录保存在本地。
其他
项目的地址:
https://github.com/tal-tech/electron-playground
如果想看更完整的文档,请参考下面文档
Electron-Playground 官方文档
electron 实现文件下载管理器的更多相关文章
- Electron为文件浏览器创建图标(三)
在前面的文章中,请看之前文章,我们已经完成了使用 electron做文件浏览器这么一个应用,现在我们需要为应用创建图标操作.为应用创建图标以后,我们就可以从计算机中与其他应用区分开来,如果我们自己会做 ...
- MCDownloadManager ios文件下载管理器
我们用AFNetworking小试牛刀,写一个简单的下载器来演示功能. 前言 为什么AFNetworking能够成为顶级框架?我们究竟该如何领悟它的精髓所在?这都是很难的问题.安全,高效,流畅,这3个 ...
- 【Electron Playground 系列】文件下载篇
作者:long.woo 文件下载是我们开发中比较常见的业务需求,比如:导出 excel. web 应用文件下载存在一些局限性,通常是让后端将响应的头信息改成 Content-Disposition: ...
- 配置electron
配置语句: git clone https://github.com/electron/electron-quick-start 文件夹名字 打开该文件(我用的webstorm)
- Electron一学习资源收集和练习demo
1.近日为了做项目查资料学习electron,简直头都要炸了,就官方的electron-quick-start的例子进行了基本的练习之后,不断的查资料终于发现一些有用的demo来看源代码学习,一遍看代 ...
- electron 安装使用
1.安装 node.js 链接:http://pan.baidu.com/s/1o7W7BIy 密码:y6od 一路next 我安装在F:\Program Files\node.js下 2.检查nod ...
- 从零开始用electron整个跨平台桌面应用---基础配置篇
1.安装node.npm node以及npm都需要是最新版本(版本过低有坑) 2.安装淘宝镜像cnpm(建议,下载较快) npm install -g cnpm --registry=https:// ...
- Electron入门Demo之桌面应用计算器笔记(二)
码文不易啊,转载请带上本文链接呀,感谢感谢 https://www.cnblogs.com/echoyya/p/14307996.html 在之前总结了一篇自学笔记,通过之前学习到的方法和知识,完成了 ...
- electron 起步
electron 起步 为什么要学 Electron,因为公司需要调试 electron 的应用. Electron 是 node 和 chromium 的结合体,可以使用 JavaScript,HT ...
随机推荐
- VUE第一个项目怎么读懂
VUE介绍 VUE是前端开发框架. 原始的前端开发需要工程师写html.写css.写javascript(js).js是脚本语言,浏览器可以运行js来执行一些js支持的动作,例如点击反馈,下拉菜单.操 ...
- Error: Module did not self-register报错解决
最近在做node升级过程中发现拉起一个引用到底层c++ addon动态库时,报如下错误 [root@Test dynamiclibs]# node test-all.js module.js:664 ...
- golang拾遗:指针和接口
这是本系列的第一篇文章,golang拾遗主要是用来记录一些遗忘了的.平时从没注意过的golang相关知识.想做本系列的契机其实是因为疫情闲着在家无聊,网上冲浪的时候发现了zhuihu上的go语言爱好者 ...
- CMD/ENTROYPOINT区别
CMD/ENTROYPOINT区别 相同点:都是指定一个容器:启动时要运行的命令 不同点(重点): CMD: dockerfile中可以有多个CMD指令,但是只有最后一个生效,CMD会被docker ...
- Docker学习:(一)初识Docker
Docker(容器虚拟化技术)要点(秒级启动) Docker的WWH公式学习 What[是什么]. Why[为什么要用它]. How[怎么用] 1.Docker简介 (1)问题:为什么会有docker ...
- day04 Pyhton学习
一.上节课内容回顾 字符串 由','','''',""'"括起来的内容是字符串 字符:单一文字符号 字符串:把字符连成串(有顺序的) 索引和切片 s[start: end ...
- es7.8启动报错 说是主节点没找到
p.p1 { margin: 0; font: 11px Menlo; color: rgba(0, 0, 0, 1); background-color: rgba(255, 255, 255, 1 ...
- 第六章 IP基本原理
一.引入 1.IP是网络层协议,也是当今应用最广泛的网络协议之一 2.IP协议规定了数据的封装方式,网络节点的标识方法,用于网络上数据的端到端的传递. 二.IP协议概述 1.IP及相关协议 2.IP的 ...
- 【机器学习 Azure Machine Learning】Azure Machine Learning 访问SQL Server 无法写入问题 (使用微软Python AML Core SDK)
问题情形 使用Python SDK在连接到数据库后,连接数据库获取数据成功,但是在Pandas中用 to_sql 反写会数据库时候报错.错误信息为:ProgrammingError: ('42000' ...
- 微信小程序-基于高德地图API实现天气组件(动态效果)
微信小程序-基于高德地图API实现天气组件(动态效果) 在社区翻腾了许久,没有找到合适的天气插件.迫不得已,只好借鉴互联网上的web项目,手动迁移到小程序中使用.现在分享到互联网社区中,帮助后续有 ...