В этом руководстве мы реализуем функцию push-уведомлений в нашем приложении Laravel с помощью WebPush. Мы будем использовать Vanilla Javascript без фреймворков или библиотек. Push-уведомления - это функция Service Workers. Service Worker - это сценарий внутри веб-браузера, который работает в фоновом режиме. Есть много функций, таких как кеширование, фоновая синхронизация, но это руководство касается только push-уведомлений. Мы также реализуем push-уведомления для гостевых пользователей.

Примечание. Service Workers используют HTTPS, если вы не используете localhost.

Начиная

Давайте создадим новый проект laravel с композитором:

composer create-project laravel/laravel webpush

Перед переносом таблицы добавьте эту строку в метод boot () вашего AppServiceProvider.php, расположенного в app \ Providers:

Приведенный выше код устанавливает длину строкового столбца по умолчанию равной 191. Поскольку Laravel по умолчанию имеет кодировку utf8mb4, а максимальная длина уникального ключа составляет 191. Если он превысит лимит, Laravel выдаст ошибку и не запустит миграции. Если вы хотите указать другую кодировку, вы можете установить ее в файле конфигурации database.php, расположенном в каталоге конфигурации. Теперь настройте базу данных и добавьте учетные данные базы данных в файл .env и запустите команду migrate, которая создаст все необходимые таблицы, используемые для аутентификации:

php artisan migrate

и сгенерируйте каркас аутентификации:

php artisan make:auth

Вместо использования виртуального хоста с apache мы будем использовать сервер Laravel dev с (для localhost):

php artisan serve

Откройте свой Chrome и вставьте URL-адрес, который вы видите в своем терминале. (Я не предлагаю использовать другие браузеры, кроме Chrome или Firefox).

Подписка пользователя

Чтобы начать с наших уведомлений, нам нужно будет подписать пользователя из браузера, и мы можем сделать это с помощью javascript. Подписка пользователя будет состоять из двух этапов:

  • Получение разрешения от пользователя.
  • Получение PushSubscription из этого браузера и отправка его на сервер.

Перед подпиской пользователя нам нужно будет сгенерировать ключи сервера приложений, известные как ключи VAPID. Ключи VAPID - это открытые и закрытые ключи, используемые для распознавания пользователя, и эти ключи гарантируют, что это один и тот же сервер, запускающий push-сообщения для пользователей. Есть несколько способов сгенерировать эти ключи: вы можете посетить этот сайт web-push-codelab.glitch.me, чтобы сгенерировать эти ключи, или установите web-push cli с npm, чтобы сгенерировать их из ваша командная строка:

$ npm install -g web-push
$ web-push generate-vapid-keys

Поскольку мы используем пакет Laravel под названием Webpush, мы можем сгенерировать эти ключи с помощью команды artisan. Библиотеки Webpush также доступны для других языков, см. По этой ссылке список всех библиотек. Установим пакет:

composer require laravel-notification-channels/webpush

Laravel 5.6 или выше использует функцию обнаружения пакетов, поэтому нам не нужно добавлять поставщика пакетов. Давайте добавим черту HasPushSubscription к модели User:

После добавления трейта нам нужно будет опубликовать миграцию, которая создаст таблицу push_subscriptions:

php artisan vendor:publish --provider="NotificationChannels\WebPush\WebPushServiceProvider" --tag="migrations"

Когда вы запустите команду migrate, она выдаст ошибку из-за того, что кодировка говорит: указанный ключ слишком длинный, поэтому мы добавим другую кодировку для этой таблицы и добавим другую длину для столбца конечной точки. Давайте обновим метод up ():

Вы также можете опубликовать файл config (который мы не будем использовать):

php artisan vendor:publish --provider="NotificationChannels\WebPush\WebPushServiceProvider" --tag="config"

Теперь мы можем сгенерировать ключи VAPID:

php artisan webpush:vapid

Эта команда сгенерирует открытый и закрытый ключи VAPID и сохранит их в файле .env.

Давайте создадим файл Service Worker в общедоступном каталоге с именем sw.js и файл javascript с именем enable-push.js в каталоге public / js. Добавьте сценарий прямо перед конечным тегом ‹/body› в файле макета app.blade.php, расположенном в ресурсах / представлениях / макетах:

Он будет включать сценарий только в том случае, если мы авторизованы.

Начнем работать на стороне клиента, открыв файл enable-push.js. Мы зарегистрируем нашего сервис-воркера, определив функцию с именем initSW ():

В приведенной выше функции мы сначала проверяем, поддерживаются ли сервисные воркеры и push, после этого мы регистрируем нашего сервисного воркера, который находится за пределами одного каталога (вам не нужно проверять push здесь, это остановит регистрацию сервисного воркера, но мы используем сервис-воркер с единственной целью - push, поэтому оставим его там.) Внутри then () мы вызываем initPush (), который будет отвечать за подписку пользователя. Не забудьте вызвать initSW () в нашем enable-push.js. Просто вставьте эту строку в верхнюю часть скрипта:

initSW();

Давайте определим initPush () после initSW ():

Внутри initPush () мы запрашиваем разрешение пользователя, и если пользователь нажимает кнопку «Разрешить», мы сможем получить PushSubscription. После получения разрешения мы вызываем subscribeUser (), который подписывает пользователя и отправляет PushSubscrption на наш сервер. Определим subscribeUser ():

navigator.serviceWorker.ready используется для проверки того, зарегистрирован ли и активен ли работник службы. Внутри then () мы сначала создаем объект subscriptionOptions, который будет иметь наш открытый ключ VAPID и параметр userVisibleOnly. Используйте открытый ключ, который вы сгенерировали с помощью приведенной выше команды. Установка для userVisibleOnly значения true не разрешит автоматическое нажатие, которое происходит в фоновом режиме, без уведомления пользователей (если не определено, вы получите сообщение об ошибке, прочтите подробнее). Функция urlBase64ToUint8Array () преобразует наш открытый ключ в соответствующий формат. После подписки. он вернет PushSubscription, который мы можем отправить на сервер. Внутри второго then () мы отправляем PushSubscription на наш сервер с помощью функции storePushSubscription (). Перед его определением мы должны определить urlBase64ToUint8Array ():

Наш storePushSubscription () выглядит так:

Вышеупомянутая функция выполняет запрос POST для маршрута / push. Мы получаем токен CSRF из метатега, который важен для нашего запроса ajax. Этот метатег был добавлен, когда мы создали каркас аутентификации.

Сохранение PushSubscription в базе данных

Начнем с наших маршрутов (добавьте его в свой web.php, а не в api.php, потому что нам нужен доступ к аутентифицированному пользователю):

Давайте создадим наш PushController:

php artisan make:controller PushController

Теперь откройте PushController и добавьте метод store:

Мы можем использовать updatePushSubscription () для создания или обновления PushSubscriber (поскольку мы добавили эту особенность в нашу модель User). Если это было успешно, мы получим сообщение об успешном завершении на консоли. Обратите внимание, что всякий раз, когда вы посещаете / маршрутизируете, вы не увидите сообщение «Service Worker установлен», потому что мы добавили скрипт в файл макета приложения, который не используется в режиме приветствия. Теперь обновите страницу, и вы увидите окно разрешений:

Когда вы нажмете Разрешить, вы увидите PushSubscription и сообщение об успешном завершении в консоли:

Теперь нам нужно создать Уведомление в Laravel для отправки Push-уведомлений:

php artisan make:notification PushDemo

Откройте класс уведомлений, который находится в каталоге app / Notifcations, и добавьте этот код:

Внутри метода toWebPush () у нас есть заголовок уведомления для заголовка нашего уведомления, в теле будет дополнительный текст, значок - это изображение, отображаемое в уведомлении, а действие отобразит кнопку с уведомлением (вы можете добавить больше опций и узнать больше об этих опциях). Теперь мы можем отправлять уведомления с помощью Notification :: send () нашего контроллера. Давайте определим внутри нашего контроллера метод push:

добавить новый маршрут в web.php:

Нам понадобится кнопка для отправки уведомлений, поэтому давайте добавим ее в представление home.blade.php. Поместите его в div с классом card-body:

Теперь последний шаг - добавить прослушиватель событий, который будет прослушивать событие push в файле работника службы sw.js, расположенном в общедоступном каталоге:

Внутри прослушивателя push-события мы сначала проверяем, разрешены ли и поддерживаются ли уведомления, после чего мы получаем доступ к данным уведомления из объекта e с помощью e.data и преобразовав его в json с помощью метода json (). В сервис-воркерах waitUntil () используется, чтобы сообщить браузеру, что задача запущена и не должна завершаться. мы можем отображать уведомление с помощью serviceWorkerRegistration.showNotification (заголовок, параметры). Убедитесь, что вы отметили опцию обновления при перезагрузке на вкладке приложения в инструментах разработчика.

Теперь мы можем проверить это, щелкнув эту кнопку.

Каждый браузер и операционная система имеют собственный способ отображения уведомлений. Я использую Chrome на Ubuntu. В Chrome не отображается значок, в то время как в Firefox.

и когда вы наведете на него курсор, это будет выглядеть так:

Вот как это выглядит в Firefox (не показывает действия с уведомлениями):

Уведомления для гостевых пользователей (новинка)

Пожалуйста, прочтите приведенное выше руководство, прежде чем внедрять гостевые уведомления

В большинстве случаев мы хотим, чтобы все посетители нашего веб-сайта получали push-уведомления, так что давайте поработаем над этим. Сначала нам нужно обновить миграции и создать несколько новых миграций. Откройте перенос push_subscriptions и обновите user_id на guest_id:

Удалите ограничение внешнего ключа:

Давайте создадим гостевую модель и ее перенос, связанный с принудительной подпиской:

php artisan make:model Guest -m

Внутри переноса таблицы гости у нас есть уникальный столбец конечная точка, который будет использоваться для идентификации каждой принудительной подписки:

Нам нужна еще одна миграция, которая создаст ограничение внешнего ключа между этими таблицами:

php artisan make:migration add_foreign_to_guest_id_in_push_subscriptions_table --table=push_subscriptions

Откройте миграцию и добавьте следующее внешнее ограничение внутри метода up ():

Создайте все таблицы с помощью команды миграции. Теперь откройте модель Гость и добавьте следующее:

Мы импортируем типаж Notifiable, чтобы использовать уведомления Laravel (он уже импортирован в модели User). Переопределение метода pushSubscriptionBelongsToUser () важно, поскольку мы не используем аутентифицированного пользователя.

Последним шагом будет изменение нашего PushController, чтобы открыть контроллер и сначала заменить все использования модели User на модель Guest. После этого замените строку ниже внутри метода store ():

С участием:

Конечно, вам необходимо удалить директиву @auth, которая блокирует включение нашего скрипта enable-push.js, и все готово.

Возможно, вы захотите развернуть его на heroku, у которого есть бесплатная версия с https (если вы хотите протестировать его на мобильных устройствах). Что касается UX, было бы неплохо создать что-то вроде кнопки, которая будет запускать initPush (). Просто не рекомендуется запрашивать разрешение на уведомление с самого начала, когда наши пользователи не знают, какие уведомления они получают.

Выше был всего лишь базовый пример использования push-уведомлений. Вы можете копнуть глубже, если хотите, в docs разработчиков google.

Спасибо, что прочитали это руководство, и не стесняйтесь комментировать, если вы застряли. Вы можете найти репозиторий с исходным кодом / Github ЗДЕСЬ. Отделение для уведомлений о гостях находится ЗДЕСЬ.

Обратите внимание, что ‹? Php в примерах кода используется только для выделения синтаксиса.