Skip to content

Commit

Permalink
Switch to PWA in Firefox extension when SW API is unavailable (#878)
Browse files Browse the repository at this point in the history
This is necessary for Firefox >=103, where the ServiceWorker API has been
removed in WebExtensions.
See https://hg.mozilla.org/integration/autoland/rev/3a2907ad88e8

Fixes #877
  • Loading branch information
mossroy authored Aug 4, 2022
1 parent d76e09f commit 53ba099
Showing 1 changed file with 73 additions and 64 deletions.
137 changes: 73 additions & 64 deletions www/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -780,76 +780,85 @@ define(['jquery', 'zimArchiveLoader', 'uiUtil', 'settingsStore','abstractFilesys
caches.delete(ASSETS_CACHE);
}
} else if (value === 'serviceworker') {
if (!isServiceWorkerAvailable()) {
uiUtil.systemAlert('The ServiceWorker API is not available on your device. Falling back to JQuery mode', 'ServiceWorker API not available').then(function () {
setContentInjectionMode('jquery');
});
return;
}
if (!isMessageChannelAvailable()) {
uiUtil.systemAlert('The MessageChannel API is not available on your device. Falling back to JQuery mode', 'MessageChannel API not available').then(function () {
setContentInjectionMode('jquery');
});
return;
}
var protocol = window.location.protocol;
if (!isServiceWorkerReady()) {
$('#serviceWorkerStatus').html("ServiceWorker API available : trying to register it...");
if (navigator.serviceWorker.controller) {
console.log("Active service worker found, no need to register");
serviceWorkerRegistration = true;
// Remove any jQuery hooks from a previous jQuery session
$('#articleContent').contents().remove();
// Create the MessageChannel and send 'init'
initOrKeepAliveServiceWorker();
refreshAPIStatus();
} else {
navigator.serviceWorker.register('../service-worker.js').then(function (reg) {
// The ServiceWorker is registered
serviceWorkerRegistration = reg;
// We need to wait for the ServiceWorker to be activated
// before sending the first init message
var serviceWorker = reg.installing || reg.waiting || reg.active;
serviceWorker.addEventListener('statechange', function(statechangeevent) {
if (statechangeevent.target.state === 'activated') {
// Remove any jQuery hooks from a previous jQuery session
$('#articleContent').contents().remove();
// Create the MessageChannel and send the 'init' message to the ServiceWorker
// Since Firefox 103, the ServiceWorker API is not available any more in Webextensions. See https://hg.mozilla.org/integration/autoland/rev/3a2907ad88e8 and https://bugzilla.mozilla.org/show_bug.cgi?id=1593931
// Previously, the API was available, but failed to register (which we could trap a fews lines below).
// So we now need to suggest a switch to the PWA if we are inside a Firefox Extension and the ServiceWorker API is unavailable.
// Even if some older firefox versions do not support ServiceWorkers at all (versions 42, 43, 45ESR, 52ESR, 60ESR and 68ESR, based on https://caniuse.com/serviceworkers). In this case, the PWA will not work either.
if (protocol === 'moz-extension:' && !isServiceWorkerAvailable()) {
launchMozillaExtensionServiceWorker();
} else {
if (!isServiceWorkerAvailable()) {
uiUtil.systemAlert('The ServiceWorker API is not available on your device. Falling back to JQuery mode', 'ServiceWorker API not available').then(function () {
setContentInjectionMode('jquery');
});
return;
}
if (!isMessageChannelAvailable()) {
uiUtil.systemAlert('The MessageChannel API is not available on your device. Falling back to JQuery mode', 'MessageChannel API not available').then(function () {
setContentInjectionMode('jquery');
});
return;
}
if (!isServiceWorkerReady()) {
$('#serviceWorkerStatus').html("ServiceWorker API available : trying to register it...");
if (navigator.serviceWorker.controller) {
console.log("Active service worker found, no need to register");
serviceWorkerRegistration = true;
// Remove any jQuery hooks from a previous jQuery session
$('#articleContent').contents().remove();
// Create the MessageChannel and send 'init'
initOrKeepAliveServiceWorker();
refreshAPIStatus();
} else {
navigator.serviceWorker.register('../service-worker.js').then(function (reg) {
// The ServiceWorker is registered
serviceWorkerRegistration = reg;
// We need to wait for the ServiceWorker to be activated
// before sending the first init message
var serviceWorker = reg.installing || reg.waiting || reg.active;
serviceWorker.addEventListener('statechange', function(statechangeevent) {
if (statechangeevent.target.state === 'activated') {
// Remove any jQuery hooks from a previous jQuery session
$('#articleContent').contents().remove();
// Create the MessageChannel and send the 'init' message to the ServiceWorker
initOrKeepAliveServiceWorker();
// We need to refresh cache status here on first activation because SW was inaccessible till now
// We also initialize the ASSETS_CACHE constant in SW here
refreshCacheStatus();
refreshAPIStatus();
}
});
if (serviceWorker.state === 'activated') {
// Even if the ServiceWorker is already activated,
// We need to re-create the MessageChannel
// and send the 'init' message to the ServiceWorker
// in case it has been stopped and lost its context
initOrKeepAliveServiceWorker();
// We need to refresh cache status here on first activation because SW was inaccessible till now
// We also initialize the ASSETS_CACHE constant in SW here
refreshCacheStatus();
refreshAPIStatus();
}
});
if (serviceWorker.state === 'activated') {
// Even if the ServiceWorker is already activated,
// We need to re-create the MessageChannel
// and send the 'init' message to the ServiceWorker
// in case it has been stopped and lost its context
initOrKeepAliveServiceWorker();
}
refreshCacheStatus();
refreshAPIStatus();
}).catch(function (err) {
if (protocol === 'moz-extension:') {
launchMozillaExtensionServiceWorker();
} else {
console.error('Error while registering serviceWorker', err);
refreshCacheStatus();
refreshAPIStatus();
var message = "The ServiceWorker could not be properly registered. Switching back to jQuery mode. Error message : " + err;
if (protocol === 'file:') {
message += "<br/><br/>You seem to be opening kiwix-js with the file:// protocol. You should open it through a web server : either through a local one (http://localhost/...) or through a remote one (but you need SSL : https://webserver/...)";
}).catch(function (err) {
if (protocol === 'moz-extension:') {
// This is still useful for Firefox<103 extensions, where the ServiceWorker API is available, but fails to register
launchMozillaExtensionServiceWorker();
} else {
console.error('Error while registering serviceWorker', err);
refreshAPIStatus();
var message = "The ServiceWorker could not be properly registered. Switching back to jQuery mode. Error message : " + err;
if (protocol === 'file:') {
message += "<br/><br/>You seem to be opening kiwix-js with the file:// protocol. You should open it through a web server : either through a local one (http://localhost/...) or through a remote one (but you need SSL : https://webserver/...)";
}
uiUtil.systemAlert(message, "Failed to register ServiceWorker").then(function () {
setContentInjectionMode('jquery');
});
}
uiUtil.systemAlert(message, "Failed to register ServiceWorker").then(function () {
setContentInjectionMode('jquery');
});
}
});
});
}
} else {
// We need to reactivate Service Worker
initOrKeepAliveServiceWorker();
}
} else {
// We need to reactivate Service Worker
initOrKeepAliveServiceWorker();
}
// User has switched to Service Worker mode, so no longer needs the memory cache
// We should empty it to ensure good memory management
Expand Down

0 comments on commit 53ba099

Please sign in to comment.