Electron-修改默认的安装路径

5,396 阅读3分钟

背景

electron + electron-builder,使用的是nsis生成安装包;

需要修改安装界面中的默认的安装目录;

解决办法

electron-build文档中给出的相关方案如下

www.electron.build/configurati… image.png

在yml中添加include属性指定自定义的nsh文件如下

#installer.nsh 

!macro preInit
    SetRegView 64 
    WriteRegExpandStr HKLM "${INSTALL_REGISTRY_KEY}" InstallLocation "C:\MyApp"
    WriteRegExpandStr HKCU "${INSTALL_REGISTRY_KEY}" InstallLocation "C:\MyApp"
    SetRegView 32
    WriteRegExpandStr HKLM "${INSTALL_REGISTRY_KEY}" InstallLocation "C:\MyApp"
    WriteRegExpandStr HKCU "${INSTALL_REGISTRY_KEY}" InstallLocation "C:\MyApp"
!macroend

上面代码的作用为在安装程序初始化之前,修改软件的注册表数据“InstallLocation”;

成功修改后,发现执行安装程序后,默认的安装路径为修改后的了;

但是这样修改会出现,由于注册表数据修改,如果是重新安装/更新,旧包没法进行正确的卸载;

image.png

看了下electron-builder中nsis相关的源码

github.com/electron-us…

其中官方提供的修改默认的安装路径原理为:

在源码的onInit生命周期会判断是否存在preInit的宏,存在的话就会调用;

然后在初始化$INSTDIR(默认安装路径)的时候,会先判断注册表中是否存在,如果存在则将注册表中的InstallLocation赋值到$INSTDIR中;

再看了下,发现源码中还提供了customInit的宏,就是初始化结束的时候调用,而上述中的从注册表获取数据赋值到$INSTDIR,是在preInitcustomInit之间的;

那么,如果可以在customInit宏的时候再次修改$INSTDIR,就可以达到修改默认路径,而且暂时不修改注册表数据的效果(使得旧包可以正常卸载)

# installer.nsi(electron-builder的nsis相关源码片段)

Function .onInit
    !ifmacrodef preInit 
        !insertmacro preInit // init 前调用 
    !endif 
    
    # ...
    
    !insertmacro initMultiUser // 其中的逻辑包括从注册表获取赋值到 $INSTDIR
    
    !ifmacrodef customInit 
        !insertmacro customInit // init 后调用 
   !endif
   
   # ...
FunctionEnd

因此可以这么修改默认的安装路径

#installer.nsh

!macro customInit
    # 修改默认安装路径
    StrCpy $INSTDIR "$LocalAppData\Programs\${APP_FILENAME}"
!macroend

在项目的yml配置中引入include: installer.nsh即可保证修改了默认的安装路径,但是旧包也能被正确删除;

不过从源码可以看出,如果使用electron-update走的是更新逻辑的话,会直接跳过选择目录的步骤;

如果我们修改了安装路径,就意味着用户更新后,软件都会静默的重新安装到我们设定好的位置(而且没有通知用户,似乎有点流氓软件的感觉 =。=);

1)如果不考虑删除旧包,还是乖乖使用官方建议的preInit修改方法;

2)如果需要删除旧包而且修改默认的安装路径,则可以使用customInit的方法;

题外话 - 在安装完后主动卸载旧包

如果安装包允许用户选择(为计算机安装、为个人安装);

当用户两次安装选择不一样的时候,会出现计算出现两个应用,由于两个安装场景在注册表的位置不一样,因此这是两个软件,并不冲突;

若需求是希望为保证安装的时候计算机只允许有一个软件,则需要在安装过程中将其他环境的程序给卸载了;

下面是每次安装结束检查卸载用户目录是否有安装,有则卸载的相关逻辑

Var OLD_PATH
Var UNINSTALL_PROG

# 宏 初始化前
!macro preInit
  # 获取个人环境的注册表信息
  ReadRegStr $R5 HkCU "SOFTWARE\${APP_GUID}" "InstallLocation"
  StrCpy $OLD_PATH $R5
  StrCpy $UNINSTALL_PROG "$OLD_PATH\Uninstall ${PRODUCT_FILENAME}.exe"
!macroend 

# 宏 安装后 卸载(个人用户)旧的程序
!macro customInstall
  # 判断卸载程序是否存在,存在则静默执行,执行完将卸载程序删除,并删除文件夹
  IfFileExists $UNINSTALL_PROG handleUninstall done 
    handleUninstall:
      ExecWait '"$UNINSTALL_PROG" /S _?=$OLD_PATH' $0
      DetailPrint "Uninstall ${PRODUCT_FILENAME}.exe returned $0"
      Delete "$UNINSTALL_PROG"
      RMDir $OLD_PATH
    done: 
      ; MessageBox MB_ICONEXCLAMATION|MB_OK "$OLD_PATH"
!macroend