Для использования push-уведомлений от fcm необходим валидный ssl сертификат.
Первым делом необходимо перейти в консоль firebase: console.firebase.google.com
Добавить проект:
Переходим в авторизацию:
Настраиваем способ входа, включаем анонимный вход(чтобы токен можно было получить без авторизации в гугл):
Добавляем авторизованный домен:
Заходим в базы данных и выставляем правила на чтение/запись для всех:
{ "rules": {".read": true,".write": true }}
Заходим в хранилище и выставляем правила:
service firebase.storage { match /b/{bucket}/o { match /{allPaths=**} { allow read, write; }}}
1 |
firebase-messaging-sw.js |
:
importScripts('https://www.gstatic.com/firebasejs/4.2.0/firebase.js'); firebase.initializeApp({ messagingSenderId: '1053599252147' }); const messaging = firebase.messaging();
где 1053599252147 – идентификатор отправителя(берется из проекта fcm).
Создаем
1 |
index.html |
:
<html> <div id="token"></div> <script type="text/javascript" src="jquery-3.1.1.js"></script> <script type="text/javascript"> //сохранение токена function SendTokenToServer(currentToken) { xmlhttp=new XMLHttpRequest(); xmlhttp.onreadystatechange=function() { if (this.readyState==4 && this.status==200) { console.log(this.responseText); } } xmlhttp.open("GET","savetoken.php?token="+currentToken,true); xmlhttp.send(); } </script> <script type="text/javascript" src="https://www.gstatic.com/firebasejs/4.2.0/firebase.js"></script> <script type="text/javascript"> //Настройки FCM //https://console.firebase.google.com/u/1/ var config = { apiKey: "AAAA9U9ovrM:APA91bHUKF3vF1axlPeF-slhqGpRPNuEfRJJvpAOBWiMu19C7PyCiByYDr0Mz75kTV4MZx2M-Ac-zNUakEjMBWrHG0Yr8F7FsUQPnbA8W1p350Bf8kiC7XMDUulVToygji2s09LzOqlw", authDomain: "sergdudko-ce384.firebaseapp.com", databaseURL: "https://sergdudko-ce384.firebaseio.com", storageBucket: "sergdudko-ce384.appspot.com", messagingSenderId: "1053599252147", }; //инициализируем подключение к FCM firebase.initializeApp(config); const messaging = firebase.messaging(); document.getElementById('token').innerHTML = 'NO LOAD TOKEN'; //запрос на показ Web-PUSH браузеру messaging.requestPermission() .then(function() { console.log('Notification permission granted.'); // Если нотификация разрешена, получаем токен. messaging.getToken() .then(function(currentToken) { if (currentToken) { console.log(currentToken); //отправка токена на сервер SendTokenToServer(currentToken); document.getElementById('token').innerHTML = currentToken; } else { console.log('No Instance ID token available. Request permission to generate one.'); } }) .catch(function(err) { console.log('An error occurred while retrieving token. ', err); showToken('Error retrieving Instance ID token. ', err); }); // ... }) .catch(function(err) { console.log('Unable to get permission to notify.', err); }); /* //обновление токена messaging.onTokenRefresh(function() { messaging.getToken() .then(function(refreshedToken) { console.log('Token refreshed.'); }) .catch(function(err) { console.log('Unable to retrieve refreshed token ', err); showToken('Unable to retrieve refreshed token ', err); }); }) */ //окно sw messaging.onMessage(function(payload) { console.log('Message received. ', payload); // регистрируем пустой ServiceWorker каждый раз navigator.serviceWorker.register('firebase-messaging-sw.js'); // запрашиваем права на показ уведомлений если еще не получили их Notification.requestPermission(function(result) { if (result === 'granted') { navigator.serviceWorker.ready.then(function(registration) { // теперь мы можем показать уведомление return registration.showNotification(payload.notification.title, payload.notification); }).catch(function(error) { console.log('ServiceWorker registration failed', error); }); } }); }); </script> </html>
Где:
• sergdudko-ce384 – идентификатор проекта

• AAAA9U9ovrM:APA91bHUKF3vF1axlPeF-slhqGpRPNuEfRJJvpAOBWiMu19C7PyCiByYDr0Mz75kTV4MZx2M-Ac-zNUakEjMBWrHG0Yr8F7FsUQPnbA8W1p350Bf8kiC7XMDUulVToygji2s09LzOqlw – ключ сервера
• 1053599252147 – идентификатор отправителя

При этом запрос для сохранения токена через
1 |
$_GET[‘token’] |
в
1 |
savetoken.php |
, xmlhttprequest требует jQuery:
//сохранение токена function SendTokenToServer(currentToken) { xmlhttp=new XMLHttpRequest(); xmlhttp.onreadystatechange=function() { if (this.readyState==4 && this.status==200) { console.log(this.responseText); } } xmlhttp.open("GET","savetoken.php?token="+currentToken,true); xmlhttp.send(); }
Инициализация базы данных(для работы с firebase требуется соответствующий скрипт https://www.gstatic.com/firebasejs/4.2.0/firebase.js):
var config = { apiKey: "AAAA9U9ovrM:APA91bHUKF3vF1axlPeF-slhqGpRPNuEfRJJvpAOBWiMu19C7PyCiByYDr0Mz75kTV4MZx2M-Ac-zNUakEjMBWrHG0Yr8F7FsUQPnbA8W1p350Bf8kiC7XMDUulVToygji2s09LzOqlw", authDomain: "sergdudko-ce384.firebaseapp.com", databaseURL: "https://sergdudko-ce384.firebaseio.com", storageBucket: "sergdudko-ce384.appspot.com", messagingSenderId: "1053599252147", }; //инициализируем подключение к FCM firebase.initializeApp(config);
Инициализация fcm:
const messaging = firebase.messaging();
Запрос на прием push-уведомлений браузеру:
messaging.requestPermission() .then(function() { console.log('Notification permission granted.'); }) .catch(function(err) { console.log('Unable to get permission to notify.', err); });
Получение токена с firebase и запись его через функцию SendTokenToServer(token):
messaging.getToken() .then(function(currentToken) { if (currentToken) { console.log(currentToken); //отправка токена на сервер SendTokenToServer(currentToken); document.getElementById('token').innerHTML = currentToken; } else { console.log('No Instance ID token available. Request permission to generate one.'); } }) .catch(function(err) { console.log('An error occurred while retrieving token. ', err); showToken('Error retrieving Instance ID token. ', err); });
Регистрация service worker:
messaging.onMessage(function(payload) { console.log('Message received. ', payload); // регистрируем пустой ServiceWorker каждый раз navigator.serviceWorker.register('firebase-messaging-sw.js'); // запрашиваем права на показ уведомлений если еще не получили их Notification.requestPermission(function(result) { if (result === 'granted') { navigator.serviceWorker.ready.then(function(registration) { // теперь мы можем показать уведомление return registration.showNotification(payload.notification.title, payload.notification); }).catch(function(error) { console.log('ServiceWorker registration failed', error); }); } }); });
Отправка уведомления через curl:
1 2 3 4 5 6 7 8 9 10 |
curl -X POST -H "Authorization: key=AAAA9U9ovrM:APA91bHUKF3vF1axlPeF-slhqGpRPNuEfRJJvpAOBWiMu19C7PyCiByYDr0Mz75kTV4MZx2M-Ac-zNUakEjMBWrHG0Yr8F7FsUQPnbA8W1p350Bf8kiC7XMDUulVToygji2s09LzOqlw" -H "Content-Type: application/json" -d '{ "notification": { "title": "Web PUSH с push.sergdudko.tk", "body": "Body PUSH", "icon": "push-button.png", "click_action": "https://sergdudko.tk" }, "to": "cPzofyAkzZ0:APA91bFBM8_V8l-XdgIv60N7h5mQh6C_Mf8UyGbwPMCOOlQrPR1q2QJTWn_72tVNGKYObfDKius5bdNyrxe_1Pt2Sf-KLvHWJ0DXfxfSgxsuJL4_8ZvBMU_Pdg6Gb4cqllU9pV4WxjRH" }' https://fcm.googleapis.com/fcm/send |
Где:
• AAAA9U9ovrM:APA91bHUKF3vF1axlPeF-slhqGpRPNuEfRJJvpAOBWiMu19C7PyCiByYDr0Mz75kTV4MZx2M-Ac-zNUakEjMBWrHG0Yr8F7FsUQPnbA8W1p350Bf8kiC7XMDUulVToygji2s09LzOqlw – ключ сервера, полученный в FCM
• Web PUSH с push.sergdudko.tk – наименование уведомления
• Body PUSH – текст уведомления
• push-button.png – иконка уведомления
• https://sergdudko.tk – откроется при клике
• cPzofyAkzZ0:APA91bFBM8_V8l-XdgIv60N7h5mQh6C_Mf8UyGbwPMCOOlQrPR1q2QJTWn_72tVNGKYObfDKius5bdNyrxe_1Pt2Sf-KLvHWJ0DXfxfSgxsuJL4_8ZvBMU_Pdg6Gb4cqllU9pV4WxjRH – токен пользователя полученный на сервере функцией messaging.getToken()
Или через php:
$url = 'https://fcm.googleapis.com/fcm/send'; $YOUR_API_KEY = 'AAAA9U9ovrM:APA91bHUKF3vF1axlPeF-slhqGpRPNuEfRJJvpAOBWiMu19C7PyCiByYDr0Mz75kTV4MZx2M-Ac-zNUakEjMBWrHG0Yr8F7FsUQPnbA8W1p350Bf8kiC7XMDUulVToygji2s09LzOqlw; // Server key $YOUR_TOKEN_ID = ‘cPzofyAkzZ0:APA91bFBM8_V8l-XdgIv60N7h5mQh6C_Mf8UyGbwPMCOOlQrPR1q2QJTWn_72tVNGKYObfDKius5bdNyrxe_1Pt2Sf-KLvHWJ0DXfxfSgxsuJL4_8ZvBMU_Pdg6Gb4cqllU9pV4WxjRH’; // Client token id $request_body = [ 'to' => $YOUR_TOKEN_ID, 'notification' => [ 'title' => 'Web PUSH с sergdudko.tk', 'body' => 'Body PUSH', 'icon' => 'push-button.png', 'click_action' => 'https://sergdudko.tk', ], ]; $fields = json_encode($request_body); $request_headers = [ 'Content-Type: application/json', 'Authorization: key=' . $YOUR_API_KEY, ]; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST'); curl_setopt($ch, CURLOPT_HTTPHEADER, $request_headers); curl_setopt($ch, CURLOPT_POSTFIELDS, $fields); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); $response = curl_exec($ch); curl_close($ch); echo $response;
Если произведен вход в google account под учетной записью владельца, то можно также проверить запись в БД firebase:
Дополнение(настройка кастомных обработок):
В параметр notification можно запихать данные(подробнее тут https://firebase.google.com/docs/cloud-messaging/http-server-ref), они будут автоматически обрабатываться на соответствующих устройствах.
Пример инициирующий отправку из php:
'notification' => [ 'title' => 'Добро пожаловать', //название уведомления 'body' => 'на сайт www.sergdudko.tk', //тело уведомления 'icon' => 'img/push.png', //картинка уведомления 'tag' => 'sergdudko.tk', //тэг уведомления, уведомления с одним тегом заменяют друг друга 'livetime' => 300, //время жизни уведомления 'priority' => 10, //приоритет уведомления 5 - норм, 10 - высокий 'click_action' => 'https://sergdudko.tk' //действие при клике на стандартное уведомление ],
Можно создать кастомный обработчик, для удобства это должна быть внешняя функция для
1 |
messaging.onMessage() |
, при этом в нее необходимо передать данные, по умолчанию json-данные имеют имя
1 |
payload |
. Если необходимо передать не стандартные данные(точнее с не стандартными ключами), можно использовать дополнительный массив
1 |
data |
:
'data' => [ 'click' => 'чего-то там', 'text' => 'клик по уведомлению', 'function' => 'window.open("https://vk.com","_self");' ],
При этом стоит помнить, что в json хранятся и типы данных. Т.е. переданное число остается числовым типом, переданная сторока – строковый, а переданная функция должна быть функцией.
Чтобы принять данное сообщение мы заменим
if (result === 'granted') { navigator.serviceWorker.ready.then(function(registration) { // события при получении пуша, стандартная функция return registration.showNotification(payload.notification.title, payload.notification).then(function(notificationclick) {console.log('получили пуш');}); } })
На нашу функцию:
if (result === 'granted') { navigator.serviceWorker.ready.then(function(registration) { // события при получении пуша, стандартная функция //return registration.showNotification(payload.notification.title, payload.notification).then(function(notificationclick) {console.log('получили пуш');}); //вызываем нашу функцию, вместо стандартной return notifications_incoming(payload); } })
Далее необходимо ее описать:
function notifications_incoming(payload){ var myNotification = new Notification(payload.notification.title, { tag : payload.notification.tag, title : payload.notification.title, body : payload.notification.body, icon : payload.notification.icon, time_to_live : payload.notification.livetime, priority : payload.notification.priority }); myNotification.onshow = function() { // alert( 'onshow' ); }; myNotification.onclick = function() { eval(payload.data.function); }; myNotification.onclose = function() { // alert( 'onclose' ); }; myNotification.onerror = function() { // alert( 'onerror' ); }; }
При этом стандартные данные будут формата
1 |
payload.notification |
, а дополнительные
1 |
payload.data |
. Также для класса
1 |
Notification() |
есть стандартные события: показ, клик, закрытие, ошибка.