Ранее в серии Qt мы видели, как объединить кроссплатформенную мощь Qt с инфраструктурой CI/CD Github Actions для создания двоичных файлов для Windows, MacOs и Linux.
В этом эпизоде мы увидим, как создать установщик для доставки нашей программы клиентам. Это основной способ распространения в Windows, но его также можно сделать для MacOs и Linux.
Qt Installer Framework поддерживает два типа установщиков:
- Offline: простой исполняемый файл, который устанавливает двоичный файл и его зависимости.
- В сети: исполняемый файл, который вызывает веб-сервер, сравнивает версию программы с текущей и устанавливает соответствующую версию с веб-сервера. Эта версия позволяет выполнять простые обновления для пользователя.
В этом эпизоде мы создадим простой установщик только с одним пакетом и настраиваемым компонентом. Установщик выполнит три задачи:
- Принятие лицензии.
- Установка программы в указанное место.
- Открытие программы и документации.
Архитектура
Во-первых, нам нужно создать необходимые папки и файлы конфигурации, которые будут следовать этой архитектуре (для нескольких пакетов инкапсулируйте каждый пакет в подпапку внутри каталога пакетов):
ProgramInstaller │ └───packages │ │ │ └───Program │ │ │ └───data │ │ │ data.7z │ │ │ └───meta │ │ license.txt │ │ installscript.qs │ │ package.xml │ │
readmecheckboxform.ui│ └───config │ config.xml
Лицензия.txt
Лицензия программного обеспечения, которую пользователь должен принять для установки программы.
Установить.qss
Файл install.qss определяет компонент, отображаемый в процессе установки. В функции Component.prototype.createOperations мы определяем два ярлыка: один для исполняемого файла программы, второй для Qt MaintenanceTool, который появится в стартовом меню. Следующие две функции отобразят пользовательский компонент, который откроет программу и документацию, если пользователь установит флажки.
function Component() { installer.installationFinished.connect(this, Component.prototype.installationFinishedPageIsShown); installer.finishButtonClicked.connect(this, Component.prototype.installationFinished); } Component.prototype.createOperations = function() { component.createOperations(); if (systemInfo.productType === "windows") { component.addOperation("CreateShortcut", "@TargetDir@/Program.exe", "@StartMenuDir@/Program.lnk", "workingDirectory=@TargetDir@","iconPath=@TargetDir@/icon.ico", "description=Program Icon"); component.addOperation("CreateShortcut", "@TargetDir@/maintenancetool.exe", "@StartMenuDir@/ProgramUpdater.lnk", "workingDirectory=@TargetDir@", "description=Program Updater"); installer.setDefaultPageVisible(QInstaller.LicenseCheck, false); } } Component.prototype.installationFinishedPageIsShown = function() { try { if (installer.isInstaller() && installer.status == QInstaller.Success) { installer.addWizardPageItem( component, "ReadMeCheckBoxForm", QInstaller.InstallationFinished ); } } catch(e) { console.log(e); } } Component.prototype.installationFinished = function() { try { if (installer.isInstaller() && installer.status == QInstaller.Success) { var isReadMeCheckBoxChecked = component.userInterface( "ReadMeCheckBoxForm" ).readMeCheckBox.checked; if (isReadMeCheckBoxChecked) { QDesktopServices.openUrl("https://siteofdoc.html"); } var isStartCheckBoxChecked = component.userInterface( "ReadMeCheckBoxForm" ).startCheckBox.checked; if (isStartCheckBoxChecked) { installer.executeDetached("@TargetDir@/Program.exe"); } } } catch(e) { console.log(e); } }
Пакет.xml
Файл package.xml — это файл конфигурации единственного пакета, содержащегося в нашем установщике.
<?xml version="1.0" encoding="UTF-8"?> <Package> <DisplayName>Program package</DisplayName> <Description>Program package</Description> <Version>0.0.0</Version> <ReleaseDate></ReleaseDate> <Licenses> <License name="GNU GENERAL PUBLIC LICENSE" file="license.txt" /> </Licenses> <Default>true</Default> <Script>installscript.qs</Script> <UserInterfaces> <UserInterface>readmecheckboxform.ui</UserInterface> </UserInterfaces> </Package>
Readmecheckboxform.ui
Этот файл представляет собой декларативный пользовательский интерфейс для нашего пользовательского компонента, который откроет программу и документацию в конце процесса установки, если пользователь установит флажки.
<?xml version="1.0" encoding="UTF-8"?> <ui version="4.0"> <class>ReadMeCheckBoxForm</class> <widget class="QWidget" name="ReadMeCheckBoxForm"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>412</width> <height>179</height> </rect> </property> <layout class="QVBoxLayout" name="verticalLayout"> <property name="leftMargin"> <number>0</number> </property> <property name="topMargin"> <number>0</number> </property> <property name="rightMargin"> <number>0</number> </property> <property name="bottomMargin"> <number>0</number> </property> <item> <widget class="QCheckBox" name="readMeCheckBox"> <property name="text"> <string>Open the User manual</string> </property> <property name="checked"> <bool>true</bool> </property> <property name="tristate"> <bool>false</bool> </property> </widget> </item> <item> <widget class="QCheckBox" name="startCheckBox"> <property name="text"> <string>Start Program</string> </property> <property name="checked"> <bool>true</bool> </property> </widget> </item> </layout> </widget> <resources/> <connections/> </ui>
Данные.7z
Архив data.7z будет содержать бинарник и зависимости пакета, который будет распакован в папку установки.
Конфиг.xml
config.xml — это файл конфигурации для установщика. Если вам нужен интерактивный установщик, необходимо добавить URL-адрес, доступный для установщика, в теге ‹Url›‹/Url›. На следующем шаге мы увидим, что добавить в конечную точку этого URL.
<?xml version="1.0" encoding="UTF-8"?> <Installer> <Name>Program</Name> <Version>0.0.0</Version> <Title>Program Installer</Title> <Publisher>MyCompany</Publisher> <StartMenuDir>Program</StartMenuDir> <TargetDir>@HomeDir@/Program Files (x86)/Program</TargetDir> <RemoteRepositories> <Repository> <Url>url to remote repo</Url> </Repository> </RemoteRepositories> </Installer>
Действия на GitHub
Теперь мы автоматизируем создание этого установщика с помощью действий GitHub и повторного использования концепций, которые мы видели в эпизоде 1 серии Qt.
Как обычно, мы создаем новый файл .github/workflows/installer.yml.
│.github │ └───workflows │ │ installer.yml │ ProgramInstaller │ └───packages │ │ │ └───Program │ │ │ └───data │ │ │ data.7z │ │ │ └───meta │ │ license.txt │ │ installscript.qs │ │ package.xml │ │
readmecheckboxform.ui│ └───config │ config.xml
installer.yml:
name: Continous Builds on: push: branches: [master] jobs: runs-on: windows-latest steps: - uses: actions/checkout@v2 - uses: actions/setup-python@v2 with: python-version: '3.8' - name: install qt6 run: | pip install aqtinstall python3 -m aqt install-qt -O ${{ github.workspace }}/Qt/ windows desktop 6.2.0 win64_msvc2019_64 python3 -m aqt install-tool -O ${{ github.workspace }}/Qt/ windows desktop tools_ifw echo "${{ github.workspace }}/Qt/6.2.0/msvc2019_64/bin/" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append echo "${{ github.workspace }}/Qt/Tools/QtInstallerFramework/4.1/bin/" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append - name: build shell: cmd run: | repogen.exe -p .\ProgramInstaller
\packages OnlineRepository binarycreator.exe -p .\ProgramInstaller
\packages -c .\Program
\config\config.xmlProgramInstaller
- name: Windows artefact uses: actions/upload-artifact@v1 with: name:ProgramInstaller
path: ./Program
Installer.exe - name: Windows artefact uses: actions/upload-artifact@v1 with: name: OnlineRepository path: ./OnlineRepository
Первые шаги Действия аналогичны тому, что мы видели в S01E01. Дополнительным шагом является установка Qt Installer Framework с помощью aqtinstall с командой install-tool.
Мы используем repogen.exe для создания онлайн-репозитория, который мы должны разместить на веб-сервере в конечной точке URL, который мы указали в файле config.xml. .
Затем мы используем binarycreator для создания установщика. По умолчанию установщик будет содержать все компоненты и может получить доступ к онлайн-репозиторию, если URL-адрес был указан заранее. В результате его можно установить как с подключением к Интернету, так и без него. Можно создать автономный установщик, добавив параметр — только офлайн, и онлайн-установщик, который не содержит никаких компонентов и требует подключения к Интернету, добавив — параметр только онлайн.
Вывод
Автоматическое создание автономных и онлайн-установщиков с использованием Qt Installer Framework и GitHub Actions — это просто и упростит процесс доставки нашего приложения клиенту. В следующем эпизоде мы подробно рассмотрим онлайн-репозиторий, который мы создали с помощью онлайн-установщика. Что с этим делать? Как им управлять? Как клиент может обновить Программу?