Develop and Configure

Version added 20-Jun-2018| Modified 11-Jun-2019

To create a native app, you must write the source code and prepare the required configuration files.

For easier understanding, the process to create a native app is explained using the example of an app named that has the following features:

  • Displays a "Hello, Native Qt Application" message on screen.

  • Calls com.webos.service.applicationmanager/registerApp method.

  • Prints log on /var/log/messages file when it is first launched.

  • Prints log with the updated parameter and status whenever the app is relaunched.

The directory structure of must be as follows:
├── main.cpp
├── ServiceRequest.h
├── ServiceRequest.cpp
├── appinfo.json
├── icon.png


Before you begin developing the native app, you must:

  • Build and flash the webOS OSE image. For detailed information, see Building webOS OSE and Flashing webOS OSE.

  • Create a project directory ( for the sample native app.

$ mkdir

Source Code

First, define the functionality of the native app on the source code.


Write a class that can register to luna-service2 and call registerApp() method of System and Application Manager (SAM). This header file has the function declaration.

  • Create and update the file : ServiceRequest.h

    • Directory :

#include <glib.h>
#include <string>
#include <luna-service2/lunaservice.h>
#include <pbnjson.hpp>
#include <PmLog.h>

static PmLogContext getPmLogContext()
    static PmLogContext s_context = 0;
    if (0 == s_context)
        PmLogGetContext("NativeQtApp", &s_context);
    return s_context;

class ServiceRequest
    ServiceRequest(std::string appId);
    virtual ~ServiceRequest();
    LSHandle* getHandle() const { return m_serviceHandle; }
    void registerApp();
    LSHandle* acquireHandle();
    void clearHandle();
    GMainLoop* m_mainLoop;
    LSHandle* m_serviceHandle;
    std::string m_appId;

A brief explanation of the above file:

  • Line(10~18) : A function that calls PmLogGetContext() in PmLog library to print log on /var/log/messages. For more details about pmlog, see Using Pmlog in C/C++.


Define SeviceRequest class methods. In addition, add methods related to PmLog and PbnJson to use conveniently.

  • Create and update the file : ServiceRequest.cpp

    • Directory :

#include "ServiceRequest.h"
static pbnjson::JValue convertStringToJson(const char *rawData)
    pbnjson::JInput input(rawData);
    pbnjson::JSchema schema = pbnjson::JSchemaFragment("{}");
    pbnjson::JDomParser parser;
    if (!parser.parse(input, schema))
        return pbnjson::JValue();
    return parser.getDom();
static std::string convertJsonToString(const pbnjson::JValue json)
    return pbnjson::JGenerator::serialize(json, pbnjson::JSchemaFragment("{}"));
ServiceRequest::ServiceRequest(std::string appId)
    : m_mainLoop(g_main_loop_new(nullptr, false))
    , m_serviceHandle(nullptr)
    m_appId = appId;
    m_serviceHandle = acquireHandle();
    if (m_mainLoop)
        g_main_loop_quit(m_mainLoop); // optional!
        m_mainLoop = nullptr;
LSHandle* ServiceRequest::acquireHandle()
    LSError lserror;
    LSHandle* handle = nullptr;
    if (!LSRegister(m_appId.c_str(), &handle, &lserror))
        LSErrorPrint(&lserror, stderr);
        return nullptr;       
    if (!LSGmainAttach(handle, m_mainLoop, &lserror))
        LSErrorPrint(&lserror, stderr);
        return nullptr;
    return handle;
void ServiceRequest::clearHandle()
    LSError lserror;
    if (m_serviceHandle)
        LSUnregister(m_serviceHandle, &lserror);
        m_serviceHandle = nullptr;
static bool registerAppCallback(LSHandle* sh, LSMessage* msg, void* ctx)
    PmLogInfo(getPmLogContext(), "REGISTER_CALLBACK", 1, PMLOGJSON("payload", LSMessageGetPayload(msg)),  " ");
    pbnjson::JValue response = convertStringToJson(LSMessageGetPayload(msg));
    bool successCallback = response["returnValue"].asBool();
    if (successCallback)
        std::string event = response["event"].asString();
        PmLogInfo(getPmLogContext(), "REGISTER_CALLBACK", 1, PMLOGKS("event", event.c_str()),  " ");
        if (event == "registered")
            //handle "registered" event
        else if (event == "relaunch")
            //handle "relaunch" event
            if (response.hasKey("parameters"))
                pbnjson::JValue launchParams = response["parameters"];
                PmLogInfo(getPmLogContext(), "REGISTER_CALLBACK", 1,
                            PMLOGJSON("parameters", convertJsonToString(launchParams).c_str()),  " ");
        else if (event == "close")
            //handle "close" event
        PmLogError(getPmLogContext(), "REGISTER_CALLBACK", 0, "RegisterApp Callback error" );
        // error handling..
    return true;
void ServiceRequest::registerApp()
    PmLogInfo(getPmLogContext(), "APP_REGISTER", 0, "RegisterApp called");
    LSError lserror;
    LSHandle* handle = getHandle();
    if (!handle)
        PmLogError(getPmLogContext(), "APP_REGISTER", 0, "LSHandle is NULL" );
    if (!LSCall(handle,
        LSErrorPrint(&lserror, stderr);

A brief explanation of the above file:

  • Line(3~18) : Create pbnjson utility functions, which convert String to Json and Json to String based on pbnjson library. pbnjson is a JSON engine, implemented as a pair of libraries with APIs for easier C and C++ abstraction.

  • Line(20~37) : Define constructor and destructor of ServiceRequest Class.

  • Line(39~68) : Define functions to register and unregister "" to and from luna-service. For more details about luna-service functions, see the Native services section.

  • Line(70~106) : Implement the callback function of registerApp.

    • Line(81~84) : When the app first calls the method, the value of event in response is "registered".

    • Line(85~94) : When the app is already running and SAM’s launch method is called, the value of event comes up as "relaunch". If the user gives a parameter of params when calling launch, the app can get the value of params with the property "parameters" in response.

    • Line(95~98) : When the app is closed by SAM's closeByAppId method, the value of event comes up as "close".

  • Line(108~129) : Call the registerApp() method of SAM.


For the sample native app (, you must:

  • Create and update the file : main.cpp

    • Directory :

#include "ServiceRequest.h"
#include <QApplication>
#include <QLabel>
#include <QDesktopWidget>
#include <QWindow>
#include <qpa/qplatformnativeinterface.h>
int main(int argc, char* argv[])
    PmLogInfo(getPmLogContext(), "MAIN_ARGV", 1, PMLOGJSON("argv[1]", argv[1]),  " ");

    QApplication app(argc, argv);
    QRect rec = QApplication::desktop()->screenGeometry();
    QLabel *label = new QLabel("Hello, Native Qt Application!!");
    label->setFixedSize(rec.width(), rec.height());
    QFont font = label->font();
    ServiceRequest s_request("");
    QWidget *widget = label->window();
    QWindow *window = widget->windowHandle();
    QApplication::platformNativeInterface()->setWindowProperty(window->handle(), QStringLiteral("appId"), QStringLiteral(""));
    return app.exec();

A brief explanation of the above file:

  • Line(1) : Include "ServiceRequest.h" header file which has methods that can call services based on luna-service2.

  • Line(2~6) : Include Qt header files.

  • Line(10) : argv[1] holds the value that SAM gives to the native app when the app is first launched. The value passed as "params" in SAM's launch method call can be received as "parameters", and the lifecycle "event" of the native app comes up as "launch".

  • Line(12~23) : Create QApplication and QLabel. Set label's position, font-size and style. After that, display the label.

  • Line(25~26) : Declare ServiceRequest object and call the registerApp() function.

  • Line(29~31) : Use QWindow::Handle() to get QPlatformWindow from QLabel. Set "appId" to the window.

  • Line(33) : Enters the main event loop and waits until exit() is called, then returns the value that was set to exit(): 0 if exit() is called via quit().

For detailed information on Qt, see Qt Documentation.

This file provides general information of the native app. For the sample native app (, you should:

  • Create and update the file :

    • Directory :

If the file is missing, a build error occurs.
Make sure the 'Summary' subsection is a single line. Even a blank space before the 'Description' section is considered a part of the summary and can cause the build to fail. 
Here is a snippet of the file that will not cause a build error. Any whitespace character in the red-colored line would cause a build error.

native app sample
(no blank space)

native app sample

native app sample

How to Build on Linux

## Dependencies

Below are the tools and libraries (and their minimum versions) required to build sample program:

* qmake

## Building

    $ cd build-webos
    $ source oe-init-build-env
    $ bitbake

Copyright and License Information
Unless otherwise specified, all content, including all source code files and
documentation files in this repository are:

Copyright (c) 2018 LG Electronics, Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
See the License for the specific language governing permissions and
limitations under the License.

SPDX-License-Identifier: Apache-2.0

Configuration Files

This section describes how to prepare the configuration files required to build and test the native app.


Apps are required to have metadata before they can be packaged. This metadata is stored in a file called appinfo.json, which is used by the webOS device to identify the app, its icon, and other information that is needed to launch the app. For the sample native app (, you must:

  • Create and update the file : appinfo.json

    • Directory :

    "id": "",
    "version": "0.1.0",
    "vendor": "My Company",
    "type": "native",
    "main": "nativeqt",
    "title": "Native qt App",
    "icon": "icon.png",
    "requiredPermissions" : ["applications"],
    "nativeLifeCycleInterfaceVersion": 2

A brief explanation of the above file:

  • Line(2) : The ID for the app.

  • Line(5) : The type of the native app.

  • Line(6) : The executable file name.

  • Line(7) : The title to be shown on the Home Launcher app.

  • Line(8) : The icon to be shown on the Home Launcher app. Make sure the icon file is available in the project root directory. You can use your own icon.png (80*80) file.

  • Line(9) : Specify the group to which the external service's method called by the app belongs. Because SAM's registerApp method belongs to "applications" group, put "applications" in this property. To check the group of each method, use ls-monitor command with "-i" option.

  • Line(10) : This field is required to use SAM's registerApp method.

For more details, see appinfo.json.

qmake Project File

This file specifies the application name and the qmake template to be used for generating the project, as well as the source, header, and UI files included in the project.

  • Create and update the file :

    • Directory :

TARGET = nativeqt
CONFIG += qt
QT += widgets gui-private
CONFIG += link_pkgconfig
PKGCONFIG += luna-service2 glib-2.0 pbnjson_cpp PmLogLib
SOURCES += ServiceRequest.cpp main.cpp
HEADERS += ServiceRequest.h 
target.path = $${INSTALL_APPDIR}
icon.path = $${INSTALL_APPDIR}
icon.files = icon.png
appinfo.path = $${INSTALL_APPDIR}
appinfo.files = appinfo.json
INSTALLS += target icon appinfo

A brief explanation of the above file:

  • Line(1) : Set TARGET name. It must be an executable file name of the app.

  • Line(3) : The CONFIG variable is a special variable that 'qmake' uses when generating a Makefile. qt is added to the list of existing values contained in CONFIG.

  • Line(4) : Link against the Qt Widgets Module. Add 'gui-private' to use private GUI include directories.

  • Line(6~7) : 'qmake' can configure the build process to take advantage of external libraries that are supported by pkg-config, such as the luna-servic2, glib, pbnjson, and PmLog libraries.

  • Line(9) : A list of source code files to be used when building the project.

  • Line(10) : A list of filenames of header (.h) files used when building the project.

  • Line(12) : Set installed directory on target board. INSTALL_APPDIR would be /usr/palm/applications/ on the target.

  • Line(14~20) : *.files specifies a path in project directory and *.path specifies the path to the file system to be installed on the target.

  • Line(22) : Add targets, icons, and appinfo files from the INSTALLS list.

For more details, see qmake Project Files.

Except as noted, this content is licensed under Creative Commons Attribution 4.0 and sample code is licensed under Apache License 2.0.