|
| 1 | +--- |
| 2 | +title: "PWA Wrapper: Push Notification Setup" |
| 3 | +linktitle: "PWA Wrapper Push Setup" |
| 4 | +url: /refguide/mobile/using-mobile-capabilities/push-notifications/notif-pwa-wrapper/ |
| 5 | +weight: 75 |
| 6 | +description: "How to configure push notification prerequisites when your progressive web app is packaged with PWA Wrapper." |
| 7 | +--- |
| 8 | + |
| 9 | +## Introduction |
| 10 | + |
| 11 | +This guide explains how to set up push notifications for a Mendix PWA packaged with PWA Wrapper. Unlike standard PWAs, wrapped PWAs behave like native applications, which changes how you integrate push notifications. |
| 12 | + |
| 13 | +In a wrapped PWA, push notifications are handled natively through the device's operating system (Android or iOS) rather than through the browser. This guide takes you through Firebase configuration, PWA Wrapper integration, Push Notifications Connector setup, and app-level implementation. |
| 14 | + |
| 15 | +## Prerequisites |
| 16 | + |
| 17 | +Before starting this guide, make sure you have completed the following: |
| 18 | + |
| 19 | +* [Install PWA Wrapper](/refguide/mobile/pwa-wrapper/install-pwa-wrapper/) |
| 20 | +* Have a Firebase account (https://firebase.google.com) |
| 21 | + |
| 22 | +## Setting Up Firebase and PWA Wrapper |
| 23 | + |
| 24 | +Follow these steps to configure Firebase and integrate it with PWA Wrapper: |
| 25 | + |
| 26 | +### Step 1: Create and Configure Firebase Project |
| 27 | + |
| 28 | +1. Follow the steps in [Setting Up the Google Firebase Cloud Messaging Server](/refguide/mobile/using-mobile-capabilities/push-notifications/setting-up-google-firebase-cloud-messaging-server/) to create a Firebase project and set up a service account. |
| 29 | +2. In Firebase, add your Android and iOS apps to the project by following the same guide. |
| 30 | +3. Download and securely store the configuration files: |
| 31 | + * For Android: `google-services.json` |
| 32 | + * For iOS: `GoogleService-Info.plist` |
| 33 | + |
| 34 | +### Step 2: Configure PWA Wrapper for Push Notifications |
| 35 | + |
| 36 | +When building your wrapped app with PWA Wrapper, enable push notification infrastructure: |
| 37 | + |
| 38 | +1. Open the PWA Wrapper builder and select **Build** for your target platform (Android or iOS). |
| 39 | +1. Navigate to the **App Packing** section. |
| 40 | +1. Enable **Enable push notification infrastructure**. |
| 41 | +1. Upload the appropriate Firebase configuration file: |
| 42 | + * For Android: select and upload `google-services.json` |
| 43 | + * For iOS: select and upload `GoogleService-Info.plist` |
| 44 | +1. Complete the remaining builder steps as described in [Build PWA Wrapper Apps](/refguide/mobile/pwa-wrapper/build-pwa-wrapper-apps/). |
| 45 | + |
| 46 | +This configures the native layer to receive push notifications from Firebase Cloud Messaging (FCM). |
| 47 | +{{% alert color="warning" %}} |
| 48 | +Push notifications only work on physical devices. Emulators and simulators do not have the necessary Firebase Cloud Messaging infrastructure to receive push notifications. Always test push notifications on real Android and iOS devices. |
| 49 | +{{% /alert %}} |
| 50 | +## Installing Push Notifications Connector |
| 51 | + |
| 52 | +Add the Push Notifications Connector module to your app: |
| 53 | + |
| 54 | +1. In Mendix Studio Pro, download the [Push Notifications Connector](https://marketplace.mendix.com/link/component/3003) from the Marketplace. |
| 55 | +1. Add it to your app following the standard module import process. |
| 56 | +1. Complete the steps in [Adding Module Dependencies](/refguide/mobile/using-mobile-capabilities/push-notifications/notif-add-module-depends/) and [Implementing the Push Notifications Module](/refguide/mobile/using-mobile-capabilities/push-notifications/notif-implement-module/). |
| 57 | + |
| 58 | +## Implementing Push Notification Registration |
| 59 | + |
| 60 | +In your wrapped PWA application, create a nanoflow to handle device registration for push notifications. This nanoflow uses AppBuilderClient JavaScript actions to request permissions and retrieve device information. |
| 61 | + |
| 62 | +### Creating the Registration Nanoflow |
| 63 | + |
| 64 | +Create a new nanoflow in your app (for example, `ACT_RequestPushNotifications`) and add the following steps: |
| 65 | + |
| 66 | +#### Step 1: Request Permission |
| 67 | + |
| 68 | +1. Add a **Call JavaScript Action** activity. |
| 69 | +1. Select the **RequestPermission** action from **AppBuilderClient**. |
| 70 | +1. Set the parameter: |
| 71 | + * **Permission**: `notifications` |
| 72 | +1. Assign the return value to a variable (for example, `$PermissionState`). |
| 73 | + |
| 74 | +#### Step 2: Check Permission Status |
| 75 | + |
| 76 | +1. Add a **Decision** activity to check if permission was granted. |
| 77 | +1. Verify: `$PermissionState = 'granted'` |
| 78 | +1. If the condition is false (permission denied), end the flow and optionally show a message to the user. |
| 79 | + |
| 80 | +#### Step 3: Retrieve Device Information |
| 81 | + |
| 82 | +Add three **Call JavaScript Action** activities to retrieve device details: |
| 83 | + |
| 84 | +1. **GetDeviceInfo** from **AppBuilderClient** |
| 85 | + * Assign return value to `$DeviceInfo` |
| 86 | + |
| 87 | +2. **GetPushToken** from **AppBuilderClient** |
| 88 | + * Assign return value to `$PushToken` |
| 89 | + |
| 90 | +3. **GetOperatingSystem** from **AppBuilderClient** |
| 91 | + * Assign return value to `$OperatingSystem` |
| 92 | + |
| 93 | +#### Step 4: Create Device Registration Object |
| 94 | + |
| 95 | +1. Add a **Create Object** activity to create a new `PushNotifications.DeviceRegistration` object. |
| 96 | +2. Assign the following attributes: |
| 97 | + * **DeviceType**: Use a decision based on the operating system: |
| 98 | + ``` |
| 99 | + if $OperatingSystem = getKey(PushNotifications.DeviceSystemType.Android) then |
| 100 | + PushNotifications.DeviceType.Android |
| 101 | + else if $OperatingSystem = getKey(PushNotifications.DeviceSystemType.iOS) then |
| 102 | + PushNotifications.DeviceType.iOS |
| 103 | + else if $OperatingSystem = getKey(PushNotifications.DeviceSystemType.iPadOS) then |
| 104 | + PushNotifications.DeviceType.iOS |
| 105 | + else |
| 106 | + empty |
| 107 | + ``` |
| 108 | + * **RegistrationID**: `$PushToken` |
| 109 | + * **DeviceId**: `$DeviceInfo/UniqueId` |
| 110 | +
|
| 111 | +3. Assign the created object to a variable (for example, `$NewDeviceRegistration`). |
| 112 | +
|
| 113 | +#### Step 5: Synchronize Device Registration |
| 114 | +
|
| 115 | +1. Add a **Synchronize** activity to commit the device registration object to the database. |
| 116 | +1. Select `$NewDeviceRegistration` as the object to synchronize. |
| 117 | +
|
| 118 | +The complete nanoflow flow is shown below: |
| 119 | +
|
| 120 | +{{< figure src="/attachments/refguide/mobile/push-notifications/notif-pwa-wrapper/pwa-wrapper-push-nanoflow.png" alt="Push notification registration nanoflow for PWA Wrapper" max-width="80%" >}} |
| 121 | +
|
| 122 | +{{% alert color="info" %}} |
| 123 | +The nanoflow requests the `notifications` permission, retrieves the device token and unique ID, and registers the device in the Push Notifications Connector database. This allows the runtime to send push notifications to this device. |
| 124 | +{{% /alert %}} |
| 125 | +
|
| 126 | +### Calling the Registration Nanoflow |
| 127 | +
|
| 128 | +The registration nanoflow should run automatically each time the app opens — both on first launch and when the user returns to the app from the background. This ensures the FCM token stays current. The next section explains how to implement this using app lifecycle events. |
| 129 | +
|
| 130 | +## Running Push Notification Registration on App Lifecycle Events |
| 131 | +
|
| 132 | +To keep device registration up to date, run the registration nanoflow automatically whenever the app becomes active. Use the [Events](https://marketplace.mendix.com/link/component/224259) module from the Mendix Marketplace together with a custom JavaScript action that listens for app lifecycle changes. |
| 133 | +
|
| 134 | +### Step 1: Install the Events Module |
| 135 | +
|
| 136 | +Download and install the [Events](https://marketplace.mendix.com/link/component/224259) module from the Mendix Marketplace. |
| 137 | +
|
| 138 | +### Step 2: Create the ListenToAppLifecycle JavaScript Action |
| 139 | +
|
| 140 | +Create a new JavaScript action named `ListenToAppLifecycle` in your app with the following configuration: |
| 141 | +
|
| 142 | +* Add one parameter of type **Nanoflow**: |
| 143 | + * `onResume` |
| 144 | +
|
| 145 | +Use the following as the action's implementation: |
| 146 | +
|
| 147 | +```js |
| 148 | +// BEGIN EXTRA CODE |
| 149 | +let appLifecycleListenerInitialized = false; |
| 150 | +// END EXTRA CODE |
| 151 | +
|
| 152 | +export async function ListenToAppLifecycle(onResume) { |
| 153 | + // BEGIN USER CODE |
| 154 | +
|
| 155 | + if (appLifecycleListenerInitialized) { |
| 156 | + return; |
| 157 | + } |
| 158 | +
|
| 159 | + appLifecycleListenerInitialized = true; |
| 160 | +
|
| 161 | + const handleVisibilityChange = async () => { |
| 162 | + try { |
| 163 | + if (document.visibilityState === "visible") { |
| 164 | + if (onResume) { |
| 165 | + await onResume(); |
| 166 | + } |
| 167 | + } |
| 168 | + } catch (error) { |
| 169 | + console.error("Failed to handle app lifecycle event:", error); |
| 170 | + } |
| 171 | + }; |
| 172 | +
|
| 173 | + document.addEventListener("visibilitychange", handleVisibilityChange); |
| 174 | +
|
| 175 | + if (document.visibilityState === "visible" && onResume) { |
| 176 | + await onResume(); |
| 177 | + } |
| 178 | +
|
| 179 | + // END USER CODE |
| 180 | +} |
| 181 | +``` |
| 182 | + |
| 183 | +The `appLifecycleListenerInitialized` guard prevents duplicate event listeners from being registered if the action is called more than once. |
| 184 | + |
| 185 | +### Step 3: Create the Lifecycle Nanoflow |
| 186 | + |
| 187 | +Create a new nanoflow (for example, `ACT_InitAppLifecycle`) and add the following: |
| 188 | + |
| 189 | +1. Add a **Call JavaScript Action** activity. |
| 190 | +1. Select the **ListenToAppLifecycle** action you created. |
| 191 | +1. Set the parameters: |
| 192 | + * **onResume**: select the `ACT_RequestPushNotifications` nanoflow you created earlier |
| 193 | + |
| 194 | +The nanoflow is shown below: |
| 195 | + |
| 196 | +{{< figure src="/attachments/refguide/mobile/push-notifications/notif-pwa-wrapper/pwa-wrapper-lifecycle-nanoflow.png" alt="App lifecycle nanoflow calling ListenToAppLifecycle and ACT_RequestPushNotifications" max-width="80%" >}} |
| 197 | + |
| 198 | +### Step 4: Add the Events Widget to the Home Page |
| 199 | + |
| 200 | +1. Open your app's default home page in Studio Pro. |
| 201 | +1. Add the **Events** widget from the installed Events module to the page. |
| 202 | +1. In the widget properties, locate the **Component Load** event. |
| 203 | +1. Set the action to **Call a nanoflow**. |
| 204 | +1. Select the `ACT_InitAppLifecycle` nanoflow. |
| 205 | + |
| 206 | +This ensures that every time the page loads — which happens when the app opens — the lifecycle listener is registered and the push notification registration nanoflow runs immediately. If the FCM token has changed since the last session, the updated token is saved automatically. |
| 207 | + |
| 208 | +## Sending Push Notifications |
| 209 | + |
| 210 | +After you have built and deployed your wrapped app with device registrations in place, use the standard Push Notifications Connector workflow to send notifications: |
| 211 | + |
| 212 | +1. Follow [Configuring Push Notifications](/refguide/mobile/using-mobile-capabilities/push-notifications/notif-config-push/) to configure Firebase credentials in your app's administration page. |
| 213 | +2. Use [Sending Your First Test Push Notification](/refguide/mobile/using-mobile-capabilities/push-notifications/notif-send-test/) to test sending a notification to a registered device. |
| 214 | + |
| 215 | +When testing, verify behavior on physical Android and iOS devices to ensure notifications are received correctly. |
| 216 | + |
| 217 | +## Read More |
| 218 | + |
| 219 | +* [Push Notifications](/refguide/mobile/using-mobile-capabilities/push-notifications/) |
| 220 | +* [PWA Wrapper](/refguide/mobile/pwa-wrapper/) |
| 221 | +* [PWA Wrapper Capabilities](/refguide/mobile/pwa-wrapper/pwa-wrapper-capabilities/) |
| 222 | +* [PWA Wrapper Limitations](/refguide/mobile/pwa-wrapper/pwa-wrapper-limitations/) |
0 commit comments