OiO.lk Community platform!

Oio.lk is an excellent forum for developers, providing a wide range of resources, discussions, and support for those in the developer community. Join oio.lk today to connect with like-minded professionals, share insights, and stay updated on the latest trends and technologies in the development field.
  You need to log in or register to access the solved answers to this problem.
  • You have reached the maximum number of guest views allowed
  • Please register below to remove this limitation

PWA handle notifications without push

  • Thread starter Thread starter Themodmin
  • Start date Start date
T

Themodmin

Guest
I have this simple management app that i built and now i want to add notifications to it however i didn't want to use any push service I'm trying to do a simple fetch to my api evry 15 minutes and find if any new notifications are available then i show them to the user and log what has been shown using my service work to indexdb so that i don't swns the same notification twice, sounds fairly simple as i don't have any need for instant notification. Here is my attempt : sw.js

Code:
importScripts('/rss/umd.js');
importScripts('https://storage.googleapis.com/workbox-cdn/releases/5.1.2/workbox-sw.js');

const CACHE = "pwabuilder-offline-page-v001";
const OFFLINE_PAGE = "offline.html";
const NOTIFICATIONS_API = "/api/notifications";
const ICON_BASE_URL = "/storage/photos/users/";
const SYNC_INTERVAL = 15 * 60 * 1000; // 15 minutes

self.addEventListener("message", (event) => {
  if (event.data?.type === "SKIP_WAITING") {
    self.skipWaiting();
  }
});

self.addEventListener('install', (event) => {
  event.waitUntil(
    caches.open(CACHE)
      .then((cache) => cache.add(OFFLINE_PAGE))
  );
});

if (workbox.navigationPreload.isSupported()) {
  workbox.navigationPreload.enable();
}

workbox.routing.registerRoute(
  new RegExp('/rss/*'),
  new workbox.strategies.StaleWhileRevalidate({
    cacheName: CACHE
  })
);

self.addEventListener('fetch', (event) => {
  if (event.request.mode === 'navigate') {
    event.respondWith(handleFetchEvent(event));
  }
});

async function handleFetchEvent(event) {
  try {
    const preloadResp = await event.preloadResponse;
    if (preloadResp) return preloadResp;

    const networkResp = await fetch(event.request);
    return networkResp;
  } catch {
    const cache = await caches.open(CACHE);
    const cachedResp = await cache.match(OFFLINE_PAGE);
    return cachedResp;
  }
}

const dbPromise = idb.openDB('notification-store', 1, {
  upgrade(db) {
    if (!db.objectStoreNames.contains('notifications')) {
      db.createObjectStore('notifications', { keyPath: 'id' });
    }
  }
});

async function fetchNotifications() {
  try {
    const response = await fetch(NOTIFICATIONS_API);
    if (!response.ok) throw new Error('Failed to fetch notifications');

    const notifications = await response.json();
    for (const notification of notifications) {
      const sent = await isNotificationSent(notification.id);
      if (!sent) {
        self.registration.showNotification(notification.name, {
          body: notification.dec,
          icon: `${ICON_BASE_URL}${notification.sender_id}/avatar.jpg`
        });
        await markNotificationAsSent(notification.id);
      }
    }
  } catch {}
}

async function isNotificationSent(id) {
  const db = await dbPromise;
  const tx = db.transaction('notifications', 'readonly');
  const store = tx.objectStore('notifications');
  const notification = await store.get(id);
  return !!notification;
}

async function markNotificationAsSent(id) {
  const db = await dbPromise;
  const tx = db.transaction('notifications', 'readwrite');
  tx.objectStore('notifications').put({ id: id });
  await tx.done;
}

self.addEventListener('activate', (event) => {
  event.waitUntil((async () => {
    setInterval(fetchNotifications, SYNC_INTERVAL);
    await fetchNotifications();
  })());
});

self.addEventListener('fetch', () => {});

self.addEventListener('sync', (event) => {
  if (event.tag === 'fetch-notifications') {
    event.waitUntil(fetchNotifications());
  }
});

This works on android while the app is running however once i close the app i no longer get any notification, On the other hand ios this did work at all, i did add the app to the home screen and enabled notifications but it never triggered at all

<p>I have this simple management app that i built and now i want to add notifications to it however i didn't want to use any push service I'm trying to do a simple fetch to my api evry 15 minutes and find if any new notifications are available then i show them to the user and log what has been shown using my service work to indexdb so that i don't swns the same notification twice, sounds fairly simple as i don't have any need for instant notification.
Here is my attempt :
sw.js</p>
<pre><code>importScripts('/rss/umd.js');
importScripts('https://storage.googleapis.com/workbox-cdn/releases/5.1.2/workbox-sw.js');

const CACHE = "pwabuilder-offline-page-v001";
const OFFLINE_PAGE = "offline.html";
const NOTIFICATIONS_API = "/api/notifications";
const ICON_BASE_URL = "/storage/photos/users/";
const SYNC_INTERVAL = 15 * 60 * 1000; // 15 minutes

self.addEventListener("message", (event) => {
if (event.data?.type === "SKIP_WAITING") {
self.skipWaiting();
}
});

self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(CACHE)
.then((cache) => cache.add(OFFLINE_PAGE))
);
});

if (workbox.navigationPreload.isSupported()) {
workbox.navigationPreload.enable();
}

workbox.routing.registerRoute(
new RegExp('/rss/*'),
new workbox.strategies.StaleWhileRevalidate({
cacheName: CACHE
})
);

self.addEventListener('fetch', (event) => {
if (event.request.mode === 'navigate') {
event.respondWith(handleFetchEvent(event));
}
});

async function handleFetchEvent(event) {
try {
const preloadResp = await event.preloadResponse;
if (preloadResp) return preloadResp;

const networkResp = await fetch(event.request);
return networkResp;
} catch {
const cache = await caches.open(CACHE);
const cachedResp = await cache.match(OFFLINE_PAGE);
return cachedResp;
}
}

const dbPromise = idb.openDB('notification-store', 1, {
upgrade(db) {
if (!db.objectStoreNames.contains('notifications')) {
db.createObjectStore('notifications', { keyPath: 'id' });
}
}
});

async function fetchNotifications() {
try {
const response = await fetch(NOTIFICATIONS_API);
if (!response.ok) throw new Error('Failed to fetch notifications');

const notifications = await response.json();
for (const notification of notifications) {
const sent = await isNotificationSent(notification.id);
if (!sent) {
self.registration.showNotification(notification.name, {
body: notification.dec,
icon: `${ICON_BASE_URL}${notification.sender_id}/avatar.jpg`
});
await markNotificationAsSent(notification.id);
}
}
} catch {}
}

async function isNotificationSent(id) {
const db = await dbPromise;
const tx = db.transaction('notifications', 'readonly');
const store = tx.objectStore('notifications');
const notification = await store.get(id);
return !!notification;
}

async function markNotificationAsSent(id) {
const db = await dbPromise;
const tx = db.transaction('notifications', 'readwrite');
tx.objectStore('notifications').put({ id: id });
await tx.done;
}

self.addEventListener('activate', (event) => {
event.waitUntil((async () => {
setInterval(fetchNotifications, SYNC_INTERVAL);
await fetchNotifications();
})());
});

self.addEventListener('fetch', () => {});

self.addEventListener('sync', (event) => {
if (event.tag === 'fetch-notifications') {
event.waitUntil(fetchNotifications());
}
});
</code></pre>
<p>This works on android while the app is running however once i close the app i no longer get any notification, On the other hand ios this did work at all, i did add the app to the home screen and enabled notifications but it never triggered at all</p>
 

Latest posts

Online statistics

Members online
0
Guests online
5
Total visitors
5
Top