Speeding up debugging and prototyping of mobile QML applications on a live device

    Hey.

    I want to share a simple way to optimize my working time when developing QML applications for Android / iOS / Embedded.

    Perhaps what I said to someone will seem a slaughter, but so far I have not read about such an elementary method.

    The essence of the problem is when developing, debugging or prototyping any mobile application in any language, we usually always go through the same steps: editing the code, deploying, launching. And so on ad infinitum. In the case of mobile development, the deployment phase of the code can stretch for an impressive time - from 2 to 10 minutes, during which there is basically nothing to do. Perhaps for some it is good, but certainly not for those who value their time. In general, I think, not only this state of things freaks me out ;-)

    The situation is aggravated for native development tools, for example, for Android, where we always, without options, need to recompile Java code before the next launch on the device.

    Qt at first glance has the same problem - each new build of the project is also deployed to the device for a long time. There is only one peculiarity - we can write applications not in Qt / C ++, but in pure QML. In this case, if we do not change the logic in the C ++ part of the application, we do not need to compile anything for the target platform. So - it would be cool to just update the qml set of application files and restart the application on the device. After all, saving time for 10 launches would have been at least an hour!

    Well, since there is a potential opportunity - it’s a sin not to use it. Read under the cut, what I did.

    Starting to dig information on the topic, I first came across the once-promising QML Live Preview project ( an article on the hub ), which allowed developers to launch debug mode in Qt Creator, change code on the fly and see their edits on the device. It was magic and what I needed, only this Qt Creator module was excluded from the general code base ( link to commit ). Maybe Digia is muddying something and transferred it to the commercial version, or maybe it was unstable. I do not know. The main thing is that he is no more.

    In general, I had to look for a workaround. He was found on the pageQt documentation that talks about a topic like network transparency when loading resources. The idea is that Qt and QML do not care where to load QML files and resources such as fonts, images, and more. The source can be a local disk, Qt resources (qrc), smb-ball or http-server.

    The idea of ​​implementation arose instantly! We deploy the HTTP server on the local machine, the root directory of which will be our project, change the script for loading resources in the C ++ part of the application, check the health on the desktop, collect it under the mobile, check the health on the mobile, rejoice!

    Full description of the algorithm:
    1) We make sure that our PC and device are on the same local network.

    2) We bring the project to the requirements of Qt Network Transparent and a specific template:
    - all resources in the / assets directory;
    - all qml files in the / qml directory;
    - inside the qml directory, the directory file structure should be a maximum of two levels;
    - all inclusions of type import "dir" are reduced to the form import "dir" as Dir;
    - all calls to components in subdirectories are given from the form MyComp {...} to the form Dir.MyComp {...};

    3) Download, configure and run nginx. In the default settings, you need to change only two parameters - the port and root directory. Then run nginx. Example:
    server {
            listen       8085;
    ...
    location / {
                root   D:/Dropbox/work/anyway;
    

    4) In the main.cpp file at the place of loading the qml-files, we change the logic to the following:
        bool qmlDebug = true;
        QString url = "http://192.168.1.22:8085/";
        QString qmlLoadPrefix;
        QString assetsLoadPrefix;
        QNetworkAccessManager NAManager;
        QUrl qurl (url+"qml/main.qml");
        QNetworkRequest request(qurl);
        QNetworkReply *reply = NAManager.get(request);
        QEventLoop eventLoop;
        QObject::connect(reply, SIGNAL(finished()), &eventLoop, SLOT(quit()));
        eventLoop.exec();
        if (reply->error() != QNetworkReply::NoError) {
            qmlDebug = false;
            qDebug() << "Error loading qml by network. Load from resources!";
        }
        if (qmlDebug) {
            qmlLoadPrefix = url+"qml/";
            assetsLoadPrefix = url+"assets/";
        } else {
            qmlLoadPrefix = "qrc:/";
            assetsLoadPrefix = "qrc:/";
        }
        engine.rootContext()->setContextProperty("qmlLoadPrefix", qmlLoadPrefix);
        engine.rootContext()->setContextProperty("assetsLoadPrefix", assetsLoadPrefix);
        engine.load(QUrl(qmlLoadPrefix+"main.qml"));
    

    Here we set the URL of our PC on the local network, as well as two variables qmlLoadPrefix and assetsLoadPrefix. It’s not hard to guess, these are just prefixes for accessing application resources and qml files, depending on the current application configuration. So during the active development phase, we can quickly download the required resources via http, and when the application is released, we can download everything from the resource files of the application itself.

    5) Well, the last step is to change all occurrences of the type “qrc: //myImg.png” to assetsLoadPrefix + “myImg.png” in all qml files of the project.

    That's all. It remains to note that now you need to start the debugging application not using the large green “Play” button on the left toolbar of Qt Creator, but using the small “Play” button on the bottom toolbar in the “Application Output” section. True, this button will not be available immediately after starting Qt Creator and you will need to launch the application for the first time in the old fashion, but then it is enough to use only it. At the same time, all the necessary debug messages will also be poured into the Qt Creator log, and if you need full debugging, then it will work as usual.

    Of course, this is not so hot hack and it still will not save you from rebuilding the application when writing C ++ code, but even in this form we get much more convenience when developing applications for any of the platforms.

    I suggest in the comments to share my thoughts and suggestions regarding even more optimization of the Qt-application development process and their advantages over native applications for iOS and Android.

    Also popular now: