问题
So I want to cache my web app assets in a service worker, but I already have firebase messaging SW, can I put my code there or create a new service worker?
回答1:
This is what worked for me: - create two service workers: sw.js (for caching and fetch handler) and the firebase-messaging-sw.js
as mentioned, sw.js will handle your caching. DO NOT create a "push" or "notificationclick" handler in sw.js
create your "push" and "notificationclick" handlers in firebase-messaging-sw.js. I do NOT call any firebase instantiating code in firebase-messaging-sw.js, and I DO NOT use the firebase messaging object or the setBackgroundMessageHandler method. I only use the "push" and "notificationclick" handlers. Reason for this is that if you instantiate the firebase messaging sdk in your app, it will automatically look for and install firebase-messaging-sw.js, and by putting your "push" handler there, you're golden.
I only register "sw.js". The firebase sdk will automatically register firebase-messaging-sw.js when you initialize it.
index.html:
<!-- Firebase App (the core Firebase SDK) is always required and must be listed first -->
<script src="https://www.gstatic.com/firebasejs/7.5.0/firebase-app.js"></script>
<!-- Add Firebase products that you want to use -->
<script src="https://www.gstatic.com/firebasejs/7.5.0/firebase-messaging.js"></script>
<script>
// Your web app's Firebase configuration
var firebaseConfig = {...config props...};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
var messaging = firebase.messaging();
// Project Settings => Cloud Messaging => Web Push certificates
//REGISTER SERVICE WORKER
window.addEventListener('load', () => {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('sw.js').then(function(swReg) {
return navigator.serviceWorker.ready;
})
.catch(function(error) {
console.error('Service Worker Error', error);
});
}
});
sw.js:
(function(){
//IMPORTANT: DO NOT use this service worker for push!! That is handled in firebase-messaging-sw.js
var cache_v = '1.0.43';
var cache_list = [...];
self.addEventListener('install', function(e) {...});
// intercept network requests:
self.addEventListener('fetch', function(event) {...});
// delete unused caches
self.addEventListener('activate', function(e) {...});
self.addEventListener('sync', function(event) {...});
})();
firebase-messaging-sw.js:
(function(){
self.addEventListener('push', function(event) {
let title = "Push Default Title";
let options = {};
const fallback_url = "https://www.[yourdomain.com]"; //used clicking "see all"
//promise for parsing json. firebase will send over json, but other push services, incl chrome's serviceworker push test, may just send text.
const parse_payload = (payload_obj) => {
return new Promise((resolve, reject) => {
try {
if(JSON.parse(payload_obj)){ //firebase struct
let json = JSON.parse(payload_obj);
if(json.hasOwnProperty("notification")){ //resolve to this only if notification is a property. otherwise reject
resolve(json);
} else {
reject(payload_obj);
}
}
reject(payload_obj);
} catch(e){
reject(payload_obj); //other push is just a text string
}
});
};
//struct of event.data.text() is: {"data": {"url (custom options)": [custom value]}, ..., "notification": {"title": "", "body": "", "tag": "campaign_[xxx]"}}
parse_payload(event.data.text()).then((notif) => {
title = notif.notification.title; //only resolves if notif.notification exists
console.log(notif);
options = {
body: notif.notification.body,
icon: './images/push_icon.png',
badge: './images/notif_badge.png',
data: {
url: notif.data.url || fallback_url //would have to change by item
},
actions: [{
action: 'purchase',
title: 'Purchase'
}, {
action: 'see_all',
title: '...'
}]
};
event.waitUntil(self.registration.showNotification(title, options));
}, (notif) => {
options = {
body: notif,
icon: './images/push_icon.png',
badge: './images/notif_badge.png',
data: {url: fallback_url}
};
event.waitUntil(self.registration.showNotification(title, options));
});
});
self.addEventListener('notificationclick', function(event) {
const url = event.notification.data.url;
event.notification.close(); //by default, this doesn't even close the notif. need to do that.
if(!event.action){ //did not click on an action
if (clients.openWindow && url) {
event.waitUntil(clients.openWindow(url));
}
} else { //action click, as defined in push handler
switch(event.action){
case 'purchase':
if (clients.openWindow && url) {
event.waitUntil(clients.openWindow(url)); //if clicking purchase, use specific url sent over in push
}
break;
case 'see_all':
if (clients.openWindow) {
event.waitUntil(clients.openWindow(fallback_url)); //clicking see all, so send to fallback
}
break;
}
}
});
})();
I was going absolutely crazy trying to figure this out, and could not for the life of me get the setBackgroundMessageHandler event to fire, and I wanted to show push notifs even in the foreground. Ultimately the solution above is what worked.
来源:https://stackoverflow.com/questions/58533634/can-i-use-service-worker-caching-function-in-firebase-messaging-sw-js