Duplicate request when opening a target="_blank" link in a standalone Chrome PWA - google-chrome

I have a website which runs a service-worker. When I install the website as a PWA App using Add to Homescreen (standalone mode), the site works fine, except that any target="_blank" links cause a duplicate request on the server side - there are two simultanous requests, but only one window opens. This happens even when service worker has no caching logic (fetch handler is empty)
I'm seeing this on Chrome (Huawei, Android 9), as well as Chrome (Samsung, Android 6) and Samsung Internet Browser - but not on iOS Safari.
The duplicate request happens no matter if there is any fetch event implemented in PWA or not
Only one debugger event gets caught in service-worker fetch event, fiddler sees two requests
Only happens in "installed" PWA, not in regular browser or non-PWA homescreen website shortcut
The resource is not cached (or supposed to be cached)
I've made a minimal repro application that I can replicate the issue in:
/index.html
/page.html
/service-worker.js
/manifest.json
index.html:
<head><link rel="manifest" href="/manifest.json"></head>
<body>
CLICK ME
<script>navigator.serviceWorker.register('/service-worker.js', { scope: '/' });</script>
</body>
manifest.json:
{
"background_color": "#FFFFFF",
"description": "Repro application",
"display": "standalone",
"name": "Repro application",
"short_name": "Repro application",
"start_url": "/index.html",
"theme_color": "#FFFFFF"
}
service-worker.js:
(function () {
'use strict';
self.addEventListener('fetch', function (event) { });
self.addEventListener('activate', function (event) { });
}());
Also happens without fetch event at all, or with fetch event just returning a network fetch promise (so default browser behaviour)
page.html content doesn't matter (if it's not there, it just 404's twice)
Only the target="_blank" links hit the server twice, "_self" works fine. Any ideas how to track down what's causing the extra hit?

Related

Cache Storage created by service worker disappears after going offline and refreshing page

I am trying to implement offline capabilities for my web app but I'm experiencing some strange behavior while offline and it's probably something I'm missing since it's reproducible both in Chrome and Firefox.
I'll describe below what the sample app I created does:
Steps to reproduce
Open a new Chrome tab and open console view.
Navigate to sample app (hosted on Netlify).
Observe log messages confirming the installation and activation of service worker, plus the creation and population of the app's cache storage.
Go to application tab in developer tools and confirm that cache was created and populated
Under "Service Worker" enable "Offline" to make network unavailable.
Alternatively just turn off your wifi/network.
Refresh page.
Observed behavior
The cache storage MyCache previously created by the service worker disappears.
Expected behavior
The page fails to load as expected but the cache storage should remain available after refreshing so that the app can use it for serving content while being offline.
HTML code
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vanishing cache storage test</title>
<script>
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/sw.js')
.then((registration) => {
console.log('Service worker registered sucessfully:', registration);
})
.catch((error) => {
console.error('Failed to register service worker:', error.stack);
});
});
}
</script>
</head>
<body>
<h1>Hi!</h1>
</body>
</html>
Service worker
const CACHE_NAME = 'MyCache';
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(CACHE_NAME)
.then((cache) => {
return cache.add('/');
})
.then(() => {
console.debug(CACHE_NAME, 'created and populated');
})
);
});
self.addEventListener('activate', (event) => {
console.debug('SW activated');
});
OS + browser version
Google Chrome Version: 87.0.4280.141 (Official Build) (x86_64)
Firefox version: 85.0b5 (64-bit, Developer Edition)
OS: macOS v11.1 (Big Sur)
Question
Is this expected behavior? If so, why? 🤔
Notes
I couldn't test on Safari because I there's no visible way to visualize cache storage content (ugh!).
After refreshing on Firefox, you might need to close and reopen devtools to have the Storage tab refresh itself.
before going offline: cache is A-OK
after refreshing while offline: cache is gone!
The cache content is still there. If you go online and refresh the page, you can see it again (it isn't being redownloaded).
I've filed https://bugs.chromium.org/p/chromium/issues/detail?id=1164309, as storage should be visible in devtools even if the page doesn't load.
No, cache storage does not get disappears after going offline.
The reason you are experiencing this behavior is because your site is not working in offline mode right now.
Add below fetch event handler in your service worker and your site will work fine in offline mode as well.
self.addEventListener("fetch", function (event) {
event.respondWith(
caches.match(event.request).then(function (response) {
if (response) {
return response;
}
return fetch(event.request);
})
);
});

How do I return the user to my TWA when pressing on a media notification?

I'm building an Android app that wraps my Progressive Web App as a Trusted Web Activity. (I'm following guidelines from Google's sample project.)
When the user plays audio in the app, a media notification appears on the device. I'm using the web Media Session API to customise the content of this notification.
If running the PWA in a normal web browser, once the notification appears, pressing it returns the user to the relevant browser tab. (If the phone is locked, the user is prompted to unlock.)
If the media notification is triggered from the TWA, pressing on it does nothing. (Other functionality such as play/pause works as expected.)
The Media Session API is fairly limited in scope. MediaSession action types do not include an action to focus the app.
navigator.mediaSession.setActionHandler('pause', () => {
audioElement.pause();
navigator.mediaSession.playbackState = 'paused';
});
navigator.mediaSession.setActionHandler('play', () => {
audioElement.play();
navigator.mediaSession.playbackState = 'playing';
});
navigator.mediaSession.metadata = new MediaMetadata({
title: 'App',
artist: 'Name',
artwork: [
{ src: '/android-chrome-192x192.png?v=47rE43RRzB', sizes: '192x192', type: 'image/png' },
{ src: '/android-chrome-512x512.png?v=47rE43RRzB', sizes: '512x512', type: 'image/png' },
],
});
When the media notification is trigged from the TWA, I expect the same functionality as when it is triggered from a web browser such as Chrome.
That includes the returning the user to the TWA (or prompting the user to unlock the device) when the notification is pressed anywhere except the play/pause control.
Everything else works except this aspect.
This was the default action in pwa and web, whenever someone clicks on notification media control, its takes to the website or pwa, but in twa its broken, its taking to the chrome browser but not focusing the app or website. I already raised ticket for the same on github

My code works Firefox, Safari and MS Edge but doesn't work in Chrome

My code works Firefox, Safari and MS Edge but doesn't work in Chrome. (I try online my website. Doesn't work. is it possible my site ?)
HTML
<button onclick = "bildirim()" >Bildirim yolla</button>
JS
function bildirim () {
if (!("Notification" in window)) {
alert("Your browser does not support Web Notifications API");
}
else if (Notification.permission === "granted") {
var notification = new Notification('Bildirim', {
body: '',
icon: '',
});
setTimeout(function(){
notification.close();
}, 3000);
}
else if (Notification.permission !== 'denied') {
Notification.requestPermission(function (permission) {
if (permission === "granted") {
var notification = new Notification('', {
body: '',
icon: '',
});
setTimeout(function(){
notification.close();
}, 3000);
}
});
}
}
When I try offline, the button wants to open the permission. When I open it, it does not accept it and wants me to turn it back on. It keeps on going. Not send me notification.
When I upload html the web site, the button does not respond. The website does not even ask for permission. So I do not even get an error.
Chrome is up to date.
SOLVED
Chrome not working this code without SSL. So not work HTTP:// works HTTPS://.
Here are some observations regarding Notification in Chrome:
Notification doesn't work from local file (file://). If you have local webserver try putting it there and see it works or not. It worked for me.
When you have uploaded it on server, if its getting loaded in an iframe and the iframes domain is different than the main windows domain then it doesn't work if the domain of iframe is not already allowed for showing notification. For example: if you first check the example on https://developer.mozilla.org/en-US/docs/Web/API/notification, it doesn't work. But if you access the URL https://mdn.mozillademos.org/en-US/docs/Web/API/notification$samples/Example?revision=1326091 it asks for permission and once you allow, it works there as well as the previous link. Another example is https://davidwalsh.name/demo/notifications-api.php. Here it works because probably the iframe domain and top window domain are same.
I've seen working notifications on HTTPS sites only. I've not seen it from any HTTP site (except http://localhost). So that (HTTPS) could also be one of the requirements for notifications to work.
Unfortunately I've not found any links that document / confirm these observations.

Why is my 'add to home screen' Web App Install Banner not showing up in my web app

I've created a service-worker and manifest.json file in order to display an 'add to home screen' Web App Install Banner for Chrome Browser Users.
It is not working as intended.
Here is my manifest.json file
{
"name": "MySite",
"short_name": "Mysite",
"start_url": "./?utm_source=homescreen",
"icons": [{
"src": "assets/cacheable/images/shortcut/120x120.png",
"sizes": "128x128",
"type": "image/png"
}, {
"src": "assets/cacheable/images/shortcut/142x142.png",
"sizes": "142x142",
"type": "image/png"
}, {
"src": "assets/cacheable/images/shortcut/192x192.png",
"sizes": "192x192",
"type": "image/png"
}, {
"src": "assets/cacheable/images/shortcut/192x192.png",
"sizes": "384x384",
"type": "image/png"
}],
"orientation": "portrait" ,
"background_color": "#fff",
"display": "standalone",
"theme_color": "#fff"
}
Please let me know if I forgot to add anything?
First, let's check if your manifest fulfills the requirements for showing Web App Install Banners.
Requirements
Full (current) requirements for showing Web App Install Banners are*:
Have a web app manifest file with:
a short_name
a name (used in the
banner prompt)
a 144x144 png icon
a start_url that loads
Is served over HTTPS (a requirement for using service worker).
Is visited at least twice, with at least five minutes between visits.
Reference
Okay, so for now let's assume this is all valid. Let's move on to testing.
Testing
To test if you've installed it correctly, you can try the following steps:
Open Chrome DevTools,
Go to the Application panel
Go to the Manifest tab
Click Add to homescreen.
A prompt should now show on top of your browser asking if you want to add the url to your things (on Chrome desktop).
Troubleshooting
If after testing you are getting the following error in your console:
No matching service worker detected. You may need to reload the page, or check that the service worker for the current page also controls the start URL from the manifest
Then please make sure that 1. Your service worker is functioning properly and without errors, and 2. Your start_url matches an actual url of your website that loads. Else, you will never get the prompt to show!
Additionally,
Do note that users (and you!) can also add to the home screen manually through the the (Android) Chrome menu. It is not required to wait for the prompt! I add a lot of websites I tend to use daily to my homescreen, and I hardly ever see a banner!
* Do note that these requirements could change from time to time (they have before!). An update to 'Add to home screen' coming in 2017 has already been announced here
** Also note that these requirements differ significantly from native app install prompts.**
your manifest.json seems good enough.
and the above mentioned points by #Extricate are correct and perfect.
So the next question is have you implemented service-worker for your app?
I read somewhere that an empty service-worker file would work but when I tried an empty implementation of service-worker, it said that
'Site cannot be installed: the page does not work offline'
So I suppose that latest chrome version would not be supporting the A2HS prompt for APP INSTALL BANNERS if you service-worker dont support offline working.
You can try going to Basic web app prompt , go to devtools in chrome, navigate to Application tab.
There you will find manifest.json. On LHS of the manifest file, you can see the ADD TO HOME SCREEN. When you click, it will print
'Site cannot be installed: the page does not work offline'
PFA screenshot for same
In your service worker js file add this one line of code:
self.addEventListener('fetch', function(event) {});
May be usefull, as had similar issue. The Install infobar appeared once and never again.
From Developers Google
The mini-infobar will appear when the site meets the criteria, and
once dismissed by the user, it will not appear again until a
sufficient amount of time has passed (currently 3 months).

Multi-Window Chrome Packaged App?

Hello I'm new to chrome packaged apps.
How would I create a button image, that when clicked launches
a new chrome packaged app window displaying a local html page.
In your first html page, just add the button. Also, that page will need to reference a Javascript file to add the event handlers:
<button id="thebutton">Open a New Window</button>
<script src="script.js"></script>
Then you add an event handler to the button in script.js (or whatever you name your script page):
document.querySelector('#thebutton').addEventListener('click', function() {
chrome.app.window.create('new.html', {"width":300, "height": 200});
});
If you need for that window to be sandboxed (e.g., not use the default content security policy), you need to specify that the page is sandboxed in manifest.json:
"sandbox": {
"pages": ["new.html"]
}
When new.html is loaded, it will be loaded in its own origin which doesn't have access to the opening window or to the advanced API's. If you need the sandboxed page to do something with the advanced API's, you can use postMessage and receive messages to communicate with a window that's still in the CSP.