Je suivais cet article ici (qui n’est malheureusement pas complet) pour tenter de savoir comment se faire un ami avec PWA et Firebase Cloud Messaging sur Ionic 3: Notifications push avec FCM
Ce que j'ai fait:
'use strict';
importScripts('./build/sw-toolbox.js');
importScripts('https://www.gstatic.com/firebasejs/4.9.0/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/4.9.0/firebase-messaging');
firebase.initializeApp({
// get this from Firebase console, Cloud messaging section
'messagingSenderId': '47286327412'
});
const messaging = firebase.messaging();
messaging.setBackgroundMessageHandler((payload) => {
console.log('Received background message ', payload);
// here you can override some options describing what's in the message;
// however, the actual content will come from the service sending messages
const notificationOptions = {
icon: '/assets/img/appicon.png'
};
return self.registration.showNotification(notificationTitle, notificationOptions);
});
self.toolbox.options.cache = {
name: 'ionic-cache'
};
// pre-cache our key assets
self.toolbox.precache(
[
'./build/main.js',
'./build/vendor.js',
'./build/main.css',
'./build/polyfills.js',
'index.html',
'manifest.json'
]
);
// dynamically cache any other local assets
self.toolbox.router.any('/*', self.toolbox.cacheFirst);
// for any other requests go to the network, cache,
// and then only use that cached resource if your user goes offline
self.toolbox.router.default = self.toolbox.networkFirst;
import { Injectable } from "@angular/core";
import * as firebase from 'firebase';
import { Storage } from '@ionic/storage';
@Injectable()
export class FirebaseMessagingProvider {
private messaging: firebase.messaging.Messaging;
private unsubscribeOnTokenRefresh = () => {};
constructor(
private storage: Storage
) {
this.messaging = firebase.messaging();
}
public enableNotifications() {
console.log('Requesting permission...');
return this.messaging.requestPermission().then(() => {
console.log('Permission granted');
// token might change - we need to listen for changes to it and update it
this.setupOnTokenRefresh();
return this.updateToken();
});
}
public disableNotifications() {
this.unsubscribeOnTokenRefresh();
this.unsubscribeOnTokenRefresh = () => {};
return this.storage.set('fcmToken','').then();
}
private updateToken() {
return this.messaging.getToken().then((currentToken) => {
if (currentToken) {
// we've got the token from Firebase, now let's store it in the database
return this.storage.set('fcmToken', currentToken);
} else {
console.log('No Instance ID token available. Request permission to generate one.');
}
});
}
private setupOnTokenRefresh(): void {
this.unsubscribeOnTokenRefresh = this.messaging.onTokenRefresh(() => {
console.log("Token refreshed");
this.storage.set('fcmToken','').then(() => { this.updateToken(); });
});
}
}
Et maintenant, lors de l'initialisation de l'application, j'appelle enableNotifications () et reçois une erreur indiquant que le service worker par défaut est introuvable (404):
Un code de réponse HTTP incorrect (404) a été reçu lors de l'extraction du script .___: 8100/firebase-messaging-sw.js Échec du chargement de la ressource: net :: ERR_INVALID_RESPONSE
Si je déplace des éléments liés à service-worker.js firebase vers un agent de service par défaut dans un dossier WWW, l'erreur d'erreur générale vient de Firebase (Erreur, impossible d'enregistrer l'agent de service).
QUESTIONS. J'ai regardé le tutoriel sur Angular mais je ne vois pas comment faire de même dans Ionic 3.
UPDATE: les informations ci-dessous sont valables à compter d'aujourd'hui (02/12/2018) et seront probablement moins pertinentes une fois que AngularFire2 aura pris en charge le module de messagerie. Donc, prenez le ci-dessous avec cette hypothèse ...
OK, j'ai fait des recherches et je l'ai finalement fait fonctionner sur mon IWA 3 PWA. Je poste donc la solution ici:
export const firebaseConfig = {
apiKey: "Your Stuff Here from FB",
authDomain: "YOURAPPNAME.firebaseapp.com",
databaseURL: "https://YOURAPPNAME.firebaseio.com",
projectId: "YOURAPPNAME",
storageBucket: "YOURAPPNAME.appspot.com",
messagingSenderId: "FROMFIREBASECONEOLE"
};
...
import { AngularFireModule } from 'angularfire2';
import 'firebase/messaging'; // only import firebase messaging or as needed;
import { firebaseConfig } from '../environment';
import { FirebaseMessagingProvider } from '../providers/firebase-messaging';
...
@NgModule({
declarations: [
MyApp,
HomePage
],
imports: [
BrowserModule,
IonicModule.forRoot(MyApp),
AngularFireModule.initializeApp(firebaseConfig),
IonicStorageModule.forRoot()
],
bootstrap: [IonicApp],
entryComponents: [
MyApp,
HomePage
],
providers: [
FirebaseMessagingProvider,
StatusBar,
SplashScreen,
{provide: ErrorHandler, useClass: IonicErrorHandler}
]
})
export class AppModule {}
Ici, nous importons également notre fournisseur dont le code est ci-dessous:
import { Injectable } from "@angular/core";
import { FirebaseApp } from 'angularfire2';
// I am importing simple ionic storage (local one), in prod this should be remote storage of some sort.
import { Storage } from '@ionic/storage';
@Injectable()
export class FirebaseMessagingProvider {
private messaging;
private unsubscribeOnTokenRefresh = () => {};
constructor(
private storage: Storage,
private app: FirebaseApp
) {
this.messaging = app.messaging();
navigator.serviceWorker.register('service-worker.js').then((registration) => {
this.messaging.useServiceWorker(registration);
//this.disableNotifications()
this.enableNotifications();
});
}
public enableNotifications() {
console.log('Requesting permission...');
return this.messaging.requestPermission().then(() => {
console.log('Permission granted');
// token might change - we need to listen for changes to it and update it
this.setupOnTokenRefresh();
return this.updateToken();
});
}
public disableNotifications() {
this.unsubscribeOnTokenRefresh();
this.unsubscribeOnTokenRefresh = () => {};
return this.storage.set('fcmToken','').then();
}
private updateToken() {
return this.messaging.getToken().then((currentToken) => {
if (currentToken) {
// we've got the token from Firebase, now let's store it in the database
console.log(currentToken)
return this.storage.set('fcmToken', currentToken);
} else {
console.log('No Instance ID token available. Request permission to generate one.');
}
});
}
private setupOnTokenRefresh(): void {
this.unsubscribeOnTokenRefresh = this.messaging.onTokenRefresh(() => {
console.log("Token refreshed");
this.storage.set('fcmToken','').then(() => { this.updateToken(); });
});
}
}
Veuillez noter que je lance l'application firebase puis, dans le constructeur, nous enregistrons le service worker par défaut d'ionic (service-worker.js) qui contient les éléments suivants juste après tout ce qui se trouve par défaut:
// firebase messaging part:
importScripts('https://www.gstatic.com/firebasejs/4.9.0/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/4.9.0/firebase-messaging.js');
firebase.initializeApp({
// get this from Firebase console, Cloud messaging section
'messagingSenderId': 'YOURIDFROMYOURFIREBASECONSOLE'
});
const messaging = firebase.messaging();
messaging.setBackgroundMessageHandler(function(payload) {
console.log('Received background message ', payload);
// here you can override some options describing what's in the message;
// however, the actual content will come from the Webtask
const notificationOptions = {
icon: '/assets/images/logo-128.png'
};
return self.registration.showNotification(notificationTitle, notificationOptions);
});
À ce stade, vous devez également vous assurer que vous avez activé votre application en tant que PWA. Il existe un bon guide de Josh Morony et, aujourd’hui, un flux vidéo sur youtube la couvre. Dans TLDR, vous devez supprimer le commentaire dans votre index.html:
<!-- un-comment this code to enable service worker -->
<script>
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('service-worker.js')
.then(() => console.log('service worker installed'))
.catch(err => console.error('Error', err));
}
</script>
Ceci conclut les choses initiales sur le client. Veuillez noter que je n'ai pas encore implémenté quoi que ce soit pour gérer les notifications lorsque l'utilisateur est dans l'application elle-même. Pensez pour l'instant qu'il gère uniquement les messages envoyés depuis un serveur lorsque votre onglet n'est pas actif (c'est ce que j'ai testé).
// method: "POST",
//url: "https://fcm.googleapis.com/fcm/send",
// get the key from Firebase console
headers: { Authorization: `key=${fcmServerKey}` },
json: {
"notification": {
"title": "Message title",
"body": "Message body",
"click_action": "URL to your app?"
},
// userData is where your client stored the FCM token for the given user
// it should be read from the database
"to": userData.fcmRegistrationKey
}
Donc, en faisant tout cela, j'ai pu m'envoyer un message fiable alors que l'application était en arrière-plan. Je n'ai pas encore pris en charge le premier plan, mais cette question SO concerne la procédure à suivre pour initier le prestataire de services par défaut et le marier avec FCM.
J'espère que cela aidera certains apprenants à l'avenir.
J'ai réussi à mettre en œuvre le processus et à obtenir une réponse positive aux appels d'API. Mais aucune notification popup à venir sur mon navigateur. Une idée?
api:https://fcm.googleapis.com/fcm/send
réponse obtenu:
{"multicast_id": 6904414188195222649, "success": 1, "échec": 0, "canonical_ids": 0, "résultats": [{"message_id": "0: 1545375125056264% e609af1cf9fd7ecd"]]]]