Roman Ozhegov
Roman Ozhegov

Reputation: 230

Qt QBS and android

I'm trying to find a simple tutorial: how to make a simple application for android using gbps. The following links were found:

  1. Stack oferflow. The answer to this question has not been received, although the version of the cbs has already been updated to 1.11 and the support of android is included.
  2. AndroidApk Item in QBS Documentation. In this case I get warning: '../Application/src/main/AndroidManifest.xml' does not exist.

I unfortunately could not find any new information. I ask for help.

Update: For Qmake I just create standard widget project like this one:

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = androidtest
TEMPLATE = app

DEFINES += QT_DEPRECATED_WARNINGS

SOURCES += \
        main.cpp \
        mainwindow.cpp

HEADERS += \
        mainwindow.h

FORMS += \
        mainwindow.ui

CONFIG += mobility
MOBILITY = 

And this is works and builds fine. QtCreator automatically create all necessary files and than run app on my phone

In Qbs I try to make same application. For this reason I have QBS-file:

import qbs

Project {
    CppApplication {
        name: "helloworld"

        Depends {
            name: "Qt"
            submodules: [
                "core",
                "widgets"
            ]
        }

        Depends { name: "Android.ndk" }
        Android.ndk.appStl: "gnustl_shared"

        Group {
            name: "src"
            files: [
                "main*.*"

            ]
        }
    }

    AndroidApk {
        name: "helloworld_android"
        Depends {name: "helloworld" }
        packageName: "com.example.android.helloworld"
    }
}

At the end I have Done with HelloWorld product (libhelloworld.so). But first error of "helloworld_android" is a fail at android manifest. This file is undefined. What I should do next?

Upvotes: 0

Views: 660

Answers (3)

mardy
mardy

Reputation: 176

QBS 1.13, released on February this year (2019) makes deploying an Android application as simple as with qmake. In practice, you don't need to do anything special. For example, I took the contactlist application from the Qt examples and added this QBS file:

import qbs 1.0

Project {
    QtGuiApplication {
        name: "contactlist"
        install: true

        files: [
            "contactmodel.h",
            "contactmodel.cpp",
            "main.cpp",
        ]

        Group {
            files: [
                "*.qml",
                "designer/Backend/*.qml",
                "designer/Backend/qmldir",
            ]
            fileTags: ["qt.core.resource_data"]
        }

        Depends { name: "Qt.quick" }
    }
}

As you can see, there's nothing specific to Android here. The only trick I'm using is to assign the tag qt.core.resource_data to the QML files in order to have them compiled as resource files — but it's not even required.

With qbs run the application will be run in your connected Android device.

Upvotes: 1

Roman Ozhegov
Roman Ozhegov

Reputation: 230

Ok, I think I made it. It's not a good solution but this is work. Resulting APK you can find in "\install-root\$productName$\build\outputs\apk\$productName$-debug.apk

import qbs
import qbs.TextFile
import qbs.Process
import qbs.File

Project {
    //Main Application
    CppApplication {
        name: "helloworld";

        Depends {
            name: "Qt"
            submodules: [
                "core",
                "widgets"
            ]
        }

        Depends { name: "Android.ndk" }
        Android.ndk.appStl: "gnustl_shared"

        Group {
            name: "src"
            files: [
                "main*.*"
            ]
        }
        Group {
            qbs.install: true
            fileTagsFilter: "dynamiclibrary"
            qbs.installPrefix : product.name+"/libs/"+Android.ndk.abi+"/"
        }
    }

    //Preparation
    Product {
        name: "Prepared2Deploy"
        type: "prepared2deploy"
        Depends { name: "helloworld" }
        Depends { name: "Qt.core" }
        Depends { name: "Android.ndk" }
        Depends { name: "Android.sdk" }
        Rule {
            inputsFromDependencies: "installable"
            Artifact {
                filePath: input.fileName+".json"
                fileTags: "prepared2deploy"
            }
            prepare: {
                var cmd = new JavaScriptCommand();
                cmd.description = "prepare for androidDeployQt";
                cmd.highlight = "install";
                cmd.sourceCode = function() {
                    var outputFile = new TextFile(output.filePath, TextFile.WriteOnly);
                    outputFile.writeLine("{");
                    outputFile.writeLine("     \"qt\": \"" + product.Qt.core.binPath.replace(/\/bin$/,"") + "\",");
                    outputFile.writeLine("     \"sdk\": \"" + product.Android.sdk.sdkDir + "\",");
                    outputFile.writeLine("     \"sdkBuildToolsRevision\": \"" + product.Android.sdk.buildToolsVersion + "\",");
                    var ndkDir = product.Android.ndk.ndkDir.replace(/\\/g,"/"); //why sdk ndk get wrong slashes?
                    outputFile.writeLine("     \"ndk\": \""+ndkDir+"\",");
                    var toolchain =  product.cpp.toolchainPrefix.replace(/-$/,"");
                    outputFile.writeLine("     \"toolchain-prefix\": \"" + toolchain + "\",");
                    outputFile.writeLine("     \"tool-prefix\": \"" + toolchain + "\",");
                    outputFile.writeLine("     \"toolchain-version\": \"4.9\",");   //how I can get it ???
                    outputFile.writeLine("     \"ndk-host\": \"windows-x86_64\","); //how I can get it ???
                    var abi = product.Android.ndk.abi
                    outputFile.writeLine("     \"target-architecture\": \""+abi+"\",");
                    outputFile.writeLine("     \"stdcpp-path\": \""+ndkDir+"/sources/cxx-stl/gnu-libstdc++/4.9/libs/" + //how I can get it ???
                                         abi+"/lib"+product.Android.ndk.appStl+".so\",");
                    outputFile.writeLine("     \"application-binary\": \""+ input.filePath+"\"");
                    outputFile.writeLine("}");
                    outputFile.close();
                }
                return cmd;
            }
        }
    }
    //Deployer
    Product {
        name: "AndroidDeployQt"
        Depends { name: "helloworld" }
        id: androidDeployQt
        type: "androidDeployQt"
        Depends {name: "Qt.core" }

        Rule {
            inputsFromDependencies: "prepared2deploy"
            alwaysRun: true
            Artifact {
                filePath: "log.txt"
                fileTags: "androidDeployQt"
            }
            prepare: {
                var cmd = new JavaScriptCommand();
                cmd.description = "androidDeployQt";
                cmd.highlight = "install";
                cmd.sourceCode = function() {
                    var logFile = new TextFile(output.filePath, TextFile.WriteOnly);
                    logFile.writeLine(input.fileName);
                    var productName = input.fileName.replace(/.so.json$/,"").replace(/^(lib)/,"");
                    var androidDeployProcess = new Process();
                    var exitCode = androidDeployProcess.exec(product.Qt.core.binPath+"/androiddeployqt.exe",
                                                             [
                                                                 "--input", input.filePath,
                                                                 "--output", project.buildDirectory+"/install-root/"+productName,
                                                                 "--android-platform", "android-25", //???
                                                                 "--gradle"
                                                             ])
                    if (exitCode) {
                        console.error("Error at androidDeployProcess. Error code: "+exitCode);
                        console.error(androidDeployProcess.readStdErr());
                        console.error("FULL_LOG: ");
                        console.error(androidDeployProcess.readStdOut());
                    }
                    logFile.close();
                }
                return cmd;
            }
        }
    }
}

Upvotes: 0

Christian Kandeler
Christian Kandeler

Reputation: 831

qmake has some built-in magic when building for Android, like using resources provided by Qt (including a manifest template) and running the android-deployqt tool. None of this is currently done by qbs.

Upvotes: 1

Related Questions