diff options
Diffstat (limited to 'examples/webenginewidgets/push-notifications/doc/src/push-notifications.qdoc')
-rw-r--r-- | examples/webenginewidgets/push-notifications/doc/src/push-notifications.qdoc | 191 |
1 files changed, 191 insertions, 0 deletions
diff --git a/examples/webenginewidgets/push-notifications/doc/src/push-notifications.qdoc b/examples/webenginewidgets/push-notifications/doc/src/push-notifications.qdoc new file mode 100644 index 000000000..90b5212c8 --- /dev/null +++ b/examples/webenginewidgets/push-notifications/doc/src/push-notifications.qdoc @@ -0,0 +1,191 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only + +/*! + +\example webenginewidgets/push-notifications +\title WebEngine Push Notifications Example +\ingroup webengine-widgetexamples +\brief Demonstrates how to subscribe to and unsubscribe from push notifications. + +In this example we are going to send push notifications from a web push service to the user. +This is the typical scenario where messages are sent from the application server i.e. website +back-end through a 3rd-party push service, to finally arrive at the user's browser in form of +notifications. To demonstrate this flow, we will implement a simple push service server +application, to which the user can subscribe to receive \e ping messages. + +As already mentioned, in such a workflow there are three different parties involved: + +\list + \li the user's web browser where they receive push notifications + \li 3rd-party push service, which is defined by a subscription endpoint and is a part + of a browser's push service implementation + \li application server, which will store user's subscriptions and initiate push messages + using a subscription endpoint +\endlist + +The user visits a website, where a JavaScript web application uses the JavaScript Push API +to create a push notification subscription. The user is then asked to grant a permission +to receive and display push notifications. Once accepted, the Push API establishes a push channel +with a 3rd-party push service, which in case of QtWebEngine is \l {https://firebase.google.com} +{Firebase Cloud Messaging (FCM)}. The unique push subscription is created that +includes the subscription endpoint URL. The browser then sends a subscription message +to the application server forwarding the endpoint setup. The application server can now +use the subscription endpoint to send notifications to the browser. The browser push service +implementation will deliver a push message. However, to show it, a service worker must +be registered. As the service worker runs in the background, it allows displaying notifications +even if a website, which has installed it, is no longer opened. + +\image push-notifications.png + +Let's go more into implementation details. We start with implementing our custom +push service using NodeJS with two modules: + +\list + \li \l {https://github.com/web-push-libs/web-push} {web-push} - provides the web-push protocol + implementation + \li \l {https://github.com/expressjs/express} {express} - provides the web application framework +\endlist + +Let's initialize a new project and install the required modules in the root directory of this +example: + +\snippet /push-notifications/commands 0 + +These commands should create package.js, which defines the start command: + +\snippet /push-notifications/commands 1 + +Now let's move on to the push service back-end implementation in server.js. + +We start by including the required modules and doing basic \e express framework setup, which +we use to create our custom push server. For simplicity we are going to handle only one +subscription at a time. To do that we need to create \e VAPID keys which we are going to +generate with \e web-push libs. The public key is going to be used by the front-end and authenticate +to the service. + +\quotefromfile webenginewidgets/push-notifications/server.js +\skipto const express +\printto add subscribe route + +\note We are not going to cover the encryption of messages in this example. + +To generate keys, we can use the tool shipped with \e web-push lib, that is installed by +\c npm in our example's root directory. + +\snippet /push-notifications/commands 2 + +Now we add two \c routes to the push server. One to \c subscribe and one to \c unsubscribe, +so that our front-end can send an HTTP POST request to handle the push subscription. +In the subscribe request we will get \c subscription in the request body and we also retrieve +the custom header \c ping-time that defines how often the ping messages should be pushed to +the user. We keep around the \c subscription to be able to send push notifications later. +As a confirmation, we send the 201 status code and schedule the first push notification based on +the \c ping-time value. The \c unsubscribe request simply removes a subscription. + +\quotefromfile webenginewidgets/push-notifications/server.js +\skipto add subscribe route +\printto function sendNotification + +The \c sendNotication() function sends push messages using the web-push lib. We create the payload +with the message we want to present to a user and schedule the next push message. + +\quotefromfile webenginewidgets/push-notifications/server.js +\skipto function sendNotification +\printto server.listen + +In the end we start the server to listen on the given port. + +\quotefromfile webenginewidgets/push-notifications/server.js +\skipto server.listen +\printline started + +Let's move now to our front-end. We create a simple page index.html, where the user can enter how +often they want to receive ping notification messages. We will have two buttons: +\e {Ping Me} to subscribe for push notifications and \e Clear to unsubscribe. +In the end we load ping.js, which we cover next. + +\quotefromfile webenginewidgets/push-notifications/content/index.html +\skipto <body> +\printuntil </body> + +The last piece is creating the logic for the push subscription within the front-end. Here we have two +functions, \c setup and \c clear, to handle subscriptions. When the user clicks on the \e {Ping Me} +button, \c setup is called. To be able to receive notifications, the service worker is needed. +This way the user can leave the website and still get notified as the service worker works +in the background and handles incoming messages. To achieve that, we have to first register +one with: + +\quotefromfile webenginewidgets/push-notifications/content/ping.js +\skipto const register +\printline worker.js + +The call to \c cpushManager.subscribe() will trigger a permission prompt, which is displayed to the +user. If the permission is granted, the push subscription is returned. It includes a URL endpoint +that allows sending notifications to the browser, where the registered service worker waits for +push messages. + +\quotefromfile webenginewidgets/push-notifications/content/ping.js +\skipto var subscription +\printto console.log + +As mentioned the subscription is created for FCM and should be now sent to our custom server +with an HTTP POST request. In addition, we add to the post request the HTTP header with the +\c ping-time the user entered on our website. + +\quotefromfile webenginewidgets/push-notifications/content/ping.js +\skipto await fetch +\printto console.log + +The function \c clear call unsubscribes first from our push server by sending an HTTP POST request +and later from the 3rd-party push service (FCM). + +\quotefromfile webenginewidgets/push-notifications/content/ping.js +\skipuntil async function clear() +\skipuntil { +\printto console.log +\dots +\skipto await fetch +\printto console.log +\dots +\skipto await subscription +\printto console.log + +The rest of code in ping.js is just boilerplate code to read a user provided value +and call \c setup() or \c clear(). + +As the last part of the front-end let's look inside a service worker script, where we simply +register an event listener for \e push events. + +\quotefromfile webenginewidgets/push-notifications/content/worker.js +\skipto self +\printuntil }); +\printuntil }); + +When a push event comes we simply use the Notification JavaScript API to display a notification. + +\note QtWebEngine Notification Example shows how to provide your own handler and customize +the look and feel of a notification message. + +Having the implementation in place, we can start the server on localhost at the port 5000. +To do that, we can simply enter in the console in the project's root directory: + +\snippet /push-notifications/commands 3 + +Now we can fire up \e simplebrowser and enter \c http:\\localhost:5000 as a URL. + +\image website.png + +\note \c QWebEngineProfile cannot be set to \e off-the-record, because push messages would be +disabled. + +After granting the permission we can send our ping request: + +\image permissions.png + +We should see the coming push notification: + +\image notification.png + +\note To troubleshoot errors, open \e {Developer Tools} from Tools menu. +*/ |