Откройте PWA при нажатии на push-уведомление, обрабатываемое работником сервиса ng7 + android
У нас есть PWA, реализованный на angular 7, и NodeJS в качестве бэкэнда. Push-уведомления отправляются из бэкэнда с помощью web-push и обрабатываются службой угловой службы.
Поведение, которое мы надеемся иметь в Android, заключается в том, что когда пользователь нажимает на уведомление, приложение открывается на устройстве (т.е. PWA появляется из фона и кажется видимым для пользователя).
В настоящее время код выполняется в фоновом режиме, но PWA не появляется в фоновом режиме (т.е. Пользователь нажимает на push-уведомление, но ничего не происходит).
Push-уведомления обрабатываются угловой службой SwPush на внешней стороне и доставляются в приложение с использованием следующего кода в типичном компоненте AppComponent углового приложения:
export class AppComponent implements OnInit {
constructor(private swPush: SwPush) { }
ngOnInit(): void {
try {
if (this.swPush.isEnabled) {
this.swPush.notificationClicks.subscribe(
event => {
window.focus();
window.open(event.notification.data.url, '_self');
},
error => {
// handle error
}
);
}
} catch (err) {
// handle error
}
}
}
Я провел поиск по всему SO сайту и не нашел именно этого вопроса. Комментарии по другим вопросам SO, чтобы избежать двусторонних ссылок на другие ответы SO:
- Я прочитал этот вопрос, и в моем случае журнал консоли внутри обработчика выполняется без проблем
-
этот другой вопрос предлагает обходной путь добавления кода в библиотеку сервис-работника, но, насколько я понимаю, это потому, что они используют угловой 5 вместо углового 7 (где сервис SwPush включает обработчик уведомленияclick). В любом случае мне нужно смоделировать эту строку:
event.waitUtil(clients.openWindow(URL));
Любая идея о том, как открыть PWA, когда пользователь нажимает на push-уведомления при использовании службы SwPush Angular 7?
Ответы
Ответ 1
К сожалению, вы не сможете открыть свой PWA из углового кода. Интерфейс SwPush будет хорошо работать, если приложение в данный момент открыто.
Если ваше приложение закрыто, будет запущен только ваш обслуживающий работник (при условии, что он был успешно зарегистрирован). Таким образом, решение вашей проблемы - редактирование рабочего файла угловой службы.
В angular 7 (в частности, "@angular/service-worker" v ~ 7.2.0), после того как вы ng build --prod
свое приложение с помощью ng build --prod
, проверьте папку /dist
и найдите файл ngsw-worker.js
. Откройте его в редакторе.
На линии 1885 вы найдете:
this.scope.addEventListener('notificationclick', (event) => this.onClick(event));
Измените это на:
this.scope.addEventListener('notificationclick', (event) => {
event.notification.close();
if (clients.openWindow && event.notification.data.url) {
event.waitUntil(clients.openWindow(event.notification.data.url));
}
});
Это означает, что вы передали в уведомлении полезную нагрузку объекта данных с нужным URL-адресом. например:
{
title: "Hello",
body: "Here, open this URL",
data: {
url : "/somewhere/over/the/rainbow/42"
}
}
Что нужно иметь в виду:
- Если у вас есть какие-либо автоматические конвейеры сборки (CD), вам придется вручную изменить файл ngsw-worker.js (но вы сможете развернуть файл рабочего сервиса после завершения процесса
ng build --prod
); - Каждый раз, когда вы собираете prod, ngsw-worker.js будет перезаписываться.
- Я знаю, что вы разрабатываете на Android, но если у вас возникают проблемы с отображением изменений, вы можете использовать инструменты Chrome Dev, чтобы [A] принудительно обновить работника сервиса или [B], чтобы открыть текущий файл ngsw-worker.js и проверить, если это желаемая версия. Решение работает и для установленных приложений на вашем рабочем столе.
Ссылки по теме:
Как я могу инициировать PWA (прогрессивное веб-приложение), открытое нажатием на push-уведомление?
https://github.com/angular/angular/issues/20956
Ответ 2
Добавьте это в свой проект Angular внутри node_modules/@angular/service-worker/ngsw-worker.js
this.scope.addEventListener('notificationclick', (event) => {
console.log('[Service Worker] Notification click Received. event:%s', event);
event.notification.close();
if (clients.openWindow && event.notification.data.url) {
event.waitUntil(clients.openWindow(event.notification.data.url));
}
});
Вы можете ввести вышеуказанный код, где вы можете найти эту строку внутри файла
this.scope.addEventListener('notificationclick', (event) => ..
И вы должны построить дистрибутив снова, чтобы это работало. А в бэкэнде вам нужно будет использовать этот формат:
{"notification":{"body":"This is a message.","title":"PUSH MESSAGE","vibrate":[300,100,400,100,400,100,400],"icon":"https://upload.wikimedia.org/wikipedia/en/thumb/3/34/AlthepalHappyface.svg/256px-AlthepalHappyface.svg.png","tag":"push demo","requireInteraction":true,"renotify":true,"data":{"url":"https://maps.google.com"}}}
Внутри URL вы можете ввести свой URL, и при нажатии на уведомление ваше push-уведомление откроет данную ссылку и сфокусирует ее в браузере. Вам не нужно ничего менять внутри dist.
Ответ 3
Хотя предоставленные решения работают, было бы неплохо иметь подход, который не изменяет код работника службы в node_modules или сгенерированный код.
Подход может заключаться в создании другого сценария с именем custom-service-worker.js
В этом файле
importScripts('./ngsw-worker.js');
(function () {
'use strict';
self.addEventListener('notificationclick', (event) => {
console.log("This is custom service worker notificationclick method.");
console.log('Notification details: ', event.notification);
// Write the code to open
if (clients.openWindow && event.notification.data.url) {
event.waitUntil(clients.openWindow(event.notification.data.url));
}
});}
());
Зарегистрируйте custom-service-worker.js
в качестве работника службы вместо ngsw-worker.js
в разделе импорта, где будет записан ServiceWorkerModule.register.
Также не забудьте добавить этот скрипт как ресурс в angular.json, чтобы он копировался в папку dist
.
Я полагаю, что такой подход избавляет нас от необходимости делать что-то дополнительно для редактирования исходного файла рабочего сервиса.