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

1. Обзор

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

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

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

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

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

2. Настройте

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

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

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

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

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

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

После установки приложения «Веб-сервер для 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. Откройте DevTools: 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 DevTools на 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-сообщения поддерживаются браузером, и вы сможете проверить, подписан ли пользователь в настоящее время на рассылку сообщений или нет.

Вам нужно будет создать две функции в 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 в консоли.

а1553f4a0483d227.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-сообщения.

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

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 в кружке в строке URL-адреса и изменить разрешение «Уведомления» на «Использовать глобальное значение по умолчанию» (Спросить) .

54495592074f10ae.png

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

d4cf22468f6defda.png

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

7. Обработка push-события

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

Прежде чем вы узнаете, как отправить 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', ... );

(Если вы раньше не играли с веб-воркерами, 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-сообщения и убедитесь, что в консоли User IS subscribed . На панели приложений в DevTools на вкладке Service Workers нажмите кнопку «Нажать» :

1ee499267eeccd1c.png

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

379105dfb0ea56d8.png

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

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-сообщение в DevTools и щелкните уведомление. Теперь вы увидите закрытие уведомления и открытие новой вкладки.

9. Отправляйте push-сообщения

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

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

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

bb202867962a0249.png

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

a0dd93bc33a9e8cf.png

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

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

a5e8e89411ec034.png

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

f6815a356d4f9aaa.png

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

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

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

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

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

Единственное, чего не хватает, — это возможности отписать пользователя от push-уведомлений. Для этого вам нужно вызвать 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-сообщения» или «Отключить push-сообщения» в вашем веб-приложении, и в журналах будет показано, что пользователь подписался и отписался.

81a07119235b53da.png

11. Готово

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

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

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

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

Соответствующие сообщения в блоге