I have a webapp for iPad with the meta tag:
<meta name="apple-mobile-web-app-capable" content="yes">
When I open up the app from the homepage (web-app-capable version) or type in the address in Mobile Safari the contents of localStorage are different. I have confirmed that the addresses are identical by printing location.href.
All changes made to localStorage while using Mobile safari are reflected in the web-app-capable version, but changes made in the web-app-capable version are not reflected in the Mobile Safari version.
The domains are identical, localStorage should be identical. What in the world is going on? Can this be fixed?
Update - Solution: Following suggestion #2 from the accepted answer (forcing the user to be in fullscreen mode) I added this bit of code:
if(("standalone" in window.navigator) && !window.navigator.standalone)
window.location = "instructions.html";
So, if you are using a browser that supports standalone mode, and you are not in standalone mode, redirect to a page (instructions.html) which shows the user how to add the app to the home screen.
Thank you to everyone for their input!
Summary:
Safari and full-screen web apps (a.k.a. web-app-capable) have separate in-memory write-through caches of the localStorage data. Each time the full-screen app becomes active, it reloads the localStorage from disk (allowing it see Safari's changes). However, when Safari becomes active, it doesn't reload the localStorage data from disk, so it won't see changes made in the full-screen app unless you kill Safari and restart it.
Full Explanation:
There are only two hard problems in Computer Science:
The buggy behavior in localStorage is a result of problem #1. Here's why:
When the iOS browser engine loads, it reads the data for localStorage from disk and caches it in memory. Then each time you read data (e.g. getItem
), the data is read from memory, not from disk; and when writing (e.g. setItem
) the data is written to memory, and then (asynchronously) flushed to disk. Since localStorage is synchronous, this implementation is a totally reasonable. If it went to disk for all reads and writes, your javascript would be blocked on every read/write to perform expensive disk IO.
The problem is that a full screen web app (let's call it a FSWA) uses a separate instance of the iOS browser engine, and although a FSWA shares the same location on disk for the localStorage data, it does not share the in-memory cache of localStorage data with Safari.
When you add the fact that FSWA completely reloads (which means the localStorage data is reloaded from disk) each time they become the active application, you get the behavior that you are seeing.
Here's the behind the scenes...
To prove this, you can kill Safari between step #4 and step #10. Then when you relaunch Safari in step #11, it will reload the localStorage from disk and you will see the data written by the FSWA.