如何解决Electron应用安装在C盘没有权限更新的问题

electron 应用在增量更新时会从服务器下载更新包一般是 app.asar 或者 app.zip,然后解压更新包替换本地 app 文件夹。这里的服务器上下载文件如果是下载到 C 盘就会报错
Error: EPERM: operation not permitted


说明没有权限。
这里一般有两种方法解决:

  1. 提升权限,直接用管理员权限运行 electron 应用
  2. 不安装在 C 盘,直接避开这个问题(没有解决根本问题)

提升权限,用管理员权限运行

为了默认用管理员权限运行需要添加下配置

// electron-builder.json
"win":{
  // ...
  "requestedExecutionLevel": "requireAdministrator",
  // ...
}

配置用管理员权限运行后发现在运行时会出现授权弹窗
IMG_2897
只要点击是就可以正常运行,也能正常下载更新包到 C 盘。
运行后发现无法使用拖拽事件,这是因为 windows 规定:当拖放源与目标运行的安全级别(隔离级别)不一致时,是禁止拖放的。即,我们的 windows 资源管理器是以普通用户的身份运行的,而此时我们的应用程序是以管理员身份运行的,两个安全级别不一样,所以不能拖放了。
查询资料找了下解决办法都说不要用管理员权限运行,问题又回到了原点。

修改默认安装路径

在 electron-builder.json 中添加 nsis 脚本

"nsis":{
  // ...
  "inlcude":"./installer.nsh"
}

在当前目录下新增 installer.nsh 文件

/**
* 设置默认安装路径在D:\Program Files\electronApp
*/
!macro preInit
  SetRegView 64
  WriteRegExpandStr HKLM "${INSTALL_REGISTRY_KEY}" InstallLocation "D:\Program Files\electronApp"
  WriteRegExpandStr HkCU "${INSTALL_REGISTRY_KEY}" InstallLocation "D:\Program Files\electronApp"
  SetRegView 32
  WriteRegExpandStr HKLM "${INSTALL_REGISTRY_KEY}" InstallLocation "D:\Program Files\electronApp"
  WriteRegExpandStr HkCU "${INSTALL_REGISTRY_KEY}" InstallLocation "D:\Program Files\electronApp"
!macroend

采用这种办法可以暂时避免无法下载更新包的问题,但是如果用户强制安装在 C 盘还是会出现没有权限的问题,故还需要想办法彻底解决这个问题。

终极解决办法

没有权限就提升权限这个思路是没问题的,但是不应该在开始运行的时候就直接用管理员权限,其实只要在下载更新包到 C 盘的时候有管理员权限就行。想到 linux 系统在没有权限时用 sudo 提升权限,windows 应该也有类似的解决办法。直到查询资料发现sudo-prompt,这个库就是为了解决这个问题的。啊,真香。

为了在项目中使用我们需要改下思路,先将更新包下载到当前用户的主目录文件夹下,这采用 electron 提供的 app.getPath(“userData”)路径,因为下载到这个文件夹是无需权限的。下载完解压得到 app 文件夹后替换安装路径下正在运行的 app 文件夹(我的安装路径是 C:\Program Files\electronApp),此时需要管理员权限了

import sudo from "sudo-prompt";
// ...

// 安装在C盘需要User Account Control提升权限, 通过提升到管理员权限替换app文件夹
sudo.exec(
  `xcopy ${join(appPath, "app")} "${appFolderPath}" /y /e /i /q`, // 采用windows系统提供的xcopy命令替换文件夹
  {
    name: "gpdjy", //name must be alphanumeric only (spaces are allowed) and <= 70 characters
  },
  (err, stdout, stderr) => {
    if (err) {
      log.error("err", err);
      return;
    }
    log.info("stdout", stdout);
    log.info("stderr", stderr);
  }
);

我们发现在解压完准备替换的时候有权限提升弹窗,我们选择是就可以替换了。
替换完 app 文件夹然后重启 electronApp 就可以达到更新的目的了。这样重启后不是用管理员权限运行也就不影响拖拽事件了。

参考文章:

  1. Electron-builder NSIS 修改默认安装路径
  2. xcopy
  3. Electron 增量更新(三)