如果用户未在 Electron 中选择目录,Fileystem API showDirectoryPicker() 将永久损坏

问题描述 投票:0回答:1

此问题出现在最新版本的 Electron 中,但在 Electron 之外的 Chromium 中没有出现。

以下示例代码使用文件系统 API 的 showDirectoryPicker 方法在用户单击按钮时打开目录选择器:

async function handleClick() {
    try {
        dirHandle = await window.showDirectoryPicker({startIn: "downloads"});
    } catch (error) {
        console.log(error);
    }
}

但是以下情况会导致目录选择器永久损坏:

  • 用户已经在
    Downloads
    内部,所以认为他们不需要创建/选择子目录
  • 他们点击
    Open
    而没有做出明确的选择
  • 目录选择器“关闭”,未选择任何目录,并且
    dirHandle
    为空。
  • 用户点击按钮重试
  • showDirectoryPicker()
    的调用会抛出 AbortError
    NotAllowedError: Failed to execute 'showDirectoryPicker' on 'Window': File picker already active.

任何后续单击打开目录选择器都会失败,并出现相同的

NotAllowedError: Failed to execute 'showDirectoryPicker' on 'Window': File picker already active.
错误。

所以我的问题是:如何停用、重置、关闭、删除、解析等文件选择器,以便可以再次打开它。 我无法将

dirHandle
设置为空,因为它已经为空。 同样,
showDirectoryPicker()
返回的Promise已经解决了。

任何解决方案都将受到欢迎。 必须有一些明显的方法来解决这个问题,否则这将是文件系统 API 中的一个巨大错误。

或者,有什么方法可以让 showDirectoryPicker() 实际上选择起始目录(在本例中是

Downloads
)?

电子与铬

这似乎只发生在 Electron 中。 在普通 Chromium 中,不会出现此问题,因为它不是为用户提供

Open
选项,而是为他们提供
Select
选项,并且不允许他们 not 选择目录。

javascript electron progressive-web-apps create-directory native-file-system-api-js
1个回答
0
投票

事实证明这是一个特定于 Electron 的问题。 幸运的是,一位 Electron 工程师推出了一个修复程序,允许您捕获用户尝试选择受保护的系统目录的情况。 更好的是,Electron 实现现在允许开发人员选择为用户提供覆盖限制并指定这些目录之一的选项,例如

Desktop
Documents
Downloads
等。

该修复已记录在 Electron 文档中

简而言之,您只需要确保包含

dialog
顶部的
session
中的
electron
main.js

const { app, dialog, BrowserWindow, session } = require('electron')

然后将如下代码添加到您的

createWindow()
函数中:

session.defaultSession.on('file-system-access-restricted', async (e, details, callback) => {
    const { origin, path } = details
    const { response } = await dialog.showMessageBox({
        message: `Are you sure you want ${origin} to open restricted path ${path}?`,
        title: 'File System Access Restricted',
        buttons: ['Choose a different folder', 'Allow', 'Cancel'],
        cancelId: 2
    })

    if (response === 0) {
        callback('tryAgain')
    } else if (response === 1) {
        callback('allow')
    } else {
        callback('deny')
    }
})
© www.soinside.com 2019 - 2024. All rights reserved.