Building and Deploying Qt Applications to the Playbook
It is actually very easy to build and deploy Qt applications to the Playbook. The process is very similar to building any other Qt application. The only differences arise in packaging the application and the deployment steps which we will detail here.
About the Playbook Packaging System
To deploy an application to the Playbook we need to create a package called a bar file. A bar file is basically an archive file that contains the directory structure for your application and any additional resources that it needs. When developing an application we create a bar file using our debug token that we made earlier. This allows the bar file to be deployed only to the device that holds that debug token. The command line tools to package and deploy your application are included the BBNDK that we have already installed.
The approach we will take is to modify the .pro file for your project to add an additional Makefile target that will create the bar file for you.
Preparing Your Project File
Before we begin building your application we need to edit the .pro qmake project file to include some directives to help us package up our applications ready for deployment. Here is an example .pro file for a very simple hello world Qt 5 application that uses QtQuick2:
TEMPLATE = app
TARGET = helloqtquick2
DEPENDPATH += .
INCLUDEPATH+= .
QT += qml quick
SOURCES+= main.cpp
RESOURCES += helloqtquick2.qrc
OTHER_FILES+= main.qml
qnx {
QMAKE_LFLAGS += '-Wl,-rpath,#39;./app/native/lib#39;'
PACKAGE_ARGS = $${PWD}/bar-descriptor.xml $$TARGET -e $${PWD}/icon.png res/icon.png -e $$[QT_INSTALL_LIBS]/libQtCore.so.5 lib/
libQtCore.so.5 -e
$$[QT_INSTALL_LIBS]/libQtGui.so.5 lib/libQtGui.so.5 -e $$[QT_INSTALL_LIBS]/libQtOpenGL.so.5 lib/libQtOpenGL.so.5 -e $$[QT_INSTALL_LIBS]/
libQtNetwork.so.5
lib/libQtNetwork.so.5 -e $$[QT_INSTALL_LIBS]/libQtWidgets.so.5 lib/libQtWidgets.so.5 -e $$[QT_INSTALL_LIBS]/libQtQuick.so.5 lib/
libQtQuick.so.5 -e
$$[QT_INSTALL_LIBS]/libQtQml.so.5 lib/libQtQml.so.5 -e $$[QT_INSTALL_LIBS]/libQtSql.so.5 lib/libQtSql.so.5 -e $$[QT_INSTALL_LIBS]/libQtV8.so.5
lib/libQtV8.so.5 -e $$[QT_INSTALL_LIBS]/libQtXmlPatterns.so.5 lib/libQtXmlPatterns.so.5 -e $$[QT_INSTALL_PLUGINS]/platforms/libqnx.so
plugins/platforms/libqnx.so -e $$[QT_INSTALL_IMPORTS]/ qml/
package.target = $${TARGET}.bar
package.depends = $$TARGET
package.commands = blackberry-nativepackager -package $${TARGET}.bar -devMode -debugToken $$(DEBUG_TOKEN) $${PACKAGE_ARGS}
QMAKE_EXTRA_TARGETS+= package
OTHER_FILES += bar-descriptor.xml
}
Now that looks scary at first sight but it's actually pretty simple to see what is going on in there. At the top of the file we have the usual qmake variables that can be found in pretty much any Qt project. The interesting stuff for our purposes here is found within the qnx {} scope. Let's break it down into easy steps.
First of all we have the line:
QMAKE_LFLAGS+= '-Wl,-rpath,#39;./app/native/lib#39;'
This tells the linker that when the application is executed on the device it should additionally look for libraries inside the directory ./app/native/lib relative to the application.
We then define a variable called PACKAGE_ARGS with:
PACKAGE_ARGS = $${PWD}/bar-descriptor.xml $$TARGET -e $${PWD}/icon.png res/icon.png -e $$[QT_INSTALL_LIBS]/libQtCore.so.5 lib/libQtCore.so.5
-e
$$[QT_INSTALL_LIBS]/libQtGui.so.5 lib/libQtGui.so.5 -e $$[QT_INSTALL_LIBS]/libQtOpenGL.so.5 lib/libQtOpenGL.so.5 -e $$[QT_INSTALL_LIBS]/
libQtNetwork.so.5
lib/libQtNetwork.so.5 -e $$[QT_INSTALL_LIBS]/libQtWidgets.so.5 lib/libQtWidgets.so.5 -e $$[QT_INSTALL_LIBS]/libQtQuick.so.5 lib/libQtQuick.so.5
-e
$$[QT_INSTALL_LIBS]/libQtQml.so.5 lib/libQtQml.so.5 -e $$[QT_INSTALL_LIBS]/libQtSql.so.5 lib/libQtSql.so.5 -e $$[QT_INSTALL_LIBS]/libQtV8.so.5
lib/libQtV8.so.5 -e $$[QT_INSTALL_LIBS]/libQtXmlPatterns.so.5 lib/libQtXmlPatterns.so.5 -e $$[QT_INSTALL_PLUGINS]/platforms/libqnx.so
plugins/platforms/libqnx.so -e $$[QT_INSTALL_IMPORTS]/ qml/
This contains the arguments that will be passed to the command line tool that will actually create our application's package (the .bar file). This variable contains a few interesting parts:
- The bar-descriptor.xml file is a simple XML file that describes our package and how it should be launched. Many of the other arguments listed here can optionally be specified inside the bar-descriptor.xml file instead.
- Then what follows are a lot of -e <source> <dest> directives. These just tell the packaging tool to copy the <source> location to <dest> inside of the bar file and hence to <dest> within the application's sandbox when deployed onto the device.
Note that the icon needs to be 86x86 pixels.
For now we have to do this manually as Qt 5 is not part of the Playbook's firmware image yet and Qt Creator does not yet have an automatic way of determining what should go into your .bar file. This situation should improve shortly.
The last section of the .pro file creates the actual Makefile target for us:
package.target = $${TARGET}.bar
package.depends = $$TARGET
package.commands = blackberry-nativepackager -package $${TARGET}.bar -devMode -debugToken $$(DEBUG_TOKEN) $${PACKAGE_ARGS}
QMAKE_EXTRA_TARGETS += package
where $$(DEBUG_TOKEN) is an environment variable that you need to set that points at the path to your debug token. For example on Linux you could do:
export DEBUG_TOKEN="$HOME/.rim/debugtoken.bar"
You should be able to pretty much copy and paste the above into your own .pro files to adapt it to additionally create a Playbook bar file package.
To go along with the above .pro file we need a bar-descriptor.xml file. Here is a fairly typical example:
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<qnx >
<id>com.kdab.helloqtquick2</id>
<filename>helloqtquick2</filename>
<name>Hello QtQuick2</name>
<versionNumber>1.0.0</versionNumber>
<buildId>1</buildId>
<description>Hello QtQuick2</description>
<copyright>2012</copyright>
<initialWindow>
<systemChrome>none</systemChrome>
<transparent>false</transparent>
<autoOrients>true</autoOrients>
<aspectRatio>landscape</aspectRatio>
</initialWindow>
<publisher>KDAB</publisher>
<permission system="true">run_native</permission>
<env var="LD_LIBRARY_PATH" value="app/native/lib"/>
<env var="QT_PLUGIN_PATH" value="app/native/plugins"/>
<env var="QML_IMPORT_PATH" value="app/native/imports"/>
<env var="QML2_IMPORT_PATH" value="app/native/qml"/>
<category>core.games</category>
<icon><image>res/icon.png</image></icon>
</qnx>
The fields are fairly self-explanatory but more information can be found here
Building and packaging
To build and package our application is now simplicity itself. All we have to do is:
$ qmake
$ make -j<N>
$ make <app-name>.bar
where <app-name> is the name of your application. In this case it would be make helloqtquick2.bar. You should now have a .bar file in your build directory ready to be deployed.
Deploying and Running
To deploy your bar file to the Playbook we use another tool included in the BBNDK called blackberry-deploy. The syntax for this tool is:
$ blackberry-deploy -installApp -device <device-ip> -password <device-password> <appname>.bar
Once this tool has executed you should see your application icon in the launcher of the Playbook. The console output of the application is saved in the /accounts/1000/appdata/*APPNAME*/logs/log file on the device.
Removing an application from the device or simulator
Open a command prompt windows, and then type:
$ blackberry-deploy -uninstallApp -device <device-ip> -package <appname>.bar -password <device-password>
Deploying Qt to a central place
The method described above copies Qt into the application's BAR package, which increases its size considerably and makes deploying really slow. For development, it is useful to have Qt preinstalled on the device. See this article on how to install Qt to a central place
Of course you also need to undo the changes to the .pro file above, so that Qt is not added to the BAR package automatically. Also, the above bar-descriptor.xml file already contains lines that set environment variables, these need to be overwritten with those lines mentioned in the article.