Você pode encontrar artigos de 2017 ... 2018 que se concentram no uso de meios de nível relativamente baixo para enviar e receber mensagens push da web, por exemplo, usando a biblioteca web-push-libs / web-push . Esta biblioteca ainda está em desenvolvimento, porém é muito mais fácil trabalhar com bibliotecas do firebase hoje em dia.
Configurando um projeto Firebase
Então, vamos começar criando um projeto no firebase. Com o Firebase console aberto , um novo projeto precisa ser criado. Em Informações Gerais-> Configurações-> Configurações Gerais-> Seus Aplicativos, você precisa criar um novo aplicativo da web. Isso irá gerar um código de inicialização do aplicativo da web no front-end:
<!-- The core Firebase JS SDK is always required and must be listed first -->
<script src="https://www.gstatic.com/firebasejs/7.19.0/firebase-app.js"></script>
<!-- TODO: Add SDKs for Firebase products that you want to use
https://firebase.google.com/docs/web/setup#available-libraries -->
<script src="https://www.gstatic.com/firebasejs/7.19.0/firebase-analytics.js"></script>
<script>
// Your web app's Firebase configuration
var firebaseConfig = {
apiKey: "...",
authDomain: "...",
databaseURL: "...",
projectId: "...",
storageBucket: "...",
messagingSenderId: "...",
appId: "...",
measurementId: "..."
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
firebase.analytics();
</script>
Na mesma guia do console do firebase Informações gerais- > Configurações-> Cloud Messaging-> Credenciais para o projeto -> Chave do servidor , encontramos a chave privada, com a qual você pode enviar notificações push por meio do servidor firebase.
Enviando uma mensagem push na web
Os desenvolvedores de front-end podem enviar mensagens push da web por conta própria usando o comando curl:
curl -X POST -H "Authorization: key=< >" -H "Content-Type: application/json" -d '{
"data": {
"title": "FCM Message",
"body": "This is an <i>FCM Message</i>",
"icon": "/static/plus.png",
"sound": "/static/push.mp3",
"click_action": "https://google.com",
},
"to": "< >"
}' https://fcm.googleapis.com/fcm/send
A obtenção de uma chave de servidor é descrita na seção Configurando um projeto firebase , e a obtenção de um token de registro será descrita na seção Obtendo um token de registro .
dados vs carga útil de notificação
A carga útil pode ser enviada no campo de dados ou notificação de uma mensagem push da web. Para carga útil de notificação, a solicitação será semelhante a esta (para carga útil de dados, consulte a solicitação na seção Enviando uma mensagem push ):
curl -X POST -H "Authorization: key=< >" -H "Content-Type: application/json" -d '{
"notification": {
"title": "FCM Message",
"body": "This is an <i>FCM Message</i>",
"icon": "/static/plus.png",
"click_action": "https://google.com",
},
"to": "< >"
}' https://fcm.googleapis.com/fcm/send
dados e carga útil de notificação têm duas diferenças fundamentais:
- a carga útil de notificação tem um conjunto estritamente definido de campos, campos extras serão ignorados, enquanto a carga útil de dados envia todos os campos para o front-end sem restrição.
- Se o navegador da web estiver em segundo plano ou se o link ativo contiver um site de terceiros, o push da web de carga útil de notificação exibe uma mensagem sem transferir o controle para os manipuladores de eventos onMessage, enquanto o push da web de carga útil de dados sempre transfere o controle para os manipuladores de eventos onMessage, mas para para exibir uma mensagem, você deve criar explicitamente um objeto Notificação. Se o navegador da web estiver em um estado ativo e nosso site estiver aberto na guia ativa, o trabalho com dados e carga útil de notificação não será diferente.
Criação de um objeto de mensagem
Para trabalhar no front-end com mensagens push da web, você precisa criar um objeto de mensagem:
const messaging = window.firebase.messaging();
Neste código,
firebaseeste é um objeto global criado durante o carregamento das bibliotecas Firebase e inicializado no lado do front-end, conforme descrito em Configurando um projeto Firebase . O projeto foi desenvolvido em Vue.js. Portanto, conectar scripts por meio de um elemento de script html não parecia promissor. Para conectar esses scripts, usei a biblioteca vue-plugin-load-script:
import Vue from "vue";
import LoadScript from "vue-plugin-load-script";
Vue.use(LoadScript);
var firebaseConfig = {
apiKey: "...",
authDomain: "...",
databaseURL: "...",
projectId: "...",
storageBucket: "...",
messagingSenderId: "...",
appId: "...",
measurementId: "..."
};
Promise.resolve()
.then(() =>
Vue.loadScript(
"https://www.gstatic.com/firebasejs/7.14.0/firebase-app.js"
)
)
.then(() =>
Vue.loadScript(
"https://www.gstatic.com/firebasejs/7.14.0/firebase-messaging.js"
)
)
.then(() =>
Vue.loadScript(
"https://www.gstatic.com/firebasejs/7.14.0/firebase-analytics.js"
)
)
.then(() => {
window.firebase.initializeApp(firebaseConfig);
const messaging = window.firebase.messaging();
... // messaging
});
Obter um token de registro
Um token de registro é um identificador que identifica exclusivamente um dispositivo e um navegador da web, permitindo que uma mensagem push da web seja enviada a um dispositivo específico e processada por um navegador da web específico:
Notification.requestPermission()
.then(permission => {
if (permission === "granted") {
messaging
.getToken()
.then(token => {
... //
});
} else {
console.log("Unable to get permission to notify.");
}
});
Em algumas circunstâncias, o token pode ser atualizado. E você precisa lidar com o evento de atualização do token:
messaging.onTokenRefresh(function() {
messaging
.getToken()
.then(function(refreshedToken) {
... //
});
});
Em relação a este evento, tenho uma pergunta - é relevante. O fato é que antes mesmo de passar para o FCM, o procedimento de rotação de tokens funcionava com o GCM. Isso foi descrito na biblioteca para Android e indiretamente na descrição da operação do servidor, onde cada resposta do servidor continha tokens canônicos e eles tinham que ser constantemente verificados e alterados (no entanto, como descobri, além de mim, raramente era seguido por alguém). Após a mudança para o FCM, um conceito como tokens canônicos caiu em desuso (provavelmente porque, na prática, eles raramente eram rastreados). Nesse sentido, os casos em que um evento pode ocorrer não são totalmente claros
onTokenRefresh().
Evento OnMessage - versão simplificada
Eu responderei imediatamente porque é simplificado. Faremos pelo menos duas simplificações. 1) Usaremos carga útil de notificação para receber e exibir mensagens se o aplicativo estiver em segundo plano sem trabalho adicional. 2) Esqueçamos que em dispositivos móveis o sistema de segurança não permite que a nova operadora Notification () seja executada.
Assim, como já dissemos, para carga útil de notificação, uma mensagem push da web chega e é exibida sem a menor participação do desenvolvedor front-end (é claro, após o envio do token de registro para o servidor). Resta descobrir se o navegador da web está em um estado ativo e o site está aberto em uma guia ativa:
messaging.onMessage(function(payload) {
const data = { ...payload.notification, ...payload.data };
const notificationTitle = data.title;
const notificationOptions = {
body: data.body,
icon: data.icon,
image: data.image,
click_action: data.click_action,
requireInteraction: true,
data
};
new Notification(payload.notification.title, payload.notification);
});
Lidar com o evento de recebimento de uma mensagem push da web em segundo plano
Nesta seção, começaremos a trabalhar com um service worker. E isso, entre outras coisas, significa que você precisa configurar o site para funcionar usando o protocolo https seguro. E isso complica imediatamente o desenvolvimento posterior. Portanto, para casos simples, o que já foi descrito anteriormente é suficiente.
Para trabalhar com a biblioteca Firebase, um arquivo denominado
firebase-messaging-sw.js. O nome do arquivo pode ser diferente, mas deve, em qualquer caso, estar no diretório raiz devido à forma como funciona a proteção do navegador da web (caso contrário, este trabalhador de serviço não funcionará para todo o site).
Como regra, um manipulador de eventos também é colocado neste arquivo
notificationclick. Você dificilmente pode encontrar algo diferente deste código:
var firebaseConfig = {
apiKey: "...",
authDomain: "...",
databaseURL: "...",
projectId: "...",
storageBucket: "...",
messagingSenderId: "...",
appId: "...",
measurementId: "..."
};
importScripts("https://www.gstatic.com/firebasejs/7.17.2/firebase-app.js");
importScripts("https://www.gstatic.com/firebasejs/7.17.2/firebase-messaging.js");
firebase.initializeApp(firebaseConfig);
const messaging = firebase.messaging();
messaging.setBackgroundMessageHandler(function(payload) {
const data = { ...payload.notification, ...payload.data };
const notificationTitle = data.title;
const notificationOptions = {
body: data.body,
icon: data.icon,
image: data.image,
requireInteraction: true,
click_action: data.click_action,
data
};
self.registration.showNotification(notificationTitle, notificationOptions);
});
self.addEventListener("notificationclick", function(event) {
const target = event.notification.data.click_action;
event.notification.close();
event.waitUntil(
clients
.matchAll({
type: "window",
includeUncontrolled: true
})
.then(function(clientList) {
for (var i = 0; i < clientList.length; i++) {
var client = clientList[i];
console.log(client.url, client.focus);
if (client.url === target && "focus" in client) {
return client.focus();
}
}
return clients.openWindow(target);
})
);
});
Opção para lidar com evento onMessage com service worker
Deixe-me lembrá-lo de que na seção onMessage Event - uma versão simplificada, já descrevemos como lidar com mensagens push da web. Mas esse método tinha uma desvantagem significativa - não funcionava em dispositivos móveis devido às peculiaridades do sistema de proteção do navegador da web. Para superar essa desvantagem, uma opção de service worker foi inventada, na qual o objeto Notification já está embutido e não precisa ser criado com o novo operador:
messaging.onMessage(function(payload) {
play();
navigator.serviceWorker.register("/firebase-messaging-sw.js");
Notification.requestPermission(function(result) {
if (result === "granted") {
navigator.serviceWorker.ready
.then(function(registration) {
const data = { ...payload.notification, ...payload.data };
const notificationTitle = data.title;
const notificationOptions = {
body: data.body,
icon: data.icon,
image: data.image,
click_action: data.click_action,
requireInteraction: true,
data
};
return registration.showNotification(
notificationTitle,
notificationOptions
);
})
.catch(function(error) {
console.log("ServiceWorker registration failed", error);
});
}
});
});
Beep ao receber uma mensagem push da web
Devo dizer que praticamente não temos controle sobre como as notificações push serão exibidas em vários dispositivos. Em alguns casos, esta será uma mensagem pop-up, em outros, o push irá imediatamente para a "placa" do sistema, e se ainda não houver dublagem, simplesmente será perdido para o cliente. Com um svuk, tudo é muito difícil. As especificações anteriores incluíam um campo sonoro, que anteriormente era responsável pelo som ao receber uma mensagem push da web, mas atualmente não existe tal propriedade. Nesse sentido, estabeleci para mim mesmo o objetivo de fazer uma gravação de áudio do push.
A descrição às vezes encontrada com a criação de um elemento de áudio html e chamada de seu método play () na realidade não funciona devido aos recursos de segurança do navegador da web (ele só pode ser chamado com um clique de um usuário real). Mas também há AudioContext () - vamos trabalhar com ele:
const play = () => {
try {
const context = new AudioContext();
window
.fetch(soundUrl)
.then(response => response.arrayBuffer())
.then(arrayBuffer => context.decodeAudioData(arrayBuffer))
.then(audioBuffer => {
const source = context.createBufferSource();
source.buffer = audioBuffer;
source.connect(context.destination);
source.start();
});
} catch (ex) {
console.log(ex);
}
};
Está tudo bem, mas ainda temos um service worker que não tem um objeto AudioContext (). Vamos lembrar que todos os trabalhadores se comunicam por meio de mensagens. E o recebimento de eventos do service worker terá a seguinte aparência:
try {
const broadcast = new BroadcastChannel("play");
broadcast.onmessage = play;
} catch (ex) {
console.log(ex) ;
}
Obviamente, para que este código funcione, você precisa de 1) O navegador está aberto 2) O site está aberto (embora não necessariamente na guia ativa). Mas não há outra maneira.
Em vez de um posfácio
Agora você pode expirar e dizer, é isso. Mas ... Tudo isso não funciona no safari - e este é outro tópico separado e mal documentado, embora vários artigos possam ser encontrados.
Links úteis
1) habr.com/ru/post/321924
apapacy@gmail.com
24 de agosto de 2020