Push-уведомления в открытой сети

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

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

Начиная с Chrome версии 42, разработчикам доступны Push API и Notification API .

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

Мы также рассмотрим, что будет добавлено в API в будущих версиях Chrome, и, наконец, у нас будет FAQ.

Реализация push-сообщений для Chrome

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

Зарегистрируйте сервисного работника

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

Ниже приведен пример регистрации сервисного работника в вашем веб-приложении. После успешного завершения регистрации мы вызываем метод InitialiseState() , о котором мы вскоре расскажем.

var isPushEnabled = false;

…

window.addEventListener('load', function() {
    var pushButton = document.querySelector('.js-push-button');
    pushButton.addEventListener('click', function() {
    if (isPushEnabled) {
        unsubscribe();
    } else {
        subscribe();
    }
    });

    // Check that service workers are supported, if so, progressively
    // enhance and add push messaging support, otherwise continue without it.
    if ('serviceWorker' in navigator) {
    navigator.serviceWorker.register('/service-worker.js')
    .then(initialiseState);
    } else {
    console.warn('Service workers aren\'t supported in this browser.');
    }
});

Обработчик нажатия кнопки подписывается или отменяет подписку пользователя на рассылку сообщений. isPushEnabled — это глобальная переменная, которая просто отслеживает, подписаны ли в данный момент push-сообщения или нет. На них будут ссылаться во всех фрагментах кода.

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

Настройте исходное состояние

Пример включенного и отключенного пользовательского интерфейса push-сообщений в Chrome.

После регистрации сервисного работника нам необходимо настроить состояние нашего пользовательского интерфейса.

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

В этом документе вы можете найти некоторые рекомендации по UX , а в этой статье мы сосредоточимся на технических аспектах.

На этом этапе вы можете подумать, что есть только два состояния: включено или отключено. Однако есть и другие состояния, связанные с уведомлениями, которые вам необходимо принять во внимание.

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

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

Поскольку большинство этих проверок приводят к отключению нашего пользовательского интерфейса, вам следует установить начальное состояние «Отключено». Это также позволяет избежать путаницы в случае возникновения проблем с JavaScript вашей страницы, например, файл JS не может быть загружен или пользователь отключил JavaScript.

<button class="js-push-button" disabled>
    Enable Push Messages
</button>

Имея это начальное состояние, мы можем выполнить описанные выше проверки в методе initialiseState() , т. е. после регистрации нашего сервис-воркера.

// Once the service worker is registered set the initial state
function initialiseState() {
    // Are Notifications supported in the service worker?
    if (!('showNotification' in ServiceWorkerRegistration.prototype)) {
    console.warn('Notifications aren\'t supported.');
    return;
    }

    // Check the current Notification permission.
    // If its denied, it's a permanent block until the
    // user changes the permission
    if (Notification.permission === 'denied') {
    console.warn('The user has blocked notifications.');
    return;
    }

    // Check if push messaging is supported
    if (!('PushManager' in window)) {
    console.warn('Push messaging isn\'t supported.');
    return;
    }

    // We need the service worker registration to check for a subscription
    navigator.serviceWorker.ready.then(function(serviceWorkerRegistration) {
    // Do we already have a push message subscription?
    serviceWorkerRegistration.pushManager.getSubscription()
        .then(function(subscription) {
        // Enable any UI which subscribes / unsubscribes from
        // push messages.
        var pushButton = document.querySelector('.js-push-button');
        pushButton.disabled = false;

        if (!subscription) {
            // We aren't subscribed to push, so set UI
            // to allow the user to enable push
            return;
        }

        // Keep your server in sync with the latest subscriptionId
        sendSubscriptionToServer(subscription);

        // Set your UI to show they have subscribed for
        // push messages
        pushButton.textContent = 'Disable Push Messages';
        isPushEnabled = true;
        })
        .catch(function(err) {
        console.warn('Error during getSubscription()', err);
        });
    });
}

Краткий обзор этих шагов:

  • Проверяем, что showNotification доступен в прототипе ServiceWorkerRegistration. Без него мы не сможем отображать уведомление от нашего сервис-воркера при получении push-сообщения.
  • Мы проверяем текущее Notification.permission , чтобы убедиться, что оно не "denied" . Отказано в разрешении означает, что вы не можете показывать уведомления, пока пользователь вручную не изменит разрешение в браузере.
  • Чтобы проверить, поддерживается ли push-сообщение, мы проверяем, что PushManager доступен в объекте окна.
  • Наконец, мы использовали pushManager.getSubscription() , чтобы проверить, есть ли у нас уже подписка или нет. Если мы это сделаем, мы отправляем данные о подписке на наш сервер, чтобы убедиться, что у нас есть правильная информация, и настраиваем наш пользовательский интерфейс, чтобы указать, включен ли обмен push-сообщениями или нет. Подробности объекта подписки мы рассмотрим далее в этой статье.

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

Следующим шагом будет обработка того, когда пользователь захочет включить push-сообщения, но прежде чем мы сможем это сделать, нам нужно настроить проект консоли разработчика Google и добавить в наш манифест некоторые параметры для использования Firebase Cloud Messaging (FCM) , ранее известного как как Google Cloud Messaging (GCM).

Создайте проект в консоли разработчика Firebase

Chrome использует FCM для обработки отправки и доставки push-сообщений; однако, чтобы использовать API FCM, вам необходимо настроить проект в консоли разработчика Firebase.

Следующие шаги относятся только к Chrome, Opera для Android и браузеру Samsung, в которых используется FCM. Позже в этой статье мы обсудим, как это будет работать в других браузерах.

Создайте новый проект разработчика Firebase.

Для начала вам необходимо создать новый проект на https://console.firebase.google.com/ , нажав «Создать новый проект».

Скриншот нового проекта Firebase

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

Главная страница проекта Firebase

На этой панели управления щелкните шестеренку рядом с названием вашего проекта в верхнем левом углу и нажмите «Настройки проекта».

Меню настроек проекта Firebase

На странице настроек перейдите на вкладку «Облачные сообщения».

Меню облачных сообщений Firebase Project

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

Добавьте манифест веб-приложения

Для push-подписки нам нужно добавить файл манифеста с полем gcm_sender_id , чтобы обеспечить успешную push-подписку. Этот параметр необходим только Chrome, Opera для Android и браузеру Samsung, чтобы они могли использовать FCM/GCM.

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

Ниже приведен очень простой файл манифеста:

{
    "name": "Push Demo",
    "short_name": "Push Demo",
    "icons": [{
        "src": "images/icon-192x192.png",
        "sizes": "192x192",
        "type": "image/png"
        }],
    "start_url": "/index.html?homescreen=1",
    "display": "standalone",
    "gcm_sender_id": "<Your Sender ID Here>"
}

Вам нужно будет установить значение gcm_sender_id для идентификатора отправителя из вашего проекта Firebase.

После того, как вы сохранили файл манифеста в своем проекте (manifest.json — хорошее имя), сделайте ссылку на него из своего HTML с помощью следующего тега в заголовке вашей страницы.

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

Если вы не добавите веб-манифест с этими параметрами, вы получите исключение при попытке подписаться пользователя на push-сообщения с ошибкой "Registration failed - no sender id provided" или "Registration failed - permission denied" .

Подпишитесь на рассылку push-сообщений

Теперь, когда у вас настроен манифест, вы можете вернуться к JavaScript вашего сайта.

Чтобы подписаться, вам необходимо вызвать метод subscribe() объекта PushManager , доступ к которому осуществляется через ServiceWorkerRegistration .

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

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

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

Следующий код подписывается пользователя на push-сообщения:

function subscribe() {
    // Disable the button so it can't be changed while
    // we process the permission request
    var pushButton = document.querySelector('.js-push-button');
    pushButton.disabled = true;

    navigator.serviceWorker.ready.then(function(serviceWorkerRegistration) {
    serviceWorkerRegistration.pushManager.subscribe()
        .then(function(subscription) {
        // The subscription was successful
        isPushEnabled = true;
        pushButton.textContent = 'Disable Push Messages';
        pushButton.disabled = false;

        // TODO: Send the subscription.endpoint to your server
        // and save it to send a push message at a later date
        return sendSubscriptionToServer(subscription);
        })
        .catch(function(e) {
        if (Notification.permission === 'denied') {
            // The user denied the notification permission which
            // means we failed to subscribe and the user will need
            // to manually change the notification permission to
            // subscribe to push messages
            console.warn('Permission for Notifications was denied');
            pushButton.disabled = true;
        } else {
            // A problem occurred with the subscription; common reasons
            // include network errors, and lacking gcm_sender_id and/or
            // gcm_user_visible_only in the manifest.
            console.error('Unable to subscribe to push.', e);
            pushButton.disabled = false;
            pushButton.textContent = 'Enable Push Messages';
        }
        });
    });
}

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

Прослушиватель push-событий Service Worker

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

self.addEventListener('push', function(event) {
    console.log('Received a push message', event);

    var title = 'Yay a message.';
    var body = 'We have received a push message.';
    var icon = '/images/icon-192x192.png';
    var tag = 'simple-push-demo-notification-tag';

    event.waitUntil(
    self.registration.showNotification(title, {
        body: body,
        icon: icon,
        tag: tag
    })
    );
});

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

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

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

Отправка push-сообщения

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

Это применимо только к браузерам, использующим FCM.

Когда вы отправляете переменную PushSubscription.endpoint на свой сервер, конечная точка для FCM является специальной. В конце URL-адреса есть параметр — registration_id .

Примером конечной точки может быть:

https://fcm.googleapis.com/fcm/send/APA91bHPffi8zclbIBDcToXN_LEpT6iA87pgR-J-MuuVVycM0SmptG-rXdCPKTM5pvKiHk2Ts-ukL1KV8exGOnurOAKdbvH9jcvg8h2gSi-zZJyToiiydjAJW6Fa9mE3_7vsNIgzF28KGspVmLUpMgYLBd1rxaVh-L4NDzD7HyTkhFOfwWiyVdKh__rEt15W9n2o6cZ8nxrP

URL-адрес FCM:

https://fcm.googleapis.com/fcm/send

registration_id будет:

APA91bHPffi8zclbIBDcToXN_LEpT6iA87pgR-J-MuuVVycM0SmptG-rXdCPKTM5pvKiHk2Ts-ukL1KV8exGOnurOAKdbvH9jcvg8h2gSi-zZJyToiiydjAJW6Fa9mE3_7vsNIgzF28KGspVmLUpMgYLBd1rxaVh-L4NDzD7HyTkhFOfwWiyVdKh__rEt15W9n2o6cZ8nxrP

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

Это означает, что на вашем сервере вам нужно будет проверить, предназначена ли конечная точка для FCM, и если да, извлечь Registration_id. Чтобы сделать это в Python, вы можете сделать что-то вроде:

if endpoint.startswith('https://fcm.googleapis.com/fcm/send'):
    endpointParts = endpoint.split('/')
    registrationId = endpointParts[len(endpointParts) - 1]

    endpoint = 'https://fcm.googleapis.com/fcm/send'

Получив регистрационный идентификатор, вы можете вызвать API FCM. Справочную документацию по FCM API можно найти здесь .

Ключевые аспекты, которые следует помнить при звонке в FCM:

  • Заголовок авторизации со значением key=&lt;YOUR_API_KEY&gt; должен быть установлен при вызове API, где &lt;YOUR_API_KEY&gt; — это ключ API из проекта Firebase.
    • Ключ API используется FCM для поиска соответствующего идентификатора отправителя, проверки того, что пользователь дал разрешение на ваш проект, и, наконец, для проверки того, что IP-адрес сервера внесен в список разрешенных для этого проекта.
  • Соответствующий заголовок Content-Type application/json или application/x-www-form-urlencoded;charset=UTF-8 в зависимости от того, отправляете ли вы данные в формате JSON или в виде данных формы.
  • Массив registration_ids — это идентификаторы регистрации, которые вы извлекаете из конечных точек своих пользователей.

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

Замените &lt;YOUR_API_KEY&gt; и &lt;YOUR_REGISTRATION_ID&gt; в этой команде cURL своей собственной и запустите ее с терминала.

Вы должны увидеть великолепное уведомление:

    curl --header "Authorization: key=<YOUR_API_KEY>" --header
    "Content-Type: application/json" https://fcm.googleapis.com/fcm/send -d
    "{\"registration_ids\":[\"<YOUR_REGISTRATION_ID>\"]}"
Пример push-сообщения от Chrome для Android.

При разработке внутренней логики помните, что заголовок авторизации и формат тела POST специфичны для конечной точки FCM, поэтому определите, когда конечная точка предназначена для FCM, и условно добавьте заголовок и отформатируйте тело POST. Для других браузеров (и, надеюсь, Chrome в будущем) вам потребуется реализовать протокол Web Push .

Недостатком текущей реализации Push API в Chrome является то, что вы не можете отправлять какие-либо данные с помощью push-сообщения. Нет, ничего. Причина этого в том, что в будущей реализации полезные данные придется шифровать на вашем сервере, прежде чем они будут отправлены в конечную точку push-сообщений. Таким образом, конечная точка, каким бы поставщиком push-уведомлений она ни была, не сможет легко просмотреть содержимое push-сообщения. Это также защищает от других уязвимостей, таких как плохая проверка сертификатов HTTPS и атаки «человек посередине» между вашим сервером и провайдером push-уведомлений. Однако это шифрование пока не поддерживается, поэтому тем временем вам придется выполнить выборку, чтобы получить информацию, необходимую для заполнения уведомления.

Более полный пример push-события

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

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

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

self.addEventListener('push', function(event) {
    // Since there is no payload data with the first version
    // of push messages, we'll grab some data from
    // an API and use it to populate a notification
    event.waitUntil(
    fetch(SOME_API_ENDPOINT).then(function(response) {
        if (response.status !== 200) {
        // Either show a message to the user explaining the error
        // or enter a generic message and handle the
        // onnotificationclick event to direct the user to a web page
        console.log('Looks like there was a problem. Status Code: ' + response.status);
        throw new Error();
        }

        // Examine the text in the response
        return response.json().then(function(data) {
        if (data.error || !data.notification) {
            console.error('The API returned an error.', data.error);
            throw new Error();
        }

        var title = data.notification.title;
        var message = data.notification.message;
        var icon = data.notification.icon;
        var notificationTag = data.notification.tag;

        return self.registration.showNotification(title, {
            body: message,
            icon: icon,
            tag: notificationTag
        });
        });
    }).catch(function(err) {
        console.error('Unable to retrieve data', err);

        var title = 'An error occurred';
        var message = 'We were unable to get the information for this push message';
        var icon = URL_TO_DEFAULT_ICON;
        var notificationTag = 'notification-error';
        return self.registration.showNotification(title, {
            body: message,
            icon: icon,
            tag: notificationTag
        });
    })
    );
});

Стоит еще раз подчеркнуть, что event.waitUntil() принимает обещание, в результате чего обещание возвращается showNotification() . Это означает, что наш прослушиватель событий не завершится до тех пор, пока асинхронный вызов fetch() не завершится, и уведомление Показано.

Вы заметите, что мы показываем уведомление даже в случае ошибки. Это потому, что если мы этого не сделаем, Chrome покажет собственное общее уведомление.

Открытие URL-адреса, когда пользователь нажимает уведомление

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

self.addEventListener('notificationclick', function(event) {
    console.log('On notification click: ', event.notification.tag);
    // Android doesn't close the notification when you click on it
    // See: http://crbug.com/463146
    event.notification.close();

    // This looks to see if the current is already open and
    // focuses if it is
    event.waitUntil(
    clients.matchAll({
        type: "window"
    })
    .then(function(clientList) {
        for (var i = 0; i < clientList.length; i++) {
        var client = clientList[i];
        if (client.url == '/' && 'focus' in client)
            return client.focus();
        }
        if (clients.openWindow) {
        return clients.openWindow('/');
        }
    })
    );
});

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

Здесь есть пост, посвященный некоторым вещам, которые вы можете сделать с помощью Notification API .

Отменить подписку на устройстве пользователя

Вы подписали устройство пользователя, и он получает push-сообщения, но как отписаться от него?

Главное, что необходимо для отмены подписки на пользовательском устройстве, — это вызвать метод unsubscribe() объекта PushSubscription и удалить конечную точку с ваших серверов (только для того, чтобы вы не отправляли push-сообщения, которые, как вы знаете, не будут получены). Код ниже делает именно это:

function unsubscribe() {
    var pushButton = document.querySelector('.js-push-button');
    pushButton.disabled = true;

    navigator.serviceWorker.ready.then(function(serviceWorkerRegistration) {
    // To unsubscribe from push messaging, you need get the
    // subscription object, which you can call unsubscribe() on.
    serviceWorkerRegistration.pushManager.getSubscription().then(
        function(pushSubscription) {
        // Check we have a subscription to unsubscribe
        if (!pushSubscription) {
            // No subscription object, so set the state
            // to allow the user to subscribe to push
            isPushEnabled = false;
            pushButton.disabled = false;
            pushButton.textContent = 'Enable Push Messages';
            return;
        }

        var subscriptionId = pushSubscription.subscriptionId;
        // TODO: Make a request to your server to remove
        // the subscriptionId from your data store so you
        // don't attempt to send them push messages anymore

        // We have a subscription, so call unsubscribe on it
        pushSubscription.unsubscribe().then(function(successful) {
            pushButton.disabled = false;
            pushButton.textContent = 'Enable Push Messages';
            isPushEnabled = false;
        }).catch(function(e) {
            // We failed to unsubscribe, this can lead to
            // an unusual state, so may be best to remove
            // the users data from your data store and
            // inform the user that you have done so

            console.log('Unsubscription error: ', e);
            pushButton.disabled = false;
            pushButton.textContent = 'Enable Push Messages';
        });
        }).catch(function(e) {
        console.error('Error thrown while unsubscribing from push messaging.', e);
        });
    });
}

Поддержание подписки в актуальном состоянии

Подписки могут не синхронизироваться между FCM и вашим сервером. Убедитесь, что ваш сервер анализирует тело ответа отправки POST API FCM в поисках результатов error:NotRegistered и canonical_id , как описано в документации FCM .

Подписки также могут не синхронизироваться между сервисным работником и вашим сервером. Например, после успешной подписки/отписки нестабильное сетевое соединение может помешать вам обновить сервер; или пользователь может отозвать разрешение на получение уведомлений, что приведет к автоматической отмене подписки. Для решения таких случаев периодически проверяйте результат serviceWorkerRegistration.pushManager.getSubscription() (например, при загрузке страницы) и синхронизируйте его с сервером. Вы также можете автоматически повторно подписаться, если у вас больше нет подписки и Notification.permission == «предоставлено».

В sendSubscriptionToServer() вам нужно будет учитывать, как вы обрабатываете неудачные сетевые запросы при обновлении endpoint . Одним из решений является отслеживание состояния endpoint в файле cookie, чтобы определить, нужны ли вашему серверу последние сведения или нет.

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

Как отладить ваше веб-приложение

При реализации push-сообщений ошибки будут жить в одном из двух мест: на вашей странице или в вашем сервис-воркере.

Ошибки на странице можно отладить с помощью DevTools . Для отладки проблем сервис-воркера у вас есть два варианта:

  1. Перейдите в chrome://inspect > Сервисные работники . Это представление не предоставляет много информации, кроме запущенных в данный момент сервис-воркеров.
  2. Перейдите на chrome://serviceworker-internals и отсюда вы сможете просмотреть состояние сервис-воркеров и увидеть ошибки, если они есть. Эта страница является временной, пока DevTools не предоставит аналогичный набор функций.

Один из лучших советов, который я могу дать всем, кто не знаком с сервис-воркерами, — это использовать флажок «Открыть окно DevTools и приостановить выполнение JavaScript при запуске сервис-воркера для отладки». Этот флажок добавит точку останова в начале вашего сервис-воркера и приостановит выполнение . Это позволит вам возобновить или выполнить сценарий сервис-воркера и посмотреть, возникнут ли у вас какие-либо проблемы.

Снимок экрана, показывающий, где находится флажок приостановки выполнения во внутренних компонентах serviceworker.

Если кажется, что между FCM и событием push вашего сервисного работника возникла проблема, вы мало что можете сделать для устранения проблемы, поскольку у вас нет возможности увидеть, получил ли Chrome что-нибудь. Главное, чтобы гарантировать, что ответ от FCM будет успешным, когда ваш сервер выполняет вызов API. Это будет выглядеть примерно так:

{"multicast_id":1234567890,"success":1,"failure":0,"canonical_ids":0,"results":[{"message_id":"0:1234567890"}]}

Обратите внимание на "success": 1 ответ. Если вместо этого вы видите сбой, это говорит о том, что что-то не так с идентификатором регистрации FCM и push-сообщение не отправляется в Chrome.

Отладка Service Workers в Chrome для Android

На данный момент отладка сервис-воркеров в Chrome для Android не очевидна. Вам нужно перейти к chrome://inspect , найти свое устройство и найти элемент списка с именем «Worker pid:..», который содержит URL-адрес вашего сервисного работника.

Снимок экрана, показывающий, где живут сервисные работники в проверке Chrome

UX для push-уведомлений

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

Будущее push-сообщений в Chrome и открытой сети

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

Протокол Web Push и конечные точки

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

Протокол Web Push — это новый стандарт, который могут реализовать поставщики push-уведомлений, что позволяет разработчикам не беспокоиться о том, кто является поставщиком push-уведомлений. Идея состоит в том, что это позволяет избежать необходимости подписываться на ключи API и отправлять данные в специальном формате, как это происходит с FCM.

Chrome был первым браузером, реализовавшим Push API, а FCM не поддерживает протокол Web Push, поэтому Chrome требует gcm_sender_id , и вам нужно использовать restful API для FCM.

Конечная цель Chrome — перейти к использованию протокола Web Push с Chrome и FCM.

До тех пор вам необходимо обнаружить конечную точку «https://fcm.googleapis.com/fcm/send» и обрабатывать ее отдельно от других конечных точек, т. е. отформатировать полезные данные определенным образом и добавить ключ авторизации.

Как реализовать протокол Web Push?

Firefox Nightly в настоящее время работает над push-уведомлением и, вероятно, станет первым браузером, реализующим протокол Web Push.

Часто задаваемые вопросы

Где характеристики?

https://slightlyoff.github.io/ServiceWorker/spec/service_worker/ https://w3c.github.io/push-api/ https://notifications.spec.whatwg.org/

Могу ли я предотвратить дублирование уведомлений, если мое присутствие в Интернете имеет несколько источников или если у меня есть как веб-присутствие, так и собственное присутствие?

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

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

Зачем мне нужен gcm_sender_id?

Это необходимо, чтобы Chrome, Opera для Android и браузер Samsung могли использовать API Firebase Cloud Messaging (FCM). Цель состоит в том, чтобы использовать протокол Web Push, когда стандарт будет доработан и FCM сможет его поддерживать.

Почему бы не использовать веб-сокеты или события, отправленные сервером (EventSource)?

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

Что делать, если мне не нужна доставка фоновых событий?

Если вам не нужна фоновая доставка, веб-сокеты — отличный вариант.

Когда я могу использовать push без показа уведомлений (т. е. тихий фоновый push)?

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

Почему для этого требуется HTTPS? Как обойти это во время разработки?

Сервисным работникам требуются безопасные источники, чтобы гарантировать, что сценарий сервисного работника имеет предполагаемое происхождение и не возник в результате атаки «человек посередине». В настоящее время это означает использование HTTPS на действующих сайтах, хотя localhost будет работать во время разработки.

Как выглядит поддержка браузера?

Chrome поддерживает его в стабильной версии, а Mozilla работает над улучшением Firefox Nightly. Дополнительную информацию см. в разделе «Реализация ошибки Push API» , а отслеживать реализацию уведомлений можно здесь .

Могу ли я удалить уведомление по истечении определенного периода времени?

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

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

Каковы ограничения push-сообщений в Chrome?

В этом посте есть несколько ограничений:

  • Использование Chrome CCM в качестве службы push-уведомлений создает ряд собственных требований. Мы работаем вместе, чтобы увидеть, можно ли отменить некоторые из этих ограничений в будущем.
  • Вы должны показывать уведомление при получении push-сообщения.
  • В Chrome на рабочем столе есть предупреждение: если Chrome не запущен, push-сообщения не будут получены. Это отличается от ChromeOS и Android, где push-сообщения будут получаться всегда.

Разве мы не должны использовать API разрешений?

API разрешений реализован в Chrome, но не обязательно будет доступен во всех браузерах. Вы можете узнать больше здесь .

Почему Chrome не открывает предыдущую вкладку, когда я нажимаю уведомление?

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

Что, если уведомление устарело к тому времени, когда устройство пользователя получило уведомление?

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

Более подробную информацию можно найти здесь .

Что произойдет, если я отправлю 10 push-сообщений, но хочу, чтобы устройство получило только одно?

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

Более подробную информацию можно найти здесь .