Scythe Studio website employs cookies to improve your user experience (Read more)

How tu customise installer behaviour with Qt Installer Framework

In previous posts of this series, we briefly touched on the topic of scripting, while describing how to add custom pages to the installer UI. In this entry we will go much deeper. You will be able to learn what types of scripts are available and how to create them in the Qt Installer Framework – all of that with some handy examples. Let’s go!

 

API overview

Before doing the scripting itself, let’s explain what is the Scripting API and how it works.

In the Qt Installer Framework, Scripting API is basically a set of JavaSctipt objects. Scripts created with this API use files with .qs extension, which are executed by QJSEngine. You can use scripts to execute certain actions or modify the installer behaviour during runtime, for example by adding custom pages depending on which components were selected for installation. In the case of installers, there are two main types of scripts: controller scripts and component scripts.

Controller scripts are used for interacting with certain parts of the installer’s UI or functionality. For instance, you can modify existing pages or simulate user clicks in order to automate some parts of the installation. For each installer, there can be only a single controller script that is pointed in the config.xml file.

Component scripts are used to handle behaviour for selected component in the installer, so each component can have its own script. Because of that, each installer can contain several component scripts. They are executed when the component is selected for installation. The component script you want to use have to be pointed in the package.xml file.

Controller script basics

First, let’s talk a little bit about scripts structure in Qt Installer Framework. Both controller and component scripts share almost the same structure – the only difference between them is based on what you can do inside the script and the name of the constructor.

A minimal valid script needs to contain at least a constructor. For beginning we can create script.qs file. In order to make this file be recognized as proper script we have to put the empty constructor in it. In the case of the controller script, it is the following constructor:

function Controller()
{
}

Now let’s implement some simple function to modify installer behaviour. Let’s say that we want to skip some pages in the installer automatically – for example, the introduction page. One of the simple solutions to do this is to invoke a click on the „Next” button when the selected page appears. To do so, we can use Controller.prototype.IntroductionPageCallback. The script should look as follows:

function Controller()
{
}

Controller.prototype.IntroductionPageCallback = function()
{
    gui.clickButton(buttons.NextButton);
}

In this script, we used two global objects that are accessible in controller scripts. The first one is the gui which is JavaScript global object that allows for interaction with the installer UI. The buttons, as the name implies, allow us to use buttons placed in installer pages. Besides those objects, each page has a set of its own methods, buttons and widgets. For example on component selection page you can use functions like selectAll() or selectComponent(id) in order to manage component selection. We won’t describe all of them in this post as it would take too long. If you want to get familiar with all available options, take a look at the documentation.

Now in order to use script in your installer, open configuration file for your installer and simply add the following tag to it:

<ControlScript>script.qs</ControlScript>

Don’t forget to place script.qs inside the configuration directory! Now your first controller script is hooked up – you can generate a new installer and give it a try. If you don’t remember how to do it, take a look at the first post of this series.

Component script basics

Now we have a functional controller script. Let’s create the basic component script. Just like in the case of controller script you have to start with a constructor – in this case, its name is Component. As a simple example of a component script, let’s use the one from previous post. Its purpose is to add custom page to the installer if the component is selected. To implement it we can use addWizardPage function:

function Component()
{
    installer.addWizardPage(component, "MyOtherPage", QInstaller.ReadyForInstallation);
}

A function that adds new page takes three parameters. First is the component which contains the registered name of the widget class you want to add – in this case, a global component object referencing the current Component was passed. The next argument is the name of the registered widget class you want to use. Last is the index of the existing page before which new page will be placed. In this case, CustomPage would be placed before the ReadyForInstallation page.

In case to make this script working you also have to add a page .ui file that will contain page design in the package directory while also register this file in package.xml. Besides that you also need to point the script in the package.xml to make it execute:

<Script>installscript.qs</Script>
<UserInterfaces>
    <UserInterface>CustomPage.ui</UserInterface>
</UserInterfaces>

If you want to learn more about customizing installer UI, take a look at following post.

Adding a shortcut 

As you are now familiar with the basics of writing scripts, we can now move on to more advanced use cases with examples. Let’s say we have a Windows app installer and we want to create an app shortcut on the desktop after finishing an installation. To implement such functionality we can use the component script as different executables can be used for different packages.

All we need to do is to add custom operation that will be executed when the component is installed. To do so we can use Component.prototype.createOperations hook with addOperation function:

function Component()
{
    // default constructor
}

Component.prototype.createOperations = function()
{
    try {
        // call the base create operations function
        component.createOperations();
        // check if we are on widnows machine
        if (installer.value("os") == "win") {
            try {
                // look for user profile directory
                var userProfile = installer.environmentVariable("USERPROFILE");
                installer.setValue("UserProfile", userProfile);
                component.addOperation("CreateShortcut", "@TargetDir@\\win64\\application.exe", "@UserProfile@\\Desktop\\My\ App.lnk");                
            } catch (e) {
                // Do nothing if key doesn't exist
            }
        }
    } catch (e) {
        print(e);
    }
}

Recursive installation 

There might be a case that despite libraries and other files that you can simply place in the deployment folder there might be some external tools that are needed to make your app working on the end device. A most common example of such a case are Microsoft Visual C++ Redistributable packages containing C and C++ runtime, that are needed on the device if you compiled an app using an MVSC kit.

You can simply place runtime .dll files in the deployment folder however, there is a catch. Antivirus software doesn’t really like using C and C++ runtime libraries that were not installed with Microsoft installer, as modified runtime can do some nasty things in the user’s computer. Using this approach you can make your app be recognized as malicious, and you never want such a thing to happen. What should you do?

Solution is quite simple – perform recursive installation of redistributable packages. It may sound fancy and hard to implement, but it all comes down to check if there are existing VC runtime on the device and, if not, executing redistributable packages installer from Microsoft. Let’s take a look at how it is done.

The first thing you need to do is download a redistributable packages installer from the Microsoft website. After that place it in data folder of the package.

Now let’s go with the scripting. As we are working with a single component, we need a component script. First, we need to crate a custom function that will allow us to check for existing VC runtime and execute installer if it is missing:

Component.prototype.installVCRedist = function()
{
    var registryVC2017x64 = installer.execute("reg", new Array("QUERY", "HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\VisualStudio\\14.0\\VC\\Runtimes\\x64", "/v", "Installed"))[0];
    var doInstall = false;

    if (doInstall)
    {
        QMessageBox.information("vcRedist.install", "Install VS Redistributables", "The application requires Visual Studio 2017 Redistributables. Please follow the steps to install it now.", QMessageBox.OK);
        var dir = installer.value("TargetDir");
        installer.execute(dir + "/VC_redist.x64.exe", "/norestart", "/passive");
    }
}

In this function, we first check system registers to verify if there is VC runtime installed. If the installation is needed, a message box with proper information is shown. After clicking ok, the installer is executed. We are using the „TargetDir” path as the VC runtime installer is placed in the same place as the root directory of the installed app.

All is left to do is to execute the function after installation of the component is finished. To do so we can use signal and slots system that is also available in the script engine:

function Component()
{
    // constructor
    installer.installationFinished.connect(this, Component.prototype.installVCRedist);
}

Summary 

In this post, you learned what is Scripting API in Qt Installer Framework and how to use it.  Using this fresh knowledge you can now play and experiment with the installer scripts as the possibilities for applying them are endless. There are many more popular use cases for scripts than those presented in this post. In future posts we will present more of them, so stay tuned.

If you like this post subscribe to our newsletter and stay up to date.

Latest posts

QML 3D: First impressions main image
QML 3D: First impressions

If we think about it for a minute, it is impossible to imagine an app without a UI. We need […]

26 May 2021
Top 10 Cross-platform apps ideas 2021 main image
Top 10 Cross-platform apps ideas 2021

When developing an application you want it to be as enjoyable for clients as it’s possible, so you take much […]

15 Apr 2021
How to use NFC in Qt/Qml application? main image
How to use NFC in Qt/Qml application?

Have you ever wondered how to use NFC in Qt/Qml application? This blog post will give you a complex overview […]

09 Mar 2021
How to generate barcode in Qt/QML application main image
How to generate barcode in Qt/QML application

Nowadays, everywhere we look, no matter if it’s a real-life shop or web page, we can see these little, simple and useful, […]

24 Feb 2021
Low technology stack with Qt: Saved money main image
Low technology stack with Qt: Saved money

When creating a new software, you want the quality to be the highest, while keeping the costs low and delivery […]

08 Feb 2021
How to customize installer UI with Qt Installer Framework main image
How to customize installer UI with Qt Installer Framework

In the previous post you learned the basics of the app deployment process and installer generation. However Qt Installer Framework […]

12 Jan 2021
Deploying app and generating offline installers for Windows Qt Installer Framework tutorial main image
Deploying app and generating offline installers for Windows Qt Installer Framework tutorial

Development is not an only part of product delivering – deployment and maintenance are both equally important parts of the […]

25 Nov 2020
How to interface Qt with Android Java code main image
How to interface Qt with Android Java code

Software development is demanding and often requires us to use languages or solutions that are not part of our main […]

18 Nov 2020
Qt Creator Cheat Sheet main image
Qt Creator Cheat Sheet

Qt Creator Cheat Sheet is a convenient document to improve your familiarity with Qt Creator IDE. The work of every […]

03 Nov 2020
How to track keyboard usage on Windows with Qt in 2020 main image
How to track keyboard usage on Windows with Qt in 2020

There are many use cases when the frequency of user input needs to be tracked. The simple example is a […]

28 Sep 2020