Creating a headless app

Create the headless project

A headless app consists of two separate projects in the Momentics IDE for BlackBerry: a UI part and a headless part. You create these projects separately and then link them together to form the full headless app.

To create the headless part of the app, you start with a new Cascades project that uses the Standard empty project template, and then make modifications to the files that are included in that template. To learn how to create this type of project, see Create a new project.

Even if you're planning to create an app that doesn't use Cascades and uses only core APIs, you can still start by modifying a new Cascades project.

After you create this project, you need to modify the main.cpp, applicationui.hpp, and applicationui.cpp files. All of these files are located in the src folder of the project.

main.cpp

Here are the changes that you need to make to this file:

  • Include <bb/Application> instead of <bb/cascades/Application>. The template uses the Cascades version of the Application class (in the bb::cascades namespace), but a headless app uses the more generic version of Application.
  • Remove the specification of the bb::cascades namespace. Instead, add a using statement and specify bb::Application to make sure that the app references the correct Application class.
  • Remove the inclusion of Qt classes that support translation and debugging. You generally include translation and debugging support in the UI part of your app, and so these classes aren't required for the headless part.
  • Remove the Q_DECL_EXPORT macro from the main() function declaration. This macro is used for shared libraries in Qt and isn't required here.

Your main.cpp file should look similar to this:

#include <bb/Application>
#include "HeadlessApplication.hpp"

using bb::Application;

int main(int argc, char **argv)
{
    Application app(argc, argv);

    new HeadlessApplication(&app);

    return Application::exec();
}

applicationui.hpp

Here are the changes that you need to make to this file:

  • Change the file name to "HeadlessApplication.hpp" or something similar. This change isn't strictly required, but it can be helpful to rename this file to prevent any confusion about its purpose. This headless part of the app doesn't include any UI elements. Regardless of the file name that you choose to use, make sure to use the correct file name in other locations in your project (for example, in main.cpp).
  • Use the bb::system namespace instead of the bb::cascades namespace. The headless part doesn't use any Cascades classes, but it does use classes in the bb/system library (namely, the InvokeManager class).
  • Remove declarations that provide support for translation and locale changes. This includes QTranslator, onSystemLanguageChanged(), m_pTranslator, and m_pLocaleHandler.
  • Add a declaration for a private slot function called onInvoked(), as well as an InvokeManager private variable. These elements are used to handle invocation requests for the headless part of the app.

Your HeadlessApplication.hpp file should look similar to this:

#ifndef HeadlessApplication_HPP_
#define HeadlessApplication_HPP_

#include <bb/system/InvokeManager>
#include <bb/Application>
#include <QObject>

using namespace bb::system;

class HeadlessApplication : public QObject
{
    Q_OBJECT

public:
    HeadlessApplication(bb::Application *app);

private slots:
    void onInvoked(const bb::system::InvokeRequest& request);

private:
    InvokeManager* _invokeManager;
};

#endif /* HeadlessApplication_HPP_ */

applicationui.cpp

Here are the changes that you need to make to this file:

  • Change the file name to "HeadlessApplication.cpp". Similar to the change to the applicationui.hpp file above, a different name can help prevent confusion about this file's purpose. Make sure to use the same name as the corresponding .hpp file, and include that .hpp file in this .cpp file.
  • Remove the inclusion of Cascades classes. The headless part doesn't use any Cascades classes or other features.
  • Remove the prepopulated code from the constructor. Most of this code is used to handle the creation of a QML document from a .qml file in Cascades, which isn't required here. Instead, use the constructor to initialize the _invokeManager private variable that you declared earlier, set its parent to the current object, and connect its invoked() signal to the onInvoked() slot function.
  • Remove the definition of the onSystemLanguageChanged() function. This function is included to support translation, which isn't required in the headless part of the app.
  • Define the onInvoked() slot function, which is called when the headless app is invoked.

Your HeadlessApplication.cpp file should look similar to this:

#include "HeadlessApplication.hpp"

HeadlessApplication::HeadlessApplication(bb::Application *app) :
    QObject(app), _invokeManager(new InvokeManager())
{
    _invokeManager->setParent(this);

    connect(_invokeManager,
            SIGNAL(invoked(const bb::system::InvokeRequest&)),
            this,
            SLOT(onInvoked(const bb::system::InvokeRequest&)));
}

void HeadlessApplication::onInvoked(const bb::system::InvokeRequest& request)
{
    // When the headless app is invoked, this function is called.
    // Add your app's logic here.
    qDebug() << "Hello Headless App" << endl;
}

Modify the project structure

Because the headless part of the app uses the InvokeManager and bb::Application classes, you need to modify the .pro file in the project. This file is located in the root folder of the project and has the same name as the project (for example, "HeadlessPart.pro").

Add the following line to the .pro file:

LIBS += -lbbsystem -lbb

You should also remove cascades10 from the CONFIG line, because the headless part doesn't use any Cascades features.

To finish configuring the headless project, remove the bar-descriptor.xml file and the asset folder from the project. Neither of these are used in the headless part of the app.

Create the UI project

After you create the headless project and modify it to become the headless part of the app, you can create the UI part. To build your UI using core APIs, start with a Core Native project. If you want to create an app using Cascades APIs, see the Cascades version of Create the UI project.

Screen shot showing the choice between a Cascades app and a Core Native app in the IDE, with Core Native highlighted.

Add assets

To link the headless and UI parts of the app, you must add the headless part as an asset in the bar-descriptor.xml file of the UI part. You do this by using the <configuration> element for each launch configuration that you plan to use. You specify an entry point ID and use it to reference the binary of the headless part of the app.

In the project that you created for the UI part, open the bar-descriptor file and find the <configuration> element for a launch configuration that you want to modify (for example, the Device-Release configuration). Assuming that the project names are "HeadlessUI" and "HeadlessPart" for the UI part and headless part of the app, respectively, your configuration should look similar to the following:

<configuration name="Device-Debug">
    <platformArchitecture>armle-v7</platformArchitecture>
    <asset path ="arm/o.le-v7-g/HeadlessUI" entry="true" 
type="Qnx/Elf">HeadlessUI</asset>
    <asset entryPointId="HeadlessPart" 
path="../HeadlessPart/arm/HeadlessPart" 
type="Qnx/Elf">HeadlessPart</asset>
</configuration>

<configuration name="Device-Release">
    <entryPointType>Qnx/Cascades</entryPointType>
    <platformArchitecture>armle-v7</platformArchitecture>
    <asset path ="arm/o.le-v7-g/HeadlessUI.so" entry="true" 
type="Qnx/Elf">HeadlessUI.so</asset>
    <asset entryPointId="HeadlessPart" 
path="../HeadlessPart/arm/HeadlessPart" 
type="Qnx/Elf">HeadlessPart</asset>
</configuration>

<configuration name="Device-Profile">
    <platformArchitecture>armle-v7</platformArchitecture>
    <asset path ="arm/o.le-v7-g/HeadlessUI" entry="true" 
type="Qnx/Elf">HeadlessUI</asset>
    <asset entryPointId="HeadlessPart" 
path="../HeadlessPart/arm-p/HeadlessPart" 
type="Qnx/Elf">HeadlessPart</asset>
</configuration>

<configuration name="Simulator-Debug">
    <platformArchitecture>x86</platformArchitecture>
    <asset path ="x86/o-g/HeadlessUI" entry="true" 
type="Qnx/Elf">HeadlessUI</asset>
    <asset entryPointId="HeadlessPart" 
path="../HeadlessPart/x86/HeadlessPart" 
type="Qnx/Elf">HeadlessPart</asset>
</configuration>

To determine the location of the binary for the headless part of the app (which appears as the value of the path attribute in the entry point asset), consider the project structure that's illustrated in the image on the right. The headless part binary is generated in /arm/HeadlessPart, so to correctly reference this binary, a path of ../HeadlessPart/arm/HeadlessPart is used.

Screen shot showing the location of the binary for the headless part of an app.

Modify entry points

Before you can package the two parts as one application, you need to modify the entry points in the bar-descriptor.xml file of the UI part. This modification allows the UI and headless components of your app to use separate entry points.

The first entry point must refer to the UI part of the app:

<entryPoint id="HeadlessUI">
    <name>HeadlessUI</name>
</entryPoint>

The second entry point refers to the headless part:

<entryPoint id="HeadlessPart">
    <name>HeadlessPart</name>
    <entryPointType>Qnx/Elf</entryPointType>
</entryPoint>

Specify the appropriate permissions

Headless apps require the _sys_run_headless system permission and start when they are triggered. You specify this permission in the bar-descriptor.xml file of the UI part of the application:

<permission system="true">_sys_run_headless</permission>

Long-running headless apps require the _sys_headless_nostop system permission, as well as _sys_run_headless system permission, to run at all times. If you need to keep your headless app running indefinitely, add the following permission in the bar-descriptor.xml file of the UI part of the app:

<permission system="true">_sys_headless_nostop</permission>

For more information about app permissions and how to use them, see App permissions.

Add invocation framework support for triggers

The headless part of an app is started in response to a trigger. A trigger represents an event that your headless app should respond to, such as receiving a new message. To qualify as a headless app, your app must specify itself as an invocation target with the type application.headless, which allows it to be invoked in response to a trigger. To learn more about triggers and which ones are available, see Triggers.

You need to specify the invocation target for both the UI part and the headless part of your app. Here's an example of how to specify the invocation target for the UI part:

<invoke-target id="com.example.UI">
    <invoke-target-type>application</invoke-target-type>
    <invoke-target-name>HeadlessUI</invoke-target-name>
    <entry-point-id>HeadlessUI</entry-point-id>
</invoke-target>

Here's how to specify the invocation target for the headless part:

<invoke-target id="com.example.HEADLESSPORTION">
    <invoke-target-type>application.headless</invoke-target-type>
    <invoke-target-name>HeadlessPart</invoke-target-name>
    <entry-point-id>HeadlessPart</entry-point-id>
    <filter>
        <action>bb.action.system.STARTED</action>
        <mime-type>application/vnd.blackberry.system.event
                                             .STARTED</mime-type>
        <property var="uris" value="data://local"/>
    </filter>
</invoke-target>

Note that in the invocation target for the headless part, the system STARTED action is used in the filter. By using this action, the headless part of the app is invoked as soon as the app is installed on the device and the device is restarted.

Build and install the app

Now that you've created the UI and headless parts of the app and configured them properly, you can build the entire app and install it on a device. You need to build the headless part first, because the binary of the headless part is referenced by the UI part and needs to be available before the UI part can be built. After you build the headless part, you can build the UI part.

You don't install the headless part of the app on the device; you should install only the UI part.

If you're building your app using the Device-Release launch configuration, you need to sign your .bar file. Because the permission for headless apps is a system permission, signing is required when you build your app using a release launch configuration. If you don't sign your app, the app isn't granted the correct permissions to run properly.

If you're building your app using other configurations (such as Device-Debug), you don't need to sign your app before installing it. However, you still need to apply for and receive the appropriate permissions for headless apps to be able to deploy and test your app on a device. The debug token that you use to test your apps on a device contains the permissions that should apply to that app, and these permissions are populated based your signing account. When you apply for and receive headless app permissions (or other restricted app permissions), these permissions are added to your signing account. If you don't have these permissions, your headless app won't work properly when you deploy and test it on a device.

To receive signing keys for your application, complete the BlackBerry Keys Order Form.

Last modified: 2014-09-30



Got questions about leaving a comment? Get answers from our Disqus FAQ.

comments powered by Disqus