Rapporto Web Push SDK#
Общая информация#
Данный комплект для разработки программного обеспечения (далее – SDK) предназначен для отправки сообщений в браузер/на мобильные устройства пользователей через сервисы отправки push-уведомлений. Распространение SDK осуществляется компанией Rapporto в форме SaaS.
Основные возможности библиотеки:
- приём и отображение push-сообщений, отправленных в браузер/на мобильное устройство с помощью Push API через соответствующие сервисы, в том числе содержащих расширенный медиаконтент (изображения, кнопки); 
- сохранение принятых сообщений в локальной базе данных; 
- отслеживание доставки и открытия push-сообщений с отправкой соответствующих запросов на сервер. 
Для внедрения SDK в мобильное приложение необходимо:
- Добавить в приложение файл конфигурации - ZGRConfig.jsonи скомпилированную в виде npm-пакета библиотеку- @rapporto/web-push-sdk. Файл- ZGRConfig.jsonследует разместить в папке public.
- Запросить у Службы технической поддержки данные, необходимые для подключения к репозиторию Nexus компании Rapporto. При настройке доступа к репозиторию рекомендуется по возможности использовать корпоративный прокси-сервер для пакетов (например, Nexus или Artifactory). Это повысит общую безопасность и существенно облегчит работу: данные учетной записи не будут распространяться между разработчиками, а также не потребуется настраивать локальное подключение к репозиторию. - Пример подключения репозитория в непрерывной интеграции (CI) с использованием предварительно настроенных переменных - RAPPORTO_NPM_REGISTRY,- RAPPORTO_NPM_REGISTRY_USERNAMEи- RAPPORTO_NPM_REGISTRY_PASSWORD:- npm config set @rapporto:registry "${RAPPORTO_NPM_REGISTRY}" npm config set //${RAPPORTO_NPM_REGISTRY#https://}:_auth=$(echo -n "${RAPPORTO_NPM_REGISTRY_USERNAME}:${RAPPORTO_NPM_REGISTRY_PASSWORD}" | base64) - Пример подключения в локальном терминале с интерактивным вводом логина, пароля и любого адреса email: - npm adduser --auth-type=legacy --scope=@rapporto --registry=${RAPPORTO_NPM_REGISTRY} - Подключение зависимости в package.json: - "dependencies": { "@rapporto/web-push-sdk": "^1.0.0" } 
- Выполнить инициализацию механизма регистрации подписки на веб push-уведомления, следуя нижеприведенным указаниям. 
Системные требования#
Информация о минимальных версиях поддерживаемых браузеров доступна по ссылке.
Быстрый старт#
Подключение библиотеки Web-push-sdk
Основным классом @rapporto/web-push-sdk является ZGRMessaging. Порождающий шаблон проектирования – одиночка (singleton).
import { ZGRMessaging } from '@rapporto/web-push-sdk'
const messaging = new ZGRMessaging()
Инициализация приложения для получения веб push-уведомлений#
Этап 1. Запрос у пользователя разрешения на отправку ему веб push-уведомлений
В ZGRMessaging доступно свойство isPushesGranted:
const isPushGranted = messaging.isPushesGranted
if(!isPushGranted) {
    showAlertAndRequestPermission()
} else {
    registerSW()
}
Этап 2. Регистрация файла service-worker.js
После успешной регистрации необходимо вызвать функцию sendNotificationToken():
navigator.serviceWorker.register('/service-worker.js')
.then(serviceWorkerRegistration => {
    messaging.sendNotificationToken()
})
Этап 3. Получение подписки из центра авторизации и её отправка на сервер
После успешной отправки информации на сервер SDK создаёт в функции sendNotificationToken событие getSubscription, в котором передает приложению необходимую для получения подписки публичную часть VAPID-ключа. Полученная подписка отсылается на сервер вызовом функции savePushSubscription():
self.addEventListener('getSubscription', getSubscriptionHandler)
async function getSubscriptionHandler(event) {
    const key = event.detail
    const subs = await subscribeUserToPush(key)
    messaging.savePushSubscription(subs)
}
Этап 4. Регистрация пользователя
После ввода логина/номера телефона пользователя необходимо отправить их на сервер, вызвав функцию saveUser(userPhone, userId):
messaging.saveUser(userPhone, userId)
Получение и отображение веб push-соообщений#
Получение и отображение веб push-соообщений с отправкой на сервер статуса DELIVERED («Доставлено») на примере простых и RICH/SECURE push-сообщений:
 1async function broadcastClients(message) {
 2  const clients = await self.clients.matchAll();
 3  clients.forEach(client => client.postMessage(message));
 4}
 5
 6self.addEventListener('push', onPushEventHandler)
 7
 8function onPushEventHandler(event) {
 9
10  async function onPush(event) {
11    // wake up SW on all pages
12    await self.clients.claim();
13
14    const data = event.data.json();
15    const pushDeliveredMsg = { type: "pushDelivered", body: data };
16
17    // Execute receive push actions
18    const onPushActions = [
19      broadcastClients(pushDeliveredMsg),
20    ];
21
22    // RICH/SECURE push-сообщения
23    if(data.zgrExtraOptions) {
24      const options = JSON.parse(data.zgrExtraOptions)
25
26      if(options !== [] && (options[0] === 'RICH' || options[0] === 'SECURE')) {
27
28        const notificationUpdateDataObj = { type: 'notifUpdate', body: data.zgrNotificationId };
29        onPushActions.push(
30          broadcastClients(notificationUpdateDataObj)
31        )
32      }
33    }
34    // ordinary
35    else {
36      const message = data.zgrNotificationText
37      const title = data.zgrNotificationTitle
38
39      let imageUrl = ''
40      if(data.zgrNotificationContentCategory && data.zgrNotificationContentCategory.toLowerCase() === 'image'){
41        imageUrl = data.zgrNotificationContentUrl
42      }
43
44      const zActions = data.zgrNotificationActions ? this.setActionsArray(data.zgrNotificationActions) : []
45      const notificationOptions = { body: message, icon: imageUrl, data: data, actions: zActions, };
46
47      onPushActions.push(
48        await self.registration.showNotification(title, notificationOptions)
49      )
50    }
51
52    await Promise.all(onPushActions)
53  }
54
55  event.waitUntil(
56    onPush(event)
57  )
58}
59
60// обновление данных в случае RICH/SECURE push-сообщений
61async function onNotificationUpdateEventHandler(event) {
62    const updateData = event.data.object
63    const message = updateData.zgrNotificationText
64    const title = updateData.zgrNotificationTitle
65
66    let imageUrl = ''
67    if(updateData.zgrNotificationContentCategory && updateData.zgrNotificationContentCategory.toLowerCase() === 'image'){
68      imageUrl = updateData.zgrNotificationContentUrl
69    }
70
71    const zActions = updateData.zgrNotificationActions ?  this.setActionsArray(updateData.zgrNotificationActions) : []
72
73    self.registration.showNotification(title, {
74      body: message,
75      icon:  imageUrl,
76      actions: zActions
77    });
78}
79
80self.addEventListener('message', function(event) {
81    switch (event.data.command) {
82    ...
83    case 'update':
84        return self.onNotificationUpdateEventHandler(event)
85    ...
86}
 1if ('serviceWorker' in navigator && 'PushManager' in window) {
 2
 3    navigator.serviceWorker.addEventListener('message', function(event) {
 4        const messageType = event.data.type
 5        if(messageType == 'pushDelivered') {
 6            pushDeliveredHandler(event)
 7        } else if(messageType == 'pushClicked') {
 8            pushClickedHandler(event)
 9        } else if(messageType == 'notifUpdate') {
10            notifUpdateHandler(event)
11        }
12    })
13}
14
15async function pushDeliveredHandler(event) {
16    const data = event.data
17    messaging.receiveNotification(data)
18}
19
20// в случае RICH/SECURE push-сообщений
21async function notifUpdateHandler(event) {
22    const data = event.data
23    messaging.updateRichNotificationData(data)
24}
25
26self.addEventListener('notificationUpdate', notificationUpdateHandler);
27
28async function notificationUpdateHandler(event) {
29    const data = event.detail
30    const updateObj = { 'command': 'update', 'object': data }
31
32    navigator.serviceWorker.controller.postMessage(updateObj)
33}
Обработка событий#
Обработка событий нажатия на контент уведомления или кнопку с отправкой на сервер статуса OPENED («Открыто»):
 1self.addEventListener('notificationclick', onNotificationClickEventHandler)
 2
 3function onNotificationClickEventHandler(event) {
 4    const clickedNotification = event.notification
 5    const notificationData = event.notification.data;
 6
 7    const dataObj = { type: 'pushClicked', body: notificationData }
 8    broadcastClients(dataObj)
 9
10    const action = event.action
11    if(action) {
12
13        self.clients.openWindow(action);
14
15    } else {
16
17        event.waitUntil(
18            // Retrieve a list of the clients of this service worker.
19            self.clients.matchAll().then(function(clientList) {
20            // If there is at least one client, focus it.
21            if (clientList.length > 0) {
22                return clientList[0].focus();
23            }
24
25            // Otherwise, close notification.
26            return clickedNotification.close();
27        }))
28    }
29}
async function pushClickedHandler(event) {
    const data = event.data
    messaging.clickNotification(data)
}
Профили пользователей#
Получение профиля
messaging.fetchUser()
Функция возвращает экземпляр класса ZGRUser:
export class ZGRUser {
    this.externalUserId = 'some string value' ? ''
    this.phoneNumber = 'some string value' ? ''
}
Отправка внешнего идентификатора пользователя и/или номера телефона пользователя в ZGR
messaging.saveUser(userPhone, userId)
Функция возвращает экземпляр класса ZGRUser.
Обновление номера телефона в профиле
messaging.saveUserPhone(phoneNumber)
Функция возвращает экземпляр класса ZGRUser.
Персонализация#
Персонализация (привязка externalUserId)
messaging.personalize(externalUserId)
Функция возвращает экземпляр класса ZGRUser.
Обезличивание (выход)
messaging.depersonalize()
Настройки подписок#
Получение настроек с подписками
messaging.fetchInstallation()
Функция возвращает экземпляр класса ZGRInstallation:
 1export class ZGRInstallation {
 2
 3    this.isPrimary = true ? false           /*< Primary device attribute */
 4    this.isPushOsEnabled = true ? false     /*< System level permission for push notifications */
 5    this.isPushEnabled = true ? false       /*< User level permission for push notifications */
 6
 7    this.subscriptions = [ZGRSubscription, ZGRSubscription, ...] | []
 8
 9}
10
11export class ZGRSubscription {
12
13    this.identifier = Int value
14    this.type = 'PERMISSION' | 'SETTINGS'
15
16    this.name = 'some string value'
17    this.title = 'some string value'
18    this.desc = 'some string value' ? ''
19    this.value = 'some string value' ? ''
20}
Изменение настроек и параметров подписок
Доступно изменение свойств в классах ZGRInstallation и ZGRSubscription. Описание атрибутов приведено в соответствующем блоке.
messaging.saveInstallation(installation)
Сохраняет на сервере переданный в качестве параметра экземпляр класса ZGRInstallation.
Локальная история уведомлений#
Включение режима хранения локальной истории уведомлений
messaging.isLocalDBEnabled = true
Получение всех сохраненных уведомлений из базы данных
messaging.fetchAllNotifications()
Возвращает массив уведомлений, экземпляров класса ZGRNotification:
 1export class ZGRNotification {
 2
 3    this.identifier = 'some string value'
 4    this.title = 'some string value' ? ''
 5    this.text = 'some string value' ? ''
 6    this.contentUrl = 'some string value, that can be converted into url' ? ''
 7    this.contentCategory = 'html' | 'image' | 'other' | 'none' | ''
 8    this.customPayload = some object /*< Additional data for your's own purposes. Array, Dictionary or any other top-level object. */
 9    this.actions = [ZGRAction, ZGRAction, ...] | [] /*< Array of actions for buttons in push notification. */
10}
11
12export class ZGRAction {
13
14    this.identifier = 'some string value' ? ''
15    this.title = 'some string value' ? ''
16    this.urlString = 'some string value, that can be converted into url' ? ''
17    this.type = 'default' | 'dismiss' | 'other'
18}
При передаче contentUrl необходимо заполнить contentCategory.
Важно
Не все браузеры поддерживают функционал кнопок в push-сообщениях. Актуальная информация доступна в соответствующей документации.
Удаление уведомления из базы данных
messaging.delete(notification)
Удаление массива уведомлений из базы данных
messaging.deleteNotificationsArray(notificationsArray)
Обновление статуса уведомления в базе данных
messaging.updateNotification(notification, status)