Proces tworzenia aplikacji nie opiera się tylko i wyłącznie na programowaniu. Gdy produkt jest już gotowy, trzeba jeszcze zadbać o jego wydanie, a także dalsze utrzymanie i rozwój. Może się to wydawać trudne – na szczęście istnieją rozwiązania, które ułatwiają nam to zadanie. Świetnym przykładem jest Qt Installer Framework, który pozwala na tworzenie przejrzystego, funkcjonalnego instalatora. Umożliwia on nie tylko samą instalacje aplikacji, ale także dalsze zarządzanie nią, aktualizowanie jej, a także wykonywanie wielu innych zadań. W dzisiejszym wpisie poznacie podstawy Qt Installer Framework, a także wspólnie stworzymy instalator offline dla aplikacji Windowsowej.
Qt Installer Framework – instalacja
Jeżeli masz już framework Qt na swoim dysku, to Qt Installer Framework możesz zainstalować za pomocą Qt Maintenace Tool w zakładce Developer and Designer tools:
Alternatywnie możesz też go pobrać z oficjalnego repozytorium Qt. Po instalacji powinien on znajdować się w folderze [lokalizacja Qt]/Tools/QtInstallerFramework
Jak wygenerować instalator za pomocą Qt Installer Framework?
1. Stwórz folder deployment
Zanim będziesz mógł utworzyć instalator dla Twojej aplikacji, musisz najpierw ją odpowiednio do tego przygotować. Należy więc stworzyć folder, w którym przechowane będą wszelkie pliki wymagane do uruchomienia aplikacji, a także do utworzenia jej instalatora. W tym celu utwórz w nim dwa foldery: config oraz packages.
Jak zapewne się domyślasz, pierwszy z nich będzie zawierał konfigurację twojego instalatora. W naszym wypadku będzie to pojedynczy plik o rozszerzeniu XML. Jak powinien wyglądać taki plik?
2.Stwórz plik konfiguracyjny
Plik konfiguracyjny powinien zawierać ogólne informacje o instalatorze: docelowy folder instalacji, wyświetlany tytuł instalatora, nazwę aplikacji itp. W pliku tym możemy jednak skonfigurować znacznie więcej rzeczy, jak np. możliwość uruchomienia aplikacji po instalacji, wygląd instalatora, czy zdalne repozytorium, przy pomocy którego instalator będzie sprawdzał dostępność aktualizacji. W żadnym innym miejscu nie znajdziecie tylu informacji, co w oficjalnej dokumentacji Qt, dlatego zachęcamy Was, abyście często do niej zaglądali. Znajdziecie tam znacznie więcej tagów, których możecie użyć przy konfiguracji instalatora.
Stwórzmy więc przykładowy plik konfiguracyjny:
1 2 3 4 5 6 7 8 9 10 |
<?xml version="1.0" encoding="UTF-8"?> <Installer> <Name>APP NAME</Name> <Version>1.0.0</Version> <Title>INSTALLER WINDOW TITLE</Title> <Publisher>Binarnie.pl</Publisher> <StartMenuDir>START_MENU_DIR</StartMenuDir> <TargetDir>@HomeDir@/APP_DIR</TargetDir> </Installer> |
Jak zapewne widzicie nie jest on bardzo rozbudowany, a co za tym idzie, nie wprowadza on wielu zmian w zachowaniu instalatora. Na ten moment taka konfiguracja jest jednak w pełni wystarczająca.
3. Stwórz paczkę
Wytłumaczmy najpierw czym właściwie jest paczka. Paczka jest modułem, który zawiera konkretną wersję aplikacji lub jej część. Jeżeli stworzysz kilka paczek, to podczas instalacji użytkownik będzie miał możliwość wybrania, które z nich chce zainstalować. Dobrym przykładem takiego podejścia może być sam framework Qt:
Jak widzicie w centrum okna znajduje się drzewo, z którego możemy wybierać składniki, które chcemy zainstalować. Podobnie wyglądałoby to w naszym instalatorze, gdybyśmy zawarli w nim wiele paczek.
Utworzony wcześniej folder packages powinien mieć następującą strukturę:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
- packages - com.vendor.root - data - meta - com.vendor.root.component1 - data - meta - com.vendor.root.component1.subcomponent1 - data - meta - com.vendor.root.component2 - data - meta |
Wiedząc już czym jest paczka, a także jak należy ją umiejscowić w folderze packages, możemy stworzyć pierwsze paczki naszej aplikacji. Dla przykładu stworzymy dwie paczki zawierające 32-bitową i 64-bitową wersje aplikacji.
Zacznijmy od stworzenia podfolderów. Za wzór nazw paczek przyjmijmy „domena.nazwa_dostawcy.nazwa_paczki”:
Mając foldery paczek, możemy zacząć uzupełniać ich zawartość.
4. Dodaj metadane
Jak już wcześniej pisaliśmy, każdy folder paczki musi zawierać dwa podfoldery: data i meta:
Pierwszy z nich będzie zawierał pliki wykonywalne, biblioteki i inne zasoby wymagane do uruchomienia aplikacji.
Drugi z nich będzie przechowywał informacje na temat paczki. W naszym wypadku folder meta będzie zawierał tylko dwa pliki: license.txt, package.xml. Plik license.txt zawiera licencję korzystania z paczki. Nie ma on żadnego, wymaganego formatu, możesz jednak korzystać w nim ze znaczników HTML, jeżeli potrzebujesz dodatkowej stylizacji.
Drugi z tych plików interesuje nas jednak bardziej. Package.xml zawiera informacje o paczce, które zostaną wyświetlone w oknie instalatora. Dodając kolejne tagi możesz stworzyć dodatkowe strony instalatora, tłumaczenia, zależności pomiędzy różnymi paczkami i wiele więcej. O pliku package.xml dowiecie się więcej w kolejnych poradnikach.
Jego zawartość powinna wyglądać mniej więcej tak:
1 2 3 4 5 6 7 8 9 10 11 |
<?xml version="1.0" encoding="UTF-8"?> <Package> <DisplayName>PACKAGE NAME</DisplayName> <Description>This is going to install APP NAME on your machine</Description> <Version>1.0.0</Version> <ReleaseDate>2020-06-17</ReleaseDate> <Licenses> <License name="LICENSE TITLE" file="license.txt" /> </Licenses> <Default>true</Default> </Package> |
Już same nazwy znaczników w większości wypadków mówią o ich przeznaczeniu. Pamiętaj, że dokumentacja to najlepszy przyjaciel programisty – znajdziesz w niej więcej przydatnych tagów.
5. Dodaj pliki do folderu data
Dodaliśmy już pliki w folderze meta. Pora więc uzupełnić folder data. Jest to folder, w którym znajduje się zawartość danej paczki – jego zawartość zostanie wypakowana do wskazanego folderu instalacyjnego. Aby zachować przejrzystość struktury folderu instalacyjnego zalecamy, aby stworzyć dodatkowy podfolder w folderze data:
Jako, że stworzyliśmy już sporą ilość folderów, by nie pogubić się w nich, nazwijmy ten konkretny folder „folderem plików paczki”.
Przejdźmy do najważniejszej części tego poradnika. W folderze plików paczki należy dodać wszystkie pliki, które są wymagane do uruchomienia aplikacji poza środowiskiem Qt Creator: wszelkie pliki wykonywalne, bilbioteki Qt, bliblioteki zewnętrzne, pliki *.dll itp. Na szczęście framework Qt ułatwia to zadanie, dając nam do dyspozycji zestaw narzędzi do wydawania oprogramowania.
Najpierw dodaj do folderu plików paczki, plik wykonywalny twojego programu – w przypadku Windows jest to plik .exe. Po prostu przekopiuj go z folderu zbudowanej aplikacji. Następnie otwórz wiersz poleceń w tym folderze. Uruchomimy teraz narzędzie „windeployqt.exe” – program, który automatycznie wyszukuje wymagane biblioteki Qt dla twojej aplikacji. Aby je uruchomić użyj tej komendy:”
[QtFolder]\[WersjaQt]\[FolderWybranegoZestawuNarzedzi]\bin\windeployqt.exe APPNAME.exe –qmldir [FolderZawierajacyKodZrodlowyQML] –compiler-runtime |
Narzędzie to doda (prawie) wszystkie biblioteki i pliki, które są wymagane do uruchomienia aplikacji bazującej na QML. Użycie argumentu –qmldir sprawi, że narzędzie przeskanuje kod QML, a następnie na jego podstawie wybierze biblioteki dll z modułu Qt Quick, z których twój program korzysta. Argument jako parametr przyjmuje folder z kodem źródłowym QML. Pliki zostaną przeskanowane rekurencyjnie, więc wystarczy, że wskażesz główny folder plików źródłowych QML. Jeżeli twoja aplikacja nie bazuje na QML, to możesz spokojnie pominąć ten argument.
W przypadku naszej przykładowej aplikacji komenda wyglądałaby tak:
C:\Qt\5.15.0\mingw81_64\bin\windeployqt.exe QtInstallerTutorial.exe –qmldir C:\Projects\QtInstallerTutorial –compiler-runtime |
Gdy narzędzie zakończy prace zauważysz, że folder plików paczki został wypełniony przeróżnymi plikami:
Niestety, narzędzie windeployqt ma to do siebie, że czasem wrzuca tutaj także niepotrzebne pliki. Pomimo to w folderze nadal jeszcze nie mamy wszystkich potrzebnych plików. Jakich konkretnie?
6. Dodaj brakujące biblioteki
Gdybyście teraz spróbowali uruchomić aplikację, to wyskoczyłby wam błąd o brakujących plikach. Do folderu plików paczki trzeba bowiem jeszcze dodać pliki charakterystyczne dla wybranego przez Was kompilatora. W dokumentacji znajdziesz listę podstawowych bibliotek, w tym:
Dla Qt:
- QT5CORE.DLL – runtime QtCore
- QT5GUI.DLL – runtime QtGui
- QT5WIDGETS.DLL – runtime QtWidgets
Dla VC++ 14.0 (2015):
- VCCORLIB140.DLL, VCRUNTIME140D.DLL – runtime C
- MSVCP140.DLL – runtime C++
Dla MinGW:
- LIBWINPTHREAD-1.DLL
- LIBGCC_S_DW2-1.DLL
- LIBSTDC++-6.DLL
Aby jednak upewnić się, że nie pominęliśmy żadnej biblioteki, dokumentacja Qt zaleca uruchomienia narzędzia Dependency Walker. Pozwala ono na szybkie sprawdzenie jakich plików nasz program nie może znaleźć.
W naszym wypadku brakuje bibliotek LIBGCC_S_SEH-1.DLL oraz LIBSTDC++-6.DLL. Możemy je znaleźć w folderze danego zestawu narzędzi Qt:
Wystarczy przekopiować je do folderu plików paczki. Dobrą praktyką jest sprawdzenie, czy program działa, zanim wygenerujemy instalator. W tym celu po prostu uruchom plik wykonywalne .exe. W ten sposób sprawdzisz, czy aby na pewno dołączone zostały wszystkie wymagane pliki. Nasz aplikacja z przykładu wciąż nie będzie chciała się uruchomić. Dlaczego? Specjalnie pominęliśmy plik LIBWINPTHREAD-1.DLL przy kopiowaniu, aby pokazać Wam, że sprawdzenie programu przed jego wydaniem jest bardzo ważnym krokiem. Przekopiujmy więc ten plik do folderu plików paczki i możemy przejść do tworzenia instalatora!
Uwaga: wspomniane w przykładzie biblioteki .dll mogą się znacząco różnić w Twoim wypadku – wszystko zależy od wybranego kompilatora oraz wewnętrznych zależności. Nie zapomnij również powtórzyć kroków 4-7 dla wszystkich twoich paczek. W naszym wypadku powtórzyliśmy je dla paczki wersji 32-bitowej.
7. Generowanie instalatora
Gdy mamy już przygotowane wszystkie paczki, możemy w końcu stworzyć nasz instalator. Potrzebne nam będzie do tego narzędzie binarycreator z Qt Installer Framework.
Otwórzmy najpierw terminal w folderze wydania (ten, który zawiera foldery config i packages):
Uruchom narzędzie binarycreator.exe używając komendy poniżej:
[Qtfolder]\Tools\QtInstallerFramework\[WersjaQtInstaller]\bin\binarycreator.exe -c config/config.xml -p packages -f NAZWA_INSTALATORA |
Argument -c wskazuje na plik konfiguracyjny instalatora, argument -p wskazuje na lokalizacje folderu z paczkami, zaś argument -f informuje narzędzie, że chcemy wygenerować instalator offline. Wszystkie dostępne argumenty znajdziecie w dokumentacji.
W naszym przykładzie komenda będzie wyglądała następująco:
C:\Qt\Tools\QtInstallerFramework\4.0\bin\binarycreator.exe -c config/config.xml -p packages -f QtInstallerTutorial |
Po wciśnięciu enter terminal może się chwilowo „zwiesić”, nie ma jednak powodu do obaw – generowanie instalatora może zając trochę czasu. Gdy narzędzie zakończy swoje działanie, w folderze ujrzysz nowy plik – Twój instalator:
Instalator po uruchomieniu powinien wyglądać tak:
Instalator uruchomi się w języku systemowym – gdyby uruchomić nasz instalator na komputerze znajdującym się w Pekinie to zamiast „Dalej” ujrzelibyście „进一步”
Gratulacje! Udało nam się wspólnie utworzyć nasz pierwszy instalator. Dla upewnienia możesz sprawdzić, czy konfiguracja jest poprawna: ilość paczek, folder docelowy, zawartość folderu po instalacji itp. Jeżeli wszystko jest okej, to tego typu instalator jest gotowy do udostępnienia – można go przekazać klientowi. Jedyne, co użytkownik musi zrobić, to uruchomić instalator i postępować zgodnie z wyświetlanymi instrukcjami,
Instalacja zawiera w sobie nie tylko przekazane przez Ciebie paczki, ale także narzędzie do zarządzania zainstalowanym programem. Użytkownik może w nim dodawać, usuwać paczki, a także aktualizować aplikację (o ile zostało ustawione zdalne repozytorium) lub całkowicie ją usunąć.
Inne zastosowania
Dobrą praktyką jest tworzenie aplikacji w systemie CI/CD w połączeniu z Qt Installer Framework. Dzięki temu możesz zautomatyzować cały proces: gdy tylko zajdą w zmiany w głównej gałęzi repozytorium, to zostaną uruchomione odpowiednie komendy, dzięki czemu użytkownik będzie miał zawsze dostęp do najaktualniejszej wersji instalatora.
Warty uwagi jest również CLI dodane w Qt Installer Framework 4.0. Interfejs ten pozwala na korzystanie z instalatora poprzez wiersz poleceń. Z jego poziomu, za pomocą komend, możesz wiec zainstalować aplikacje, zaktualizować ją, zmodyfikować jej komponenty lub ją usunąć.
Interfejs ten może być przydatny, gdy np. chcesz wdrożyć automatyczne aktualizacje. W takim wypadku twoja aplikacja otworzy po prostu narzędzie do zarządzania programem, w momencie gdy dostanie informację od API o nowej aktualizacji. Możesz także bezpośrednio z niego sprawdzać ich dostępność, a nawet odinstalować aplikację wywołując odpowiednie funkcje. Jeżeli chcesz dowiedzieć się więcej, zajrzyj do dokumentacji CLI.
Podsumowanie
W dzisiejszym wpisie dowiedzieliście się jak generować instalator offline aplikacji Qt dla systemu Windows. Poznaliście również inne, przydatne funkcje frameworka Qt Installer. W następnym wpisie dowiecie się jak dostosować wygląd instalatora według własnych upodobań. Miłej środy 😀 Oryginalny tekst w języku angielskim znajdziecie tutaj: Deploying app and generating offline installers for Windows Qt Installer Framework tutorial.