目录
1.背景
本文主要实现了基于windows平台,使用PyQt5技术开发、打包软件,当用户安装完成后,软件会自动运行的效果。
2.使用的打包技术 FBS
这里我使用的PyQt打包软件为FBS,官方文档地址:https://build-system.fman.io/,官方教程https://github.com/mherrmann/fbs-tutorial。文档比较详实,经过项目的打包过程学习实践后来看,该打包框架确实简单,繁琐的打包任务一行命令就可以解决,具体使用方法这里不再赘述。
通过学习可以发现,fbs官网教程基于windows平台打包发布,有这样一段描述: Before you can use the installer
command on Windows, please install NSIS and add its installation directory to your PATH
environment variable. 如果想要打包发布项目,需要使用的是NSIS(专门用于制作window安装程序的工具软件)。从官网上下载安装后,需要配置下环境变量才可以使用。
如下图所示,为本文使用的fbs创建的项目结构,提供参考:
3.三种基于windows平台软件自启动方案
下面进入文本的正题,如何进行项目的配置,来达到软件安装后的自启动。文本参考的一篇文献为nsis-start-program-automatically-when-windows-starts。
总结下来,有三种方式可以来实现这个目的:
1. 通过添加Run 或者 RunOnce 注册表的方式;
2.在windows平台的Start Menu/Startup 文件夹下创建快捷方式;(最终使用的方案)
3.通过将程序注册为服务的方式,但是我们的项目是GUI程序,不支持这种方式,所以该方法暂时不考虑。
4. 操作实验
打包pyqt项目使用的是fbs打包工具,所以通过上面有关fbs的学习,我们可以在项目/src/installer/windows下创建文件Installer.nsi.
4.1 Run/RunOnce Key 添加注册表的方式
WriteRegStr HKLM “Software\Microsoft\Windows\CurrentVersion\Run” “Monitor” “X:\Monitor.exe”
WriteRegStr HKCU “Software\Microsoft\Windows\CurrentVersion\Run” “Monitor” “X:\Monitor.exe”
需要说明的是,HKLM(HKEY_LOCAL_MACHINE)是针对计算机系统所有用户而言的,HKCU(HKEY_CURRENT_USER)是针对当前用户而言的。
NSIS 给出的实例代码截图(https://nsis.sourceforge.io/Running_a_.exe_file_on_Windows_Start):
这里我项目里面所做的具体尝试步骤如下:
a) 修改初始化部分脚本:
b)添加写入注册表代码:
c) 在用户删除软件的时候,同时删除注册表:
最终打包软件发布后,安装一路next没有问题,点击exe打开软件也没有问题。接着把电脑关机,重新开机出现了
这里我进行了很多的尝试,打包后的软件运行没有问题,但是打包之后,放到系统自启动注册表里面就有这样的问题。我使用的python版本为3.7。FBS打包软件官网上说目前只支持python3.5 3.6版本,3.7版本没有经过测试,所以可能版本上出现了问题,如果你找到了解决的办法,请留言。
4.2 Start Menu/Startup Folder
该方法是我觉得最简单的方法,不用去写、删除注册表,直接在window的Start Menu目录下创建快捷方式,当windows系统启动后最自动打开软件,所以项目最终使用了这种方案。
同样的是在installer.nsi 编写了相关的配置文件:
最后一行命令,解决问题,打包后的软件在target目录下:
5.总结
本文最终解决了pyqt5项目如何实现安装包安装后开机自启动的问题,达到了最初的目标,这汇总了我的Installer.nsi配置文件代码最终展示如下:
!include MUI2.nsh
!include FileFunc.nsh
;--------------------------------
;Perform Machine-level install, if possible
!define MULTIUSER_EXECUTIONLEVEL Highest
;Add support for command-line args that let uninstaller know whether to
;uninstall machine- or user installation:
!define MULTIUSER_INSTALLMODE_COMMANDLINE
!include MultiUser.nsh
!include LogicLib.nsh
Function .onInit
!insertmacro MULTIUSER_INIT
;Do not use InstallDir at all so we can detect empty $InstDir!
${If} $InstDir == "" ; /D not used
${If} $MultiUser.InstallMode == "AllUsers"
StrCpy $InstDir "$PROGRAMFILES\${app_name}"
${Else}
StrCpy $InstDir "$LOCALAPPDATA\${app_name}"
${EndIf}
${EndIf}
FunctionEnd
Function un.onInit
!insertmacro MULTIUSER_UNINIT
;DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Run"
FunctionEnd
;--------------------------------
;General
Name "${app_name}"
OutFile "..\${installer}"
;--------------------------------
;Interface Settings
!define MUI_ABORTWARNING
;--------------------------------
;Pages
!define MUI_WELCOMEPAGE_TEXT "This wizard will guide you through the installation of ${app_name}.$\r$\n$\r$\n$\r$\nClick Next to continue."
!insertmacro MUI_PAGE_WELCOME
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_INSTFILES
!define MUI_FINISHPAGE_NOAUTOCLOSE
!define MUI_FINISHPAGE_RUN
!define MUI_FINISHPAGE_RUN_CHECKED
!define MUI_FINISHPAGE_RUN_TEXT "Run ${app_name}"
!define MUI_FINISHPAGE_RUN_FUNCTION "LaunchLink"
!insertmacro MUI_PAGE_FINISH
!insertmacro MUI_UNPAGE_CONFIRM
!insertmacro MUI_UNPAGE_INSTFILES
;--------------------------------
;Languages
!insertmacro MUI_LANGUAGE "SimpChinese"
!insertmacro MUI_LANGUAGE "English"
;--------------------------------
;Installer Sections
!define UNINST_KEY \
"Software\Microsoft\Windows\CurrentVersion\Uninstall\${app_name}"
Section
SetOutPath "$InstDir"
File /r "..\${app_name}\*"
WriteRegStr SHCTX "Software\${app_name}" "" $InstDir
WriteUninstaller "$InstDir\uninstall.exe"
CreateShortCut "$SMPROGRAMS\${app_name}.lnk" "$InstDir\${app_name}.exe"
WriteRegStr SHCTX "${UNINST_KEY}" "DisplayName" "${app_name}"
WriteRegStr SHCTX "${UNINST_KEY}" "UninstallString" \
"$\"$InstDir\uninstall.exe$\" /$MultiUser.InstallMode"
WriteRegStr SHCTX "${UNINST_KEY}" "QuietUninstallString" \
"$\"$InstDir\uninstall.exe$\" /$MultiUser.InstallMode /S"
WriteRegStr SHCTX "${UNINST_KEY}" "Publisher" "${author}"
${GetSize} "$InstDir" "/S=0K" $0 $1 $2
IntFmt $0 "0x%08X" $0
WriteRegDWORD SHCTX "${UNINST_KEY}" "EstimatedSize" "$0"
; CREATE SHORT_CUT
CreateDirectory "$SMPROGRAMS\${app_name}"
CreateShortCut "$DESKTOP\${app_name}.lnk" "$INSTDIR\${app_name}.exe"
; SET AUTO_BOOT
CreateShortCut "$SMSTARTUP\${app_name}.lnk" "$INSTDIR\${app_name}.exe" ""
;WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Run" "${app_name}" "$\"$INSTDIR\${app_name}.exe$\""
SectionEnd
;--------------------------------
;Uninstaller Section
Section "Uninstall"
RMDir /r "$InstDir"
Delete "$SMPROGRAMS\${app_name}.lnk"
Delete "$DESKTOP\${app_name}.lnk"
Delete "$SMSTARTUP\${app_name}.lnk"
DeleteRegKey /ifempty SHCTX "Software\${app_name}"
DeleteRegKey SHCTX "${UNINST_KEY}"
;DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Run"
SectionEnd
Function LaunchLink
!addplugindir "."
ShellExecAsUser::ShellExecAsUser "open" "$SMPROGRAMS\${app_name}.lnk"
FunctionEnd