4

I am working on a PWA and just realized that the hardware back button seems to not work correctly. The back button will go back page by page until the first page is reached, then if you continue to press it, nothing happens. I would expect the window to minimize (send the app to the background), but this only happens if the "home" button is pressed.

[Edit] It is not just a standalone issue. Backbutton->minimize is also not working in a browser on mobile for this page (works for other pages I tried).

I have reproduced this behavior on two Samsung phones, S8 and Xcover 4.

The PWA is build with Angular (1.5) / Boostrap

How can you debug something like this? Chrome Inspect emulator goes blank whenever I navigate a website on the phone. It seems it only works if you navigate in the inspector emulator.

Did I miss a setting in the manifest or something? I have included my manifest and serviceworker. Also I want to make clear that I have made no attempt to manipulate the back button within the app... afaik that is not even possible.

Manifest:

{
  "name": "My app",
  "start_url": "/login?utm_source=web_app_manifest",
  "short_name": "My app",
    "display": "standalone",
    "background_color": "#111",
  "theme_color": "#111",
  "description": "This is a description of My app", 
  "orientation": "portrait",
    "related_applications": [
    {
      "platform": "itunes",
      "url": "http://itunes.apple.com/us/app/myapp/id[removed]"
    }
  ],
  "icons": [
    {
      "src": "gfx\/fg\/favicon-16x16a.png",
      "sizes": "16x16",
      "type": "image\/png",
      "density": "0.75"
    },
    {
      "src": "gfx\/fg\/android-icon-36x36.png",
      "sizes": "36x36",
      "type": "image\/png",
      "density": "0.75"
    },
    {
      "src": "gfx\/fg\/android-icon-48x48.png",
      "sizes": "48x48",
      "type": "image\/png",
      "density": "1.0"
    },
    {
      "src": "gfx\/fg\/android-icon-72x72.png",
      "sizes": "72x72",
      "type": "image\/png",
      "density": "1.5"
    },
    {
      "src": "gfx\/fg\/android-icon-96x96.png",
      "sizes": "96x96",
      "type": "image\/png",
      "density": "2.0"
    },
    {
      "src": "gfx\/fg\/android-icon-144x144.png",
      "sizes": "144x144",
      "type": "image\/png",
      "density": "3.0"
    },
    {
      "src": "gfx\/fg\/android-icon-192x192.png",
      "sizes": "192x192",
      "type": "image\/png",
      "density": "4.0"
    }
  ]
}

Serviceworker (from pwabuilder.com)

//Install stage sets up the offline page in the cache and opens a new cache
self.addEventListener('install', function(event) {
  event.waitUntil(preLoad());
});

var preLoad = function(){
  //console.log('[PWA Builder] Install Event processing');
  return caches.open('pwabuilder-offline').then(function(cache) {
    //console.log('[PWA Builder] Cached index and offline page during Install');
    return cache.addAll(['/offline.html', '/index.html']);
  });
}

self.addEventListener('fetch', function(event) {
  //console.log('The service worker is serving the asset.');
  event.respondWith(checkResponse(event.request).catch(function() {
    return returnFromCache(event.request)}
  ));
  event.waitUntil(addToCache(event.request));
});

var checkResponse = function(request){
  return new Promise(function(fulfill, reject) {
    fetch(request).then(function(response){
      if(response.status !== 404) {
        fulfill(response)
      } else {
        reject()
      }
    }, reject)
  });
};

var addToCache = function(request){
  return caches.open('pwabuilder-offline').then(function (cache) {
    return fetch(request).then(function (response) {
      //console.log('[PWA Builder] add page to offline'+response.url)
      return cache.put(request, response);
    });
  });
};

var returnFromCache = function(request){
  return caches.open('pwabuilder-offline').then(function (cache) {
    return cache.match(request).then(function (matching) {
     if(!matching || matching.status == 404) {
       return cache.match('offline.html')
     } else {
       return matching
     }
    });
  });
};
Jette
  • 2,459
  • 28
  • 37
  • That's not the experience I have with PWAs. If I have [HNPWA](https://hnpwa.com/) installed on a Pixel device, open it, and hit the back button the PWA is closed and I'm returned to the home screen. – abraham Dec 18 '17 at 23:08
  • That is why I suspect something is wrong with my PWA. JoinDiaspora also returns flawlessly to the start screen on my mobile. – Jette Dec 19 '17 at 09:50
  • Just realized that this problem is also present when the PWA is running in a browser on the device. – Jette Dec 19 '17 at 10:44
  • 1
    I would guess there is some JavaScript running in the client (not in the service worker) that is messing up history traversal. Maybe even from some framework/library. – abraham Dec 19 '17 at 18:11
  • This answer should work for you https://stackoverflow.com/a/48932255/5657916 – Yee Kung Mar 08 '18 at 10:31
  • This should work for you, take a look at https://stackoverflow.com/a/48932255/5657916 – Yee Kung Mar 08 '18 at 10:32
  • 1
    @YeeKung It is my understanding that navigator.app.exitApp() is a Cordova/Phonegap thing and therefore not available in a PWA. – Jette Mar 19 '18 at 09:07

1 Answers1

0

I have the exact same issue, and I found the cause in my case. My PWA is doing several things with the history, but the root of the problem boils down to this:

Chrome on Android does not allow to close a fullscreen PWA programmatically via history.back(). You can invoke history.back() multiple times and it will never close the app. Even if the history is empty, a programmatic invocation of history.back() will not close the app. The only way to close the app is a physical press on the back button. A physical back press will close the app, if and only if there is currently no back-history.

Update with more details: Ultimately the problem described above had the effect of the back button being unable to close the app. The reason lies deeper in the stuff that our app is doing with the history. I will try to keep it simple. When the page first loads, our app is pushing a state onto the history, and it tries to keep this state on the history at all times. Whenever a back-navigation happens, the app will manipulate the history and make sure to re-push the state. When the app detects that the user wants to close the app, it will stop doing its thing and it will recursively invoke history.back() until the page is closed. This works fine in most scenarios, but it does not work in fullscreen PWA. The reason is described in my original answer.

In summary, there are ways to easily break the back button's ability to close the app. You have to be careful when manipulating the history.

Fatih Coşkun
  • 243
  • 2
  • 8
  • Thank you for answering, but the trouble for me is not a back button inside the app. I wrote "hardware back button seems to not work correctly". I just tested this issue again as I am now on a newer version of Android, but it seems to just re-initialize the last page/component in history again and again. – Jette Dec 05 '18 at 08:38
  • The issue I described ultimately lead to the same effect for me: the hardware back button is unable to close the app. I will add more details in the answer above. – Fatih Coşkun Dec 05 '18 at 10:07