FORUMS
Remove All Ads from XDA

[TUTORIAL] How to create a C++ Qml Ubuntu Touch Application from start to end

58 posts
Thanks Meter: 36
 
By Hempe, Member on 5th May 2013, 04:54 PM
Post Reply Email Thread
How to create a C++ Qml Ubuntu Touch Application from start to end (now with easy setup)
(Including packaging and creating your own ppa)
Important! Only use lowercase for your project name otherwise your gonna have a lot of problems

I created a branch for easy access but I recommend you still read the tutorial.
So to create the basic environment you can use the following (with the rename.sh you change all the important values)
Code:
bzr branch lp:~hansueli-burri/+junk/CreateYourProject
cd CreateYourProject/
./rename.sh
1. Things you need before we start
2. How to start your Project?
Well the default templates didn't work for me so we create a custom project.
2.1. Create a new Folder (with the name of your project)
In my case apcalc-qml

2.2. Create a subfolder for your QML-files and a subfolder for your c++ files
In my case qml and cpp

2.3. Now we create a new Project-file
In my case apcalc-qml.pro

That looks something like this (When you create a new class it should be added automaticly if not you have to add it your self, like the applicationdata class)

apcalc-qml.pro
Code:
QT += qml quick
# If your application uses the Qt Mobility libraries, uncomment the following
# lines and add the respective components to the MOBILITY variable.
# CONFIG += mobility
# MOBILITY +=

#C++ source files
SOURCES +=  cpp/main.cpp\
            cpp/applicationdata.cpp\

#C++ header files
HEADERS  += cpp/applicationdata.h

#Path to the libraries...
INCLUDEPATH +=  $$PWD\
                $$PWD/../../../../usr/lib
DEPENDPATH += $$PWD/../../../../usr/lib

#Path to "other files" in this case the QML-Files
OTHER_FILES += \
    qml/main.qml\
    qml/basicCalc/*.qml
2.4. Now we should create the C++, Source, Header and QML files.

main.cpp
Code:

#include <QtGui/QGuiApplication>
#include <QGuiApplication>
#include <QQuickView>
#include <QtQml/qqmlcontext.h>
#include <stdio.h>
#include  "applicationdata.h"

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);
    QQuickView view;
    ApplicationData data;

    //Resize Mode so the content of the QML file will scale to the window size
    view.setResizeMode(QQuickView::SizeRootObjectToView);

    //With this we can add the c++ Object to the QML file
    view.rootContext()->setContextProperty("applicationData", &data);

    //Resolve the relativ path to the absolute path (at runtime)
    const QString qmlFilePath= QString::fromLatin1("%1/%2").arg(QCoreApplication::applicationDirPath(), "qml/main.qml");
    view.setSource(QUrl::fromLocalFile(qmlFilePath));

    //For debugging we print out the location of the qml file
    QByteArray ba = qmlFilePath.toLocal8Bit();
    const char *str = ba.data();
    printf("Qml File:%s\n",str);

    //Not sure if this is nessesary, but on mobile devices the app should start in fullscreen mode
    #if defined(Q_WS_SIMULATOR) || defined(Q_OS_QNX)
    view.showFullScreen();
    #else
    view.show();
    #endif
    return app.exec();
}
main.qml
Code:
import QtQuick 2.0
import Ubuntu.Components 0.1
import "basicCalc"
import QtQuick.Window 2.0
MainView {
    //objectName for functional testing purposes (autopilot-qt5)
    objectName: "mainView"
    applicationName: "apcalc-qml"
    automaticOrientation:true;
    width: units.gu(60);
    height: units.gu(100);
    id:root
    Tabs {
        objectName: "Tabs"
        ItemStyle.class: "new-tabs"
        anchors.fill: parent
        id:mainWindow;
        Tab {
            objectName: "Calculator"
            title: "Calculator"
            page:BasicCalc{
                width: root.width;
                height: root.height-root.header.height;
                anchors.top: parent.top;
                anchors.topMargin: root.header.height;
                onToCalculateChanged: {
                    //access to the c++ Object 
                    result=applicationData.calculate(toCalculate);
                }
            }
        }
    }
}
applicationdata.h
Code:
#ifndef APPLICATIONDATA_H
#define APPLICATIONDATA_H
#include <QObject>

class ApplicationData : public QObject
{
    Q_OBJECT
public:
    explicit ApplicationData(QObject *parent = 0);
    Q_INVOKABLE QString calculate(QString) const;
signals:
    
public slots:
};
#endif // APPLICATIONDATA_H
applicationdata.cpp
Code:
#include "applicationdata.h"
ApplicationData::ApplicationData(QObject *parent) :
    QObject(parent)
{
}
QString ApplicationData::calculate(QString command) const {
	// Some Logic comes here
	return command;
}
Those were the important files.
Never forget to mark your functions as Q_INVOKABLE otherwise you can't access them from within the qml file.
You can have a look at the other qm files at http://bazaar.launchpad.net/~hansuel...calc-qml/files
Before you can build your project we have to edit the build properties and add a custom build and clean up step. It should look something like this:



3. Packaging
Lets start with the easy things.
3.1. Create an App icon
Call it something like <YourProjectName>64.png
We will use this in the Desktop file.
3.2. Create a bin file <YourProjectName>.bin
It's a very simple textfile containing something like this, and nothing more.
Code:
/usr/share/<YourProjectName>/<YourBinaryName>
The Binary name will most probably be the same as your project name.
But It can be whatever you want because we create it in the rules file manually.

3.3. Create a desktop file
Here you got an example how to do it.
Code:
[Desktop Entry] 
Encoding=UTF-8 
Version=1.0 
Type=Application 
Terminal=false 
Name=<YourProjectName>
Exec=/usr/share/<YourProjectName>/<YourBinaryName> 
Icon=/usr/share/<YourProjectName>/<YourProjectName>64.png
StartupNotify=true 
X-Ubuntu-Touch=true 
X-Ubuntu-StageHint=SideStage
3.4.Debian packaging
First you create the debian folder in your project folder, containing the following files
  • changelog
  • control
  • copyright
  • install
  • compat
  • rules
and a Subfolder called source containing a file called format
The content of the format file should be:
Code:
3.0 (native)
The other files should contain the following. (for the original files go to http://bazaar.launchpad.net/~hansuel.../head:/debian/)

changelog
Here you can document your changes, changelog entries look something like:
Code:
<YourProjectName (0.1) raring; urgency=low 

  * initial release 

 -- <Full OpenPGP Identifier (Full name and email address)>  Sat, 4 April 2013 00:00:00 +0200
for more information google it.

control
Here you put your build dependencies, dependencies for running your application, your homepage, discription and so on.
I think all the Build-Depends listed bellow are nessesary to successfully compile and build the qt5 qml project but correct me if I'm wrong.
Code:
Source: <YourProjectName>
Priority: extra 
Maintainer: <Full OpenPGP Identifier (Full name and email address)> 
Build-Depends: debhelper (>= 9),
	       qtbase5-dev,
               qtdeclarative5-dev,
               qt5-default,
	       <YourBuildDependencies>
Standards-Version: 3.9.4
Section: misc
Homepage: <YourHomePage>

Package: <YourPackageName>
Section: misc
Architecture: any
Multi-Arch: same
Pre-Depends: ${misc:Pre-Depends}
Depends: ${shlibs:Depends}, ${misc:Depends},
         qtdeclarative5-ubuntu-ui-toolkit-plugin | qt-components-ubuntu,
         qtdeclarative5-qtquick2-plugin,
	<YourRunningDependencies>
Description: <YourShortDescription>
<YourLongDescription>
copyright
Here you put licencing information mine looks like this
Code:
Format: http://dep.debian.net/deps/dep5 
Upstream-Name: <YourPackageName>
Source: 

Files: * 
Copyright: 2013 <YourName>
License: GPL-3.0 

Files: debian/* 
Copyright: 2013 <YourName>
License: LGPL-3.0 

License: GPL-3.0 
 This package is free software; you can redistribute it and/or 
 modify it under the terms of the GNU General Public 
 License as published by the Free Software Foundation; either 
 version 3 of the License. 
 . 
 This package is distributed in the hope that it will be useful, 
 but WITHOUT ANY WARRANTY; without even the implied warranty of 
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
 General Public License for more details. 
 . 
 You should have received a copy of the GNU General Public License 
 along with this program. If not, see <http://www.gnu.org/licenses/>. 
 . 
 On Debian systems, the complete text of the GNU General 
 Public License can be found in "/usr/share/common-licenses/GPL-3". 

License: LGPL-3.0 
 This package is free software; you can redistribute it and/or 
 modify it under the terms of the GNU Lesser General Public 
 License as published by the Free Software Foundation; either 
 version 3 of the License. 
 . 
 This package is distributed in the hope that it will be useful, 
 but WITHOUT ANY WARRANTY; without even the implied warranty of 
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
 Lesser General Public License for more details. 
 . 
 You should have received a copy of the GNU General Public License 
 along with this program. If not, see <http://www.gnu.org/licenses/>. 
 . 
 On Debian systems, the complete text of the GNU Lesser General 
 Public License can be found in "/usr/share/common-licenses/LGPL-3".
Install
If someone knows what this is needed for please tell me, cause I don't know, but with the following content everything will work;
Code:
usr/share/applications 
usr/bin 
usr/share/<YourProjectName>
compat
It just contains an 8, I also don't know why.
Code:
8
rules
This is a rather important file. Because here we define some of the logic to deploy the package.
Mine looks like this. You have to add all the files that need to be copied.
To understand what it does:
The content of $(CURDIR)/debian/tmp/usr/share/<YourProjectName> for example will be copied to /usr/share/<YourProjectName> when you install the package.
Code:
#!/usr/bin/make -f
# -*- makefile -*-
# Sample debian/rules that uses debhelper.
# This file was originally written by Joey Hess and Craig Small.
# As a special exception, when this file is copied by dh-make into a
# dh-make output file, you may use that output file without restriction.
# This special exception was added by Craig Small in version 0.37 of dh-make.

# Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1

# Work-around for some machines where INSTALL_ROOT is not set properly by
# dh_auto_install
override_dh_auto_install:
	dh_auto_install -- INSTALL_ROOT=$(CURDIR)/debian/tmp

# Workaround a bug in that debhelper package version
override_dh_install:
	mkdir -p $(CURDIR)/debian/tmp/usr/share/applications/
	mkdir -p $(CURDIR)/debian/tmp/usr/bin/
	mkdir -p $(CURDIR)/debian/tmp/usr/share/apcalc-qml/
	mkdir -p $(CURDIR)/debian/tmp/usr/share/apcalc-qml/
	cp apcalc-qml.desktop $(CURDIR)/debian/tmp/usr/share/applications/
	cp apcalc-qml $(CURDIR)/debian/tmp/usr/share/apcalc-qml/apcalc-qml
	cp *.png $(CURDIR)/debian/tmp/usr/share/apcalc-qml/
	cp apcalc-qml.bin $(CURDIR)/debian/tmp/usr/bin/apcalc-qml
	cp -r qml/ $(CURDIR)/debian/tmp/usr/share/apcalc-qml/
	
	
	dh_install --sourcedir=debian/tmp --fail-missing

%:
	dh $@
4. Upload everything to Lauchpad
You can push (upload) personal branches (those not related to a project) with the following command:
bzr push lp:~YOUR_LAUNCHPAD_NAME/+junk/BRANCHNAME
(... more information if requested)

5. Create a recipe and test it
5.1. Setup pbuilder
First of you need to install pbuilder and modify or create ~/.pbuilderrc
Code:
# Codenames for Debian suites according to their alias. Update these when
# needed.
UNSTABLE_CODENAME="saucy"
TESTING_CODENAME="saucy"
STABLE_CODENAME="raring"
STABLE_BACKPORTS_SUITE="$STABLE_CODENAME-backports"

# List of Debian suites.
DEBIAN_SUITES=($UNSTABLE_CODENAME $TESTING_CODENAME $STABLE_CODENAME
    "unstable" "testing" "stable")

# List of Ubuntu suites. Update these when needed.
UBUNTU_SUITES=(“saucy",”raring" "quantal" "precise" "oneiric" "natty" "lucid" "hardy")

# Mirrors to use. Update these to your preferred mirror.
DEBIAN_MIRROR="ftp.us.debian.org"
UBUNTU_MIRROR="mirrors.kernel.org"

# Optionally use the changelog of a package to determine the suite to use if
# none set.
if [ -z "${DIST}" ] && [ -r "debian/changelog" ]; then
    DIST=$(dpkg-parsechangelog | awk '/^Distribution: / {print $2}')
    # Use the unstable suite for Debian experimental packages.
    if [ "${DIST}" == "experimental" ]; then
        DIST="unstable"
    fi
fi

# Optionally set a default distribution if none is used. Note that you can set
# your own default (i.e. ${DIST:="unstable"}).
: ${DIST:="$(lsb_release --short --codename)"}

# Optionally change Debian codenames in $DIST to their aliases.
case "$DIST" in
    $UNSTABLE_CODENAME)
        DIST="unstable"
        ;;
    $TESTING_CODENAME)
        DIST="testing"
        ;;
    $STABLE_CODENAME)
        DIST="stable"
        ;;
esac

# Optionally set the architecture to the host architecture if none set. Note
# that you can set your own default (i.e. ${ARCH:="i386"}).
: ${ARCH:="$(dpkg --print-architecture)"}

NAME="$DIST"
if [ -n "${ARCH}" ]; then
    NAME="$NAME-$ARCH"
    DEBOOTSTRAPOPTS=("--arch" "$ARCH" "${DEBOOTSTRAPOPTS[@]}")
fi
BASETGZ="/var/cache/pbuilder/$NAME-base.tgz"
DISTRIBUTION="$DIST"
BUILDRESULT="/var/cache/pbuilder/$NAME/result/"
APTCACHE="/var/cache/pbuilder/$NAME/aptcache/"
BUILDPLACE="/var/cache/pbuilder/build/"

if $(echo ${DEBIAN_SUITES[@]} | grep -q $DIST); then
    # Debian configuration
    MIRRORSITE="http://$DEBIAN_MIRROR/debian/"
    COMPONENTS="main contrib non-free"
    if $(echo "$STABLE_CODENAME stable" | grep -q $DIST); then
        EXTRAPACKAGES="$EXTRAPACKAGES debian-backports-keyring"
        OTHERMIRROR="$OTHERMIRROR | deb http://www.backports.org/debian $STABLE_BACKPORTS_SUITE $COMPONENTS"
    fi
elif $(echo ${UBUNTU_SUITES[@]} | grep -q $DIST); then
    # Ubuntu configuration
    MIRRORSITE="http://$UBUNTU_MIRROR/ubuntu/"
    COMPONENTS="main restricted universe multiverse"
else
    echo "Unknown distribution: $DIST"
    exit 1
fi
5.2. How to use pbuilder?
Create a base environment for Ubuntu raring
Code:
sudo DIST=raring pbuilder create
Update a base environment for Ubuntu raring
Code:
sudo DIST=raring pbuilder update
Build package for Ubuntu raring
Code:
sudo DIST=raring pbuilder build <working-dir>/<application_name>.dsc
5.3. Content of the recipe
It can be as simple as this.
Code:
# bzr-builder format 0.3 deb-version 0.1~{revno}
lp:~YOUR_LAUNCHPAD_NAME/+junk/BRANCHNAME
(... more information if requested)

6. Create PPA
Now you just need to create your ppa as explaind on launchpad.
Important by default your ppa will not build for arm. you have to ask a question on launchpad to request that your ppa will be build for arm as well.
(... more information if requested)
The Following 9 Users Say Thank You to Hempe For This Useful Post: [ View ] Gift Hempe Ad-Free
 
 
5th May 2013, 07:59 PM |#2  
blmvxer's Avatar
Senior Member
Thanks Meter: 617
 
Donate to Me
More
Sweet! Thank you!!

Sent from my LG-LS970 using xda app-developers app
5th May 2013, 11:36 PM |#3  
Member
Thanks Meter: 0
 
More
Awesome work! I was waiting for this kind of tutorial.
thanks for that!
6th May 2013, 07:17 PM |#4  
OP Member
Flag Luzern
Thanks Meter: 36
 
More
Wink
Quote:

Awesome work! I was waiting for this kind of tutorial.
thanks for that!

I was waiting on a tutorial as well, but nobody seed to be intrested in creating one
8th May 2013, 03:07 PM |#5  
imax27's Avatar
Junior Member
Flag Sumy
Thanks Meter: 2
 
More
Can I use Java language for creating program?
9th May 2013, 09:10 AM |#6  
gianguido's Avatar
Senior Member
Flag Caserta
Thanks Meter: 23
 
More
Quote:
Originally Posted by imax27

Can I use Java language for creating program?

Please no.
BTW no, really, Ubuntu (luckily) supports only C++ and C languages

Sent from my Nexus 4 using xda premium
24th February 2016, 07:59 AM |#7  
Member
Thanks Meter: 6
 
More
Hi guys, how can I pack this into .click package for Ubuntu Touch?
Post Reply Subscribe to Thread

Tags
cpp, tutorial, ubuntu touch

Guest Quick Reply (no urls or BBcode)
Message:
Previous Thread Next Thread
Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes