Как сделать push-уведомления на сайте для Chrome (часть 1)

Биполярник
6 min readMay 12, 2016

--

С 2015 года начала стремительно набирать популярность технология Push API от Chrome. Все чаще, заходя на различные новостные (и не только новостные) сайты, посетителям вылетает вот такой системный фрейм с запросом:

Системное окно Google Chrome, запрашивающее разрешение на доставку уведомлений от сайта.

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

Однако сегодня эта технология еще довольно молода и руководств по её использованию мало не только в отечественном интернете, но и в зарубежном. Для примера далеко ходить не надо — даже сам “Google”, когда анонсировал Push API, выпустил до слёз скудный пресс-релиз. И только сейчас, несколько часов покопавшись в гугловских FAQ для разработчиков, можно собрать информацию, чтобы собрать худо-бедно работающие скрипты для отправки Push-уведомлений своим читателям.

Как же сделать такие Push-уведомления для своего сайта? Тут есть два пути: использовать сторонние сервисы (они уже есть и некоторые из них очень даже неплохи) или создать собственное решение. Поскольку я сторонник минимального использования сторонних сервисов на сайте, то наш путь в Городе был предрешен.

Но, ради справедливости, стоит замолвить пару словечек и о внешних решениях. Признаюсь, я не очень изучал этот рынок (причина названа чуть выше), однако нельзя не упомянуть сервис OneSignal, самая привлекательная черта которого в том, что их услуги абсолютно бесплатны — зарабатывают они на продаже данных о посетителях клиентского сайта. Так же есть сервис Jeapie, на их стороне очень грамотный маркетинг и, как правило, хорошие отзывы. Однако стоит отметить, что в свое время от их услуг отказалась Медуза — Платформа была попросту не готова к тому количеству пушей, которые приходилось отправлять для огромной аудитории Медузы.

Реализация. Получение учетных данных от Google.

В исходных данных сайт, написанный на Rails 3.2.8 и задача сделать на нём пушер уведомлений для Chrome.

Первым делом необходимо перевести сайт на HTTPS (защищённый гипертекстовый протокол), то есть сделать для своего сайта SSL-сертификат. Без него пуши работать не будут (не проверял с обычным http, но так везде пишут). О том, что такое SSL, с чем его едят, как поставить сертификат на сервер и подключить его, я писать не буду — интернет пестрит подобными статьями. Лишь порекомендую для этих целей StartSSL. Это хороший Удостоверяющий центр, с которым дружат все известные мне браузеры, с нарочито простой процедурой регистрации и верификации (нужно лишь минимально знать английский язык) для получения абсолютно бесплатного SSL-сертификата начального уровня, в который можно включить еще пять(sic!) субдоменов.

Итак, мы получили сертификат и соответствующим образом настроили свой Nginx или Apache. Теперь в адресной строке браузера рядом с адресом нашего сайта горит зелёненьким симпатичнейший замочек, надпись https://, и, если вам не жалко денег, еще название организации.

Далее идем в Google Сloud Platform, где регистрируем новый проект, назвав его, например, MySite-Push.

Создание нового проекта в Coogle Cloud Platform

Через несколько секунд, когда проект будет создан, через раздел Подключение к API Google, по ссылке Включить и настроить API переходим в раздел, где целый список методов API для всех сервисов Google. Там мы должны включить метод Google Cloud Messaging из раздела Mobile API.

метод Google Cloud Messaging из раздела Mobile API

Скорее всего, при подключении к методу, Google попросит зарегистрировать дополнительные данные. Например, попросит уточнить откуда будет вызываться API, тогда мы указываем необходимый нам тип обработчика (например, Веб-сервер).

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

Сгенерированный закрытый ключ для доступа к Google API

После нажатия кнопки Готово мы окажемся на странице, где нужно будет указать домен и подтвердить на него права через инструменты Search Console. Об этом тоже довольно много статей в интернете, да и сама процедура интуитивно понятна. Так что не будем здесь останавливаться.

Далее возвращаемся на главную страницу нашего проекта MySite-Push и запоминаем индикатор нашего проекта. Он нам тоже пригодится.

По сути, нам больше от Coogle Cloud Platform ничего и не надо. Ключ и идентификатор.

Реализация. Первичная настройка сайта.

Теперь в корневую папку нашего сайта нам нужно добавить файл manifest.json, в котором будет указано следующее:

{
"name": "mysite.ru Push test", // Название сайта
"display": "standalone", // Указываем, где показывать уведомления
"gcm_sender_id": "258466066904" // Тот самый идентификатор приложения в Google Cloud Platform
}

Это самый необходимый минимум информации для манифеста. Можно погуглить и узнать, какие дополнительные параметры там можно указывать.

Ну и добавить в секцию <head></head> мета-тег со ссылкой на манифест:

<link rel="manifest" href="/manifest.json">

Теперь там же, в корневой папке, создаем файл push.js, куда вписываем вот такой код:

'use strict';
function SendPushMe() {
if ('serviceWorker' in navigator) {
console.log('Service Worker is supported');
navigator.serviceWorker.register('/sw.js').then(function() {
return navigator.serviceWorker.ready;
}).then(function(reg) {
console.log('Service Worker is ready :^)', reg);
reg.pushManager.subscribe({userVisibleOnly: true}).then(function(sub) {
console.log('endpoint:', sub.endpoint);
$.get( "https://mysite.ru/createpushadresat?adresat=" + sub.endpoint, function( data ) {});
});
}).catch(function(error) {
console.log('Service Worker error :^(', error);
});
}
}

Что делает этот код? При вызове метода SendPushMe() он проверяет поддерживает ли браузер подписку на пуши. Затем, если поддерживает (в лог-консоли разработчика появится сообщение “Service Worker is supported”, в противном случае там же появится сообщение об ошибке), попытается зарегистрировать Service Worker, который скоро появится по адресу /sw.js. Именно в этот момент пользователь увидит запрос от браузера на подтверждение действия. Затем, если пользователь даст согласие, воркер будет зарегистрирован, а по адресу https://mysite.ru/createpushadresat GET-запросом в переменной adresat будет передан уникальный идентификатор браузера. Он же отобразится в лог-консоли разработчика.

Добавим ссылку на этот скрипт в <head></head> нашего сайта:

<script type="text/javascript" src="/push.js"></script>

Теперь создадим Service Worker. Это будет файл sw.js в корневой папке:

'use strict';

self.addEventListener('install', function(event) {
event.waitUntil(self.skipWaiting());
});

self.addEventListener('push', function (event) {
event.waitUntil(
fetch('/latest.json').then(function (response) {
if (response.status !== 200) {
console.log('Latest.json request error: ' + response.status);
throw new Error();
}

return response.json().then(function (data) {
if (data.error || !data.notification) {
console.error('Latest.json Format Error.', data.error);
throw new Error();
}

var title = data.notification.title;
var body = data.notification.body;
var icon = 'https://mysite.ru/my_beautiful_push_icon.png';

return self.registration.showNotification(title, {
body: body,
icon: icon,
data: {
url: data.notification.url
}
});
}).catch(function (err) {
console.error('Retrieve data Error', err);
});
})
);
});

self.addEventListener('notificationclick', function (event) {
event.notification.close();
var url = event.notification.data.url;
event.waitUntil(clients.openWindow(url));
});

Этот код после его вызова создает уведомление, данные для которого берет из файла latest.json, расположенного по адресу https://mysite.ru/latest.json. Если запрос этого файла не удался, или сайт ответил невалидным json, в лог-консоли разработчика появится соответствующая запись. Если же все хорошо, будет сформирован пуш. Пуш формируется из переменных body — это короткое текстовое сообщение, title — заголовок пуша, url — ссылка, по которой перейдет пользователь при клике на уведомление и icon — красивой и восхитительной (желательно квадратной, со стороной не меньше 150px) иконкой, на которой будет показан логотип сайта. Причем конкретно в этом скрипте icon — статичный параметр, а все остальные динамично обновляются из latest.json.

Можно скрипт чуть передать, чтобы и иконка была динамичным параметром, но, как мне кажется, это будет абсолютно лишним, лучше уведомления брендировать, чем снабжать изображением, которое толком и не рассмотришь в небольшом пуше.

Ну и, наконец, создаем latest.json, из которого и будет браться информация для уведомлений. Думаю, не трудно догадаться, что лежать он будет в корневой папке. А вот и его содержимое:

{"notification":{"url":"https://mysite.ru/posts/1","title":"Крутейшая новость","body":"Мы сделали офигительную подписку для Chrome"},"_id":319}

Полагаю, объяснять что есть что в этом json’е нет смысла, всё и так понятно.

По идее, уже сейчас наш сайт, а вернее его фронтенд, практически полностью готов. Осталось лишь научиться говорить Google, что у нас появились новые обновления, чтобы тот, в свою очередь, сообщал об этом браузерам наших подписчиков. Ну и, разумеется, динамически обновлять наш latest.json. Однако, это уже в следующей части.

P.S. Кстати, уже сейчас можно вызвать SendPushMe() и посмотреть, что произойдет. Для этого, например, можно создать ссылку, по клику которой будет этот метод и вызываться:

<a href="#"  onclick="SendPushMe();return false">Вызвать SendPushMe</a>

--

--

Биполярник

Пытаюсь каждый день. Кроме выходных и праздников. C 9:00 до 16:42. Обед: 12:30 - 13:30