Добавление push-уведомлений в веб-приложение

Push-сообщения — это простой и эффективный способ повторного взаимодействия с вашими пользователями. В этой лаборатории кода вы узнаете, как добавить push-уведомления в свое веб-приложение.

Что вы узнаете

  • Как подписаться и отписаться от пользователя для push-рассылок
  • Как обрабатывать входящие push-сообщения
  • Как отобразить уведомление
  • Как реагировать на клики уведомлений

Что вам понадобится

  • Chrome 52 или выше
  • Веб-сервер для Chrome или ваш собственный веб-сервер по выбору
  • Текстовый редактор
  • Базовые знания HTML, CSS, JavaScript и Chrome DevTools
  • Пример кода (см. раздел «Настройка»).

Загрузите пример кода

У вас есть два варианта получения примера кода для этой лаборатории кода:

  • Клонируйте репозиторий Git:
git clone https://github.com/GoogleChrome/push-notifications.git
  • Загрузите ZIP-файл:

Скачать исходный код

Если вы загрузите исходный код в виде ZIP-файла, при его распаковке вы получите корневую папку push-notifications-master .

Установите и проверьте веб-сервер

Несмотря на то, что вы можете использовать свой собственный веб-сервер, эта лаборатория кода хорошо работает с приложением «Веб-сервер для Chrome». Если у вас еще не установлено это приложение, вы можете получить его в Интернет-магазине Chrome:

Установить веб-сервер для Chrome

После установки приложения «Веб-сервер для Chrome» щелкните ярлык « Приложения » на панели закладок:

В окне приложений щелкните значок веб-сервера:

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

Нажмите кнопку « Выбрать папку » и выберите папку app в загруженной папке push-notifications . Это позволяет вам обслуживать текущую работу через URL-адрес, указанный в разделе URL-адреса веб-сервера диалогового окна.

В разделе « Параметры » установите флажок « Автоматически показывать index.html », как показано ниже:

Затем остановите и перезапустите сервер, сдвинув переключатель Веб-сервер: ЗАПУЩЕН влево, а затем обратно вправо.

Щелкните URL-адрес веб-сервера, чтобы посетить свой сайт в веб-браузере. Вы должны увидеть страницу, которая выглядит так, хотя в вашей версии в качестве адреса может отображаться 127.0.0.1:8887:

00-push-codelab.png

Всегда обновлять сервис-воркер

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

Чтобы настроить это в Chrome:

  1. Перейдите на вкладку Push Codelab .
  2. Откройте DevTools: Ctrl-Shift-I в Windows и Linux, Cmd-Option-I в macOS.
  3. Выберите панель приложения , перейдите на вкладку Service Workers и установите флажок Update on Reload . Когда этот флажок установлен, сервис-воркер принудительно обновляется каждый раз при перезагрузке страницы.

Завершенный код

Обратите внимание, что в каталоге вашего app есть пустой файл с именем sw.js Этот файл будет вашим сервис-воркером. Пока он может оставаться пустым. Вы добавите к нему код позже.

Во-первых, вам нужно зарегистрировать этот файл как сервис-воркер.

Ваша страница app/index.html загружает scripts/main.js . Вы регистрируете своего сервисного работника в этом файле JavaScript.

Добавьте следующий код в scripts/main.js :

if ('serviceWorker' in navigator && 'PushManager' in window) {
  console.log('Service Worker and Push are supported');

  navigator.serviceWorker.register('sw.js')
  .then(function(swReg) {
    console.log('Service Worker is registered', swReg);

    swRegistration = swReg;
  })
  .catch(function(error) {
    console.error('Service Worker Error', error);
  });
} else {
  console.warn('Push messaging is not supported');
  pushButton.textContent = 'Push Not Supported';
}

Этот код проверяет, поддерживаются ли сервис-воркеры и push-сообщения вашим браузером. Если они поддерживаются, код регистрирует ваш файл sw.js

Попробуйте

Проверьте свои изменения, обновив вкладку Push Codelab в браузере.

Проверьте консоль в Chrome DevTools на наличие Service Worker is registered message Registered, например:

Получить ключи сервера приложений

Для работы с этой лабораторией кода вам необходимо сгенерировать ключи сервера приложений. Вы можете сделать это на сопутствующем сайте: web-push-codelab.glitch.me

Здесь вы можете сгенерировать пару открытого и закрытого ключей.

push-codelab-04-companion.png

Скопируйте свой открытый ключ в scripts/main.js заменив значение <Your Public Key> :

const applicationServerPublicKey = '<Your Public Key>';

Важно: вы никогда не должны помещать свой закрытый ключ в свое веб-приложение!

Завершенный код

На данный момент кнопка « Включить » в веб-приложении отключена, и ее нельзя нажать. Это связано с тем, что рекомендуется отключать кнопку по умолчанию и включать ее после того, как вы узнаете, что браузер поддерживает push-сообщения, и вы можете проверить, подписан ли пользователь в настоящее время на обмен сообщениями или нет.

Вам нужно будет создать две функции в scripts/main.js :

  • initializeUI , чтобы проверить, подписан ли пользователь в данный момент
  • updateBtn , чтобы включить вашу кнопку и изменить текст в зависимости от того, подписан пользователь или нет

Добавьте функцию initializeUI в main.js следующим образом:

function initializeUI() {
  // Set the initial subscription value
  swRegistration.pushManager.getSubscription()
  .then(function(subscription) {
    isSubscribed = !(subscription === null);

    if (isSubscribed) {
      console.log('User IS subscribed.');
    } else {
      console.log('User is NOT subscribed.');
    }

    updateBtn();
  });
}

Ваш новый метод использует swRegistration из предыдущего шага, получает от него свойство pushManager и вызывает getSubscription() .

pushManager . getSubscription() возвращает обещание, которое разрешается с текущей подпиской, если она есть. В противном случае возвращается null . При этом вы можете проверить, подписан ли пользователь, установить значение isSubscribed , а затем вызвать updateBtn() для обновления кнопки.

Добавьте updateBtn() в main.js :

function updateBtn() {
  if (isSubscribed) {
    pushButton.textContent = 'Disable Push Messaging';
  } else {
    pushButton.textContent = 'Enable Push Messaging';
  }

  pushButton.disabled = false;
}

Эта функция включает кнопку и изменяет текст кнопки в зависимости от того, подписан пользователь или нет.

Последнее, что нужно сделать, это вызвать initializeUI() , когда ваш сервис-воркер зарегистрирован в main.js :

navigator.serviceWorker.register('sw.js')
.then(function(swReg) {
  console.log('Service Worker is registered', swReg);

  swRegistration = swReg;
  initializeUI();
})

Попробуйте

Обновите вкладку Push Codelab . Вы должны увидеть, что кнопка « Включить push-сообщения » теперь включена (вы можете щелкнуть ее), и вы должны увидеть, что User is NOT subscribed в консоли.

По мере прохождения остальной части этой кодовой лаборатории вы должны видеть изменение текста кнопки всякий раз, когда вы подписываетесь или отказываетесь от подписки.

Завершенный код

На данный момент ваша кнопка « Включить push-сообщения » мало что делает. Давайте исправим это.

В функции initializeUI() добавьте прослушиватель кликов для вашей кнопки:

function initializeUI() {
  pushButton.addEventListener('click', function() {
    pushButton.disabled = true;
    if (isSubscribed) {
      // TODO: Unsubscribe user
    } else {
      subscribeUser();
    }
  });

  // Set the initial subscription value
  swRegistration.pushManager.getSubscription()
  .then(function(subscription) {
    isSubscribed = !(subscription === null);

    updateSubscriptionOnServer(subscription);

    if (isSubscribed) {
      console.log('User IS subscribed.');
    } else {
      console.log('User is NOT subscribed.');
    }

    updateBtn();
  });
}

Когда пользователь нажимает кнопку, вы отключаете кнопку, чтобы гарантировать, что пользователь не сможет нажать ее во второй раз, поскольку подписка на push-сообщения может занять некоторое время.

Затем вы вызываете subscribeUser() , если пользователь в данный момент не подписан. Для этого вам нужно вставить следующий код в scripts/main.js :

function subscribeUser() {
  const applicationServerKey = urlB64ToUint8Array(applicationServerPublicKey);
  swRegistration.pushManager.subscribe({
    userVisibleOnly: true,
    applicationServerKey: applicationServerKey
  })
  .then(function(subscription) {
    console.log('User is subscribed.');

    updateSubscriptionOnServer(subscription);

    isSubscribed = true;

    updateBtn();
  })
  .catch(function(error) {
    console.error('Failed to subscribe the user: ', error);
    updateBtn();
  });
}

Давайте рассмотрим, что делает этот код и как он подписывает пользователя на push-сообщения.

Во-первых, вы берете открытый ключ сервера приложений, который закодирован в безопасном для URL-адресов формате Base64 , и преобразуете его в UInt8Array , потому что это ожидаемый ввод вызова subscribe() . Функция urlB64ToUint8Array() находится в верхней части scripts/main.js .

После того, как вы преобразовали значение, вы вызываете метод subscribe() в pushManager сервисного работника, передавая открытый ключ вашего сервера приложений и значение userVisibleOnly: true .

const applicationServerKey = urlB64ToUint8Array(applicationServerPublicKey);
swRegistration.pushManager.subscribe({
  userVisibleOnly: true,
  applicationServerKey: applicationServerKey
})

Параметр userVisibleOnly гарантирует, что вы будете показывать уведомление каждый раз, когда отправляется push-сообщение. В настоящее время это значение является обязательным и должно быть истинным.

Вызов subscribe() возвращает обещание, которое будет разрешено после следующих шагов:

  1. Пользователь предоставил разрешение на отображение уведомлений.
  2. Браузер отправил сетевой запрос службе push-уведомлений, чтобы получить данные, необходимые для создания PushSubscription .

Обещание subscribe() разрешится с помощью PushSubscription , если эти шаги были успешными. Если пользователь не предоставляет разрешение или возникают какие-либо проблемы с подпиской пользователя, обещание будет отклонено с ошибкой. Это дает вам следующую цепочку обещаний в вашей лаборатории кода:

swRegistration.pushManager.subscribe({
  userVisibleOnly: true,
  applicationServerKey: applicationServerKey
})
.then(function(subscription) {
  console.log('User is subscribed.');

  updateSubscriptionOnServer(subscription);

  isSubscribed = true;

  updateBtn();

})
.catch(function(err) {
  console.log('Failed to subscribe the user: ', err);
  updateBtn();
});

При этом вы либо получаете подписку и относитесь к пользователю как к подписчику, либо ловите ошибку и регистрируете ее в консоли. В обоих сценариях вы вызываете updateBtn() , чтобы убедиться, что кнопка снова активна и имеет соответствующий текст.

В реальном приложении функция updateSubscriptionOnServer() — это место, где вы отправляете данные подписки на серверную часть, но для лаборатории кода вы просто отображаете подписку в своем пользовательском интерфейсе. Добавьте следующую функцию в scripts/main.js :

function updateSubscriptionOnServer(subscription) {
  // TODO: Send subscription to application server

  const subscriptionJson = document.querySelector('.js-subscription-json');
  const subscriptionDetails =
    document.querySelector('.js-subscription-details');

  if (subscription) {
    subscriptionJson.textContent = JSON.stringify(subscription);
    subscriptionDetails.classList.remove('is-invisible');
  } else {
    subscriptionDetails.classList.add('is-invisible');
  }
}

Попробуйте

Перейдите на вкладку Push Codelab , обновите страницу и нажмите кнопку. Вы должны увидеть запрос разрешения, подобный этому:

Если вы дадите разрешение, вы должны увидеть, что User is subscribed на консоль. Текст кнопки изменится на « Отключить push-сообщения », и вы сможете просмотреть подписку в виде данных JSON внизу страницы.

Завершенный код

Одна вещь, которую вы еще не обработали, — это то, что произойдет, если пользователь заблокирует запрос на разрешение. Это требует особого рассмотрения, потому что, если пользователь заблокирует разрешение, ваше веб-приложение не сможет повторно отобразить запрос на разрешение и не сможет подписаться на пользователя. Вам нужно как минимум отключить кнопку, чтобы пользователь знал, что ее нельзя использовать.

Очевидное место для обработки этого сценария — updateBtn() . Все, что вам нужно сделать, это проверить значение Notification.permission , например:

function updateBtn() {
  if (Notification.permission === 'denied') {
    pushButton.textContent = 'Push Messaging Blocked';
    pushButton.disabled = true;
    updateSubscriptionOnServer(null);
    return;
  }

  if (isSubscribed) {
    pushButton.textContent = 'Disable Push Messaging';
  } else {
    pushButton.textContent = 'Enable Push Messaging';
  }

  pushButton.disabled = false;
}

Вы знаете, что если разрешение denied , то пользователь не может быть подписан, и вы больше ничего не можете сделать, поэтому навсегда отключить кнопку — лучший подход.

Попробуйте

Поскольку вы уже предоставили разрешение для своего веб-приложения на предыдущем шаге, вам нужно щелкнуть значок i в кружке в строке URL-адреса и изменить разрешение уведомлений на Использовать глобальное значение по умолчанию (Спросить) .

После изменения этого параметра обновите страницу, нажмите кнопку « Включить push-сообщения » и выберите « Блокировать » в диалоговом окне разрешений. Кнопка будет отключена и покажет текст Push Messaging Blocked .

С этим изменением теперь вы можете подписаться на пользователя, позаботившись о возможных сценариях разрешений.

Завершенный код

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

Когда вы инициируете push-сообщение, браузер получает push-сообщение, выясняет, для какого сервис-воркера оно предназначено, пробуждает этого сервис-воркера и отправляет push-событие. Вам нужно прослушать это событие и показать уведомление в результате.

Добавьте следующий код в файл sw.js :

self.addEventListener('push', function(event) {
  console.log('[Service Worker] Push Received.');
  console.log(`[Service Worker] Push had this data: "${event.data.text()}"`);

  const title = 'Push Codelab';
  const options = {
    body: 'Yay it works.',
    icon: 'images/icon.png',
    badge: 'images/badge.png'
  };

  event.waitUntil(self.registration.showNotification(title, options));
});

Давайте пройдемся по этому коду. Вы прослушиваете push -события в сервис-воркере, добавляя прослушиватель событий:

self.addEventListener('push', ... );

(Если вы раньше не играли с Web Workers, self , вероятно, новинка. В файле сервис-воркера self ссылается на самого сервис-воркера.)

Когда push-сообщение получено, будет вызван прослушиватель событий, и вы создадите уведомление, вызвав showNotification() в свойстве registration сервис-воркера. showNotification() требует title ; вы также можете дать ему объект options чтобы установить основное сообщение, значок и значок. (Значок используется только на Android на момент написания.)

const title = 'Push Codelab';
const options = {
  body: 'Yay it works.',
  icon: 'images/icon.png',
  badge: 'images/badge.png'
};
self.registration.showNotification(title, options);

Последнее, что нужно рассмотреть при обработке push -событий, — это event.waitUntil() . Этот метод принимает обещание, позволяющее браузеру поддерживать работоспособность вашего сервисного работника до тех пор, пока переданное обещание не будет разрешено.

Чтобы сделать приведенный выше код немного более понятным, вы можете переписать его так:

const notificationPromise = self.registration.showNotification(title, options);
event.waitUntil(notificationPromise);

Теперь, когда вы прошли через push-событие, давайте протестируем push-событие.

Попробуйте

С обработкой push-событий в сервис-воркере вы можете инициировать поддельное push-событие, чтобы проверить, что происходит при получении сообщения.

В своем веб-приложении подпишитесь на push-сообщения и убедитесь, что в консоли User IS subscribed . На панели приложения в DevTools на вкладке Service Workers нажмите кнопку Push :

После того, как вы нажмете Push , вы должны увидеть такое уведомление:

Примечание. Если этот шаг не работает, попробуйте отменить регистрацию вашего сервисного работника с помощью ссылки Отменить регистрацию на панели приложения DevTools , подождите, пока сервисный работник будет остановлен, а затем перезагрузите страницу.

Завершенный код

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

Начните с добавления прослушивателя notificationclick в sw.js :

self.addEventListener('notificationclick', function(event) {
  console.log('[Service Worker] Notification click received.');

  event.notification.close();

  event.waitUntil(
    clients.openWindow('https://developers.google.com/web')
  );
});

Когда пользователь щелкает notificationclick , вызывается прослушиватель событийnotificationclick.

Код сначала закрывает уведомление, которое было нажато:

event.notification.close();

Затем открывается новое окно или вкладка с загрузкой URL-адреса https://developers.google.com/web . Не стесняйтесь изменить это.

event.waitUntil(
    clients.openWindow('https://developers.google.com/web/')
  );

event.waitUntil() гарантирует, что браузер не завершит сервис-воркер до того, как будет отображено новое окно или вкладка.

Попробуйте

Попробуйте снова запустить push-сообщение в DevTools и щелкните уведомление. Теперь вы увидите, что уведомление закрывается и открывается новая вкладка.

Вы видели, что ваше веб-приложение может отображать уведомление с помощью DevTools, и узнали, как закрыть уведомление одним щелчком мыши. Следующим шагом является отправка фактического push-сообщения.

Обычно для этого требуется отправить подписку с веб-страницы на серверную часть. Затем серверная часть инициирует push-сообщение, выполняя вызов API к конечной точке в подписке.

Это выходит за рамки этой лаборатории кода, но вы можете использовать сопутствующий сайт ( web-push-codelab.glitch.me ), чтобы вызвать реальное push-сообщение. Вставьте подписку внизу страницы:

Затем вставьте это на сопутствующий сайт в текстовую область « Подписка на отправку »:

В разделе Текст для отправки добавьте любую строку, которую вы хотите отправить с push-сообщением.

Нажмите кнопку Отправить push-сообщение .

Затем вы должны получить push-сообщение. Текст, который вы использовали, будет записан в консоль.

Это должно дать вам возможность протестировать отправку и получение данных и в результате управлять уведомлениями.

Сопутствующее приложение — это просто сервер узла, который использует библиотеку веб-push для отправки сообщений. Стоит просмотреть организацию web-push-libs на GitHub , чтобы узнать, какие библиотеки доступны для отправки push-сообщений для вас. Это обрабатывает множество деталей для запуска push-сообщений.

Вы можете увидеть весь код сайта-компаньона здесь .

Завершенный код

Чего не хватает, так это возможности отписать пользователя от push-уведомлений. Для этого вам нужно вызвать unsubscribe unsubscribe() для PushSubscription .

Вернитесь в свой файл scripts/main.js и измените прослушиватель кликов pushButton в initializeUI() на следующее:

pushButton.addEventListener('click', function() {
  pushButton.disabled = true;
  if (isSubscribed) {
    unsubscribeUser();
  } else {
    subscribeUser();
  }
});

Обратите внимание, что сейчас вы собираетесь вызвать новую функцию unsubscribeUser() . В этой функции вы получаете текущую подписку и вызываете для нее функцию unsubscribe() . Добавьте следующий код в scripts/main.js :

function unsubscribeUser() {
  swRegistration.pushManager.getSubscription()
  .then(function(subscription) {
    if (subscription) {
      return subscription.unsubscribe();
    }
  })
  .catch(function(error) {
    console.log('Error unsubscribing', error);
  })
  .then(function() {
    updateSubscriptionOnServer(null);

    console.log('User is unsubscribed.');
    isSubscribed = false;

    updateBtn();
  });
}

Давайте пройдемся по этой функции.

Во-первых, вы получаете текущую подписку, вызывая getSubscription() :

swRegistration.pushManager.getSubscription()

Это возвращает обещание, которое разрешается с помощью PushSubscription , если оно существует; в противном случае возвращается null . Если есть подписка, вы вызываете для нее unsubscribe unsubscribe() , что делает PushSubscription недействительным.

swRegistration.pushManager.getSubscription()
.then(function(subscription) {
  if (subscription) {
    // TODO: Tell application server to delete subscription
    return subscription.unsubscribe();
  }
})
.catch(function(error) {
  console.log('Error unsubscribing', error);
})

Вызов unsubscribe() возвращает обещание, так как его выполнение может занять некоторое время. Вы возвращаете это обещание, поэтому следующий then() в цепочке ждет завершения unsubscribe() . Вы также добавляете обработчик перехвата на случай, если вызов unsubscribe() приведет к ошибке. После этого вы можете обновить свой пользовательский интерфейс.

.then(function() {
  updateSubscriptionOnServer(null);

  console.log('User is unsubscribed.');
  isSubscribed = false;

  updateBtn();
})

Попробуйте

Вы должны иметь возможность нажать « Включить push-сообщения » или « Отключить push-сообщения » в своем веб-приложении, и журналы покажут, что пользователь подписался и отписался.

Поздравляем с завершением этой кодлабы!

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

Если вы хотите развернуть push-уведомления на своем сайте, вам может быть интересно добавить поддержку старых браузеров или браузеров, не соответствующих стандартам, которые используют GCM. Узнайте больше здесь .

дальнейшее чтение

Соответствующие записи в блоге