Qt for HarmonyOS Notification Example
Posts a notification from a Qt application on HarmonyOS.
The example asks the user to allow notifications for the application. It then posts a notification with the title and text entered in its window. It uses the platform's @ohos.notificationManager module.
The button handlers hand the work to the JS thread. The title and text are collected on the Qt thread as a QJsonObject:
QObject::connect(
allowNotificationsButton, &QPushButton::clicked, &window,
[statusLabel]() {
statusLabel->clear();
QHarmonyApplication::runOnJsThread(
[statusLabel = QPointer<QLabel>(statusLabel)](QHarmonyJsContext &jsContext) {
askUserToAllowNotifications(QHarmonyAppJsContext::fromJsContext(jsContext), statusLabel);
});
});
QObject::connect(
postNotificationButton, &QPushButton::clicked, &window,
[notificationTitleEdit, notificationTextEdit, statusLabel]() {
const QJsonObject titleAndText{
{QStringLiteral("title"), notificationTitleEdit->text()},
{QStringLiteral("text"), notificationTextEdit->text()},
};
statusLabel->clear();
QHarmonyApplication::runOnJsThread(
[titleAndText, statusLabel = QPointer<QLabel>(statusLabel)](QHarmonyJsContext &jsContext) {
postNotification(jsContext, titleAndText, statusLabel);
});
});requestEnableNotification() shows the platform dialog in which the user allows notifications. It takes the UIAbilityContext of the default ability, and the dialog is bound to that context:
void askUserToAllowNotifications(QHarmonyAppJsContext &appJsContext, QPointer<QLabel> statusLabel)
{
const QString asyncCallName = QStringLiteral("requestEnableNotification()");
Napi::Env env(appJsContext.env());
Napi::Object notificationManagerModule(env, appJsContext.tryImportModule(notificationManagerModuleName));
if (notificationManagerModule.IsEmpty()) {
showFailureInLabel(statusLabel, asyncCallName, QStringLiteral("no notification manager module"));
return;
}
Napi::Object ability(env, appJsContext.defaultAbility());
if (ability.IsEmpty()) {
showFailureInLabel(statusLabel, asyncCallName, QStringLiteral("no ability to request from"));
return;
}
try {
auto abilityContext = ability.Get("context").As<Napi::Object>();
auto requestEnableNotificationFunc = notificationManagerModule.Get("requestEnableNotification").As<Napi::Function>();
auto requestEnableNotificationPromise = requestEnableNotificationFunc.Call(notificationManagerModule, {abilityContext}).As<Napi::Object>();
attachPromiseHandlersReportingStatusInLabel(requestEnableNotificationPromise, asyncCallName, statusLabel);
} catch (const Napi::Error &error) {
showFailureInLabel(statusLabel, asyncCallName, QString::fromUtf8(error.what()));
}
}publish() takes a notification request, which the task builds on the JS thread. The content type comes from the ContentType enumeration of the module. The title and text are mapped from the QJsonObject with QtHarmony::mapQJsonObjectToJsObject():
void postNotification(QHarmonyJsContext &jsContext, const QJsonObject &titleAndText, QPointer<QLabel> statusLabel)
{
const QString asyncCallName = QStringLiteral("publish()");
Napi::Env env(jsContext.env());
Napi::Object notificationManagerModule(env, jsContext.tryImportModule(notificationManagerModuleName));
if (notificationManagerModule.IsEmpty()) {
showFailureInLabel(statusLabel, asyncCallName, QStringLiteral("no notification manager module"));
return;
}
try {
auto basicTextContentType = notificationManagerModule.Get("ContentType").As<Napi::Object>().Get("NOTIFICATION_CONTENT_BASIC_TEXT");
Napi::Object jsTitleAndText(env, QtHarmony::mapQJsonObjectToJsObject(env, titleAndText));
auto notificationContent = Napi::Object::New(env);
notificationContent.Set("notificationContentType", basicTextContentType);
notificationContent.Set("normal", jsTitleAndText);
auto notificationRequest = Napi::Object::New(env);
notificationRequest.Set("content", notificationContent);
auto publishFunc = notificationManagerModule.Get("publish").As<Napi::Function>();
auto publishPromise = publishFunc.Call(notificationManagerModule, {notificationRequest}).As<Napi::Object>();
attachPromiseHandlersReportingStatusInLabel(publishPromise, asyncCallName, statusLabel);
} catch (const Napi::Error &error) {
showFailureInLabel(statusLabel, asyncCallName, QString::fromUtf8(error.what()));
}
}Both calls return a promise. The handlers attached to the promise report the outcome in the window. They post the text to the Qt thread with QNativeInterface::QHarmonyApplication::runOnQtThread(). They pass a QPointer to the status label, which was created on the Qt thread. The posted functor checks the QPointer before it updates the label:
void showStatusInLabel(QPointer<QLabel> statusLabel, QString text)
{
QHarmonyApplication::runOnQtThread(
[statusLabel, text]() {
if (statusLabel)
statusLabel->setText(text);
});
}
void showFailureInLabel(QPointer<QLabel> statusLabel, const QString &asyncCallName, const QString &errorText)
{
showStatusInLabel(statusLabel, QStringLiteral("%1 failed: %2").arg(asyncCallName, errorText));
}
void attachPromiseHandlersReportingStatusInLabel(Napi::Object asyncCallPromise, const QString &asyncCallName, QPointer<QLabel> statusLabel)
{
asyncCallPromise.Get("then").As<Napi::Function>().Call(
asyncCallPromise,
{
Napi::Function::New(
asyncCallPromise.Env(),
[statusLabel, asyncCallName](const Napi::CallbackInfo &) {
showStatusInLabel(statusLabel, QStringLiteral("%1 succeeded").arg(asyncCallName));
}),
Napi::Function::New(
asyncCallPromise.Env(),
[statusLabel, asyncCallName](const Napi::CallbackInfo &info) {
showFailureInLabel(statusLabel, asyncCallName, QString::fromStdString(info[0].ToString()));
}),
});
}The window also shows an error that a call throws before its promise exists, and a missing module or ability.
Running the Example
Press Allow notifications and allow notifications in the dialog. Then press Post notification. While notifications are not allowed, publish() fails with a "Notification disabled" error, which the window shows. The request uses the default notification ID, so posting again updates the notification instead of adding another one.
© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.