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

1. Обзор

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

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

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

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

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

2. Настройка

Скачать пример кода

Пример кода для этого практического занятия можно получить двумя способами:

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

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

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

Хотя вы можете использовать собственный веб-сервер, этот практический пример разработан для корректной работы с приложением Web Server for Chrome. Если у вас еще не установлено это приложение, вы можете загрузить его из Chrome Web Store:

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

946bcaaad66e5c8e.png

В окне «Приложения» щелкните значок «Веб-сервер»:

9f3c21b2cf6cbfb5.png

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

73543edeb27c3d6f.png

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

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

5ac11bca86ce7369.png

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

d42f87972f9fec24.png

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

00-push-codelab.png

Всегда сообщайте о состоянии сервисного работника.

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

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

  1. Перейдите на вкладку Push Codelab .
  2. Откройте инструменты разработчика: Ctrl-Shift-I в Windows и Linux, Cmd-Option-I в macOS.
  3. Выберите панель «Приложение» , перейдите на вкладку «Сервисные работники» и установите флажок «Обновлять при перезагрузке» . Если этот флажок установлен, сервисный работник принудительно обновляется каждый раз при перезагрузке страницы.

e7d384fb77885b99.png

3. Зарегистрируйте работника сферы услуг.

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

В каталоге вашего 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 на наличие Service Worker is registered message , примерно такого вида:

5d7ad383d6f235d5.png

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

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

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

push-codelab-04-companion.png

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

const applicationServerPublicKey = '<Your Public Key>';

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

4. Инициализация состояния

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

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

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

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

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

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 .

a1553f4a0483d227.png

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

5. Подпишите пользователя.

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

В данный момент кнопка «Включить 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-уведомления.

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

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

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

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

Вызов метода 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 , обновите страницу и нажмите кнопку. Вы должны увидеть запрос на предоставление разрешений, похожий на этот:

fcc61267a0194e81.png

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

5c5505f2ead037c.png

6. Доступ к обработке запрещен.

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

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

Наиболее подходящее место для обработки этой ситуации — функция 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» в кружке в адресной строке и изменить разрешение «Уведомления» на «Использовать глобальные настройки по умолчанию (Запрашивать)» .

54495592074f10ae.png

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

d4cf22468f6defda.png

Благодаря этому изменению теперь можно подписать пользователя, предварительно учтя все возможные сценарии предоставления прав доступа.

7. Обработка события 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-уведомления и убедитесь, что в консоли отображается User IS subscribed ». В панели «Приложение» в инструментах разработчика, на вкладке «Service Workers» , нажмите кнопку «Push» :

1ee499267eeccd1c.png

После нажатия кнопки «Push» вы должны увидеть уведомление примерно такого вида:

379105dfb0ea56d8.png

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

8. Нажатие на уведомление

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

Если вы нажмете на одно из этих уведомлений, вы заметите, что ничего не происходит. Вы можете обрабатывать нажатия на уведомления, отслеживая события 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 .

В первую очередь код закрывает уведомление, по которому был нажат клик:

event.notification.close();

Затем откроется новое окно или вкладка, загружающая URL-адрес https://developers.google.com/web . Вы можете изменить его по своему усмотрению.

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

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

Попробуйте!

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

9. Отправка push-уведомлений

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

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

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

bb202867962a0249.png

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

a0dd93bc33a9e8cf.png

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

Нажмите кнопку «Отправить push-уведомление» .

a5e8e89411ec034.png

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

f6815a356d4f9aaa.png

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

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

Весь код сопутствующего сайта можно посмотреть здесь .

10. Отписаться от пользователя

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

Единственное, чего не хватает, — это возможности отписаться пользователя от рассылки. Для этого необходимо вызвать 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() для неё, что делает 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() . Вы также добавляете обработчик catch на случай, если вызов unsubscribe() приведет к ошибке. После этого вы можете обновить свой пользовательский интерфейс.

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

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

  updateBtn();
})

Попробуйте!

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

81a07119235b53da.png

11. Завершено

Поздравляем с завершением этого практического занятия!

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

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

Дополнительная информация

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