Clicking on notification from MV3 extension has no effect if background script suspended

I’ve ported my Firefox extension to MV3, and have noticed that if the user clicks on a notification while the background script is suspended, nothing happens.

Clicking on a notification from my extension is supposed to either open an extension page in a new popup window, or open a URL in a new browser tab, depending on the ID of the notification.

This issue occurs if the user didn’t click on the notification right away, and waited a while before doing so from the Action Center on Windows, or from the sidebar on macOS that appears when clicking on the date and time on the right-hand side of the desktop menu bar.

This issue does NOT occur if the user clicked on the notification as soon as it popped up.

Is there a way to respond to delayed click events on notifications?

2 Likes

Interesting, most likely a Firefox bug. You know what that means… :smiley:

I couldn’t find a report for that, only something that may be related:

Although, even though it doesn’t count as a user action, I would still expected it to wake up the event page (since it’s an event).
Are you sure you registering the handler in the top level background script?

I’ve entered a bug in Bugzilla:

1 Like

It means two things :slight_smile:
Report the bug and find a workaround.

Would the workaround be to keep the service worker / event page alive?

edit:
I know that Firefox MV3 extensions support event pages.
Do they also support service workers?

1 Like

Good point!

And yes, keeping worker alive should help (if it’s really the root cause).

I have a following helper for similar situations (TypeScript code):

import {AsyncWork} from '../typescript/types';

// executes long-running async work without letting the service worker to die
export async function withoutKillingWorker<T>(asyncWork: AsyncWork<T>): Promise<T> {
  // WARNING: dummy call even BEFORE is needed!
  // In case you use this fn in a loop to "fetch" list of items (each taking 11s), you would still get killed before fetching the third item.
  browser.runtime.getPlatformInfo();
  const id = self.setInterval(() => browser.runtime.getPlatformInfo(), 2e4);
  return await asyncWork().finally(() => self.clearInterval(id));
}

So after showing the notification you would do something like this:

withoutKillingWorker(() => new Promise(resolve => {
  browser.notifications.onClosed.addListener(resolve);
}));

Which will keep the worker alive, until the notification is closed.

It’s a good practice to also remove the onClosed listener, but in this case it’s fine I guess, since it will be removed anyway when the event page is destroyed.

1 Like

Not yet:

And I don’t think it’s a priority anymore, since event pages are good enough (one could even say they are better, because they have DOM API available).

Plus extensions can now specify both - event page and the service worker and that will make it work in Firefox and Chrome.

1 Like

@aecreations, do you synchronously register the notification listener on first execution of the background script? If the listener is registered asynchronously, that would explain the behavior you described where “This issue does NOT occur if the user clicked on the notification as soon as it popped up”

The notification listener is registered synchronously in the background script:

browser.notifications.onClicked.addListener(aNotifID => {
  if (aNotifID == "demo-notifcn") {
    handleNotificationClick();
  }
});