iOS 'Web App' has different localStorage than Mobile Safari
Asked Answered
R

3

16

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!

Rebel answered 18/7, 2012 at 15:40 Comment(7)
when you say web app, is it a bookmark that gets saved as an app on to the home screen? or is it an app which is basically a webview that you have wrapped and running it as an app?Constituency
It is a bookmark that gets saved as an app on the home screen, but with that meta tag, it won't open IN Safari, it opens as a fullscreen app that runs in it's own instance of Safari. So, both - it's a bookmark saved to the home screen that is basically a webview running as an app.Rebel
Also, I should note - without that meta tag, this is not a problem, since the app is just opened up in a new tab of regular Mobile Safari.Rebel
once upon a time, I had tested the BoA mobile website this way and noticed considerable difference in performance between loading the url in safari, and the url wrapped in a webview as an app. Safari was faster. So I am assuming loading a webpage in a (Web App vs Mobile Safari) are not the same. I am not sure why it differs.Constituency
Mobile Safari has a faster JavaScript engine. I'm not sure why it isn't enabled for web-app, but it is probably for compatibility reasons.Bouzoun
Note the comment below about iOS 6 no longer allowing shared localstorage between Safari and Wep App. iOS 5 allowed it so some apps may need to be refactored. #11545649Jacey
There is a more recent answer (2023), here : #76700748Subedit
S
32

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:

  1. cache invalidation
  2. naming things
  3. off-by-one errors

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...

  1. user makes a change that writes data to localStorage in Safari
  2. Safari writes data to Safari's in-memory localStorage cache
  3. Safari flushes localStorage data from cache to the disk
  4. user leaves safari and launches the FSWA
  5. FSWA loads and reads localStorage data from the disk into in-memory cache
  6. user sees the data that was changed (in step #1) in Safari
  7. user makes a change in the FSWA that writes data to localStorage
  8. FSWA writes data to its localStorage cache (Safari's cache is not updated)
  9. FSWA flushes its localStorage cache data to disk
  10. user switches back to Safari
  11. Safari was already running, and it does not reload the localStorage data from disk
  12. Safari reads the old data from its existing in-memory cache
  13. user does not see changes made in step #7

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.

Supersession answered 25/8, 2012 at 15:32 Comment(1)
With iOS6, things have changed. Now data from a full-screen web app is completely separate from safari (like a native app). See blog.nsbasic.com/?p=928Supersession
B
5

In iOS5 I was able to have two full screen web apps on the same domain that were able to see each other's localStorage. That overcame the difference between full screen and Safari.

However, with iOS6 I am having to merge my two full screen web apps to one app.

Brazzaville answered 24/10, 2012 at 11:48 Comment(0)
F
3

Assuming you're saving local storage data correctly and if I'm not mistaken, what you experience is a somewhat of a common issue among web app developers. Cookies, sessions and local storage seem to be stored differently in the "web app" (launched from homescreen) to that of the data saved via mobile safari.

I've done some rather thorough testings of this in the past and it seems to me that there's no workaround good enough. Just to give you an example where my colleagues and I have faced a similar problem: in a web app we developed recently, the user has to login before accessing all its features. If one logs in via mobile safari and then switches to the downloaded version of the app, one expects to be logged in but this is not always the case. One usually has to login again, suggesting cookies may be stored in different "data banks", depending on how or from where you choose to launch the app.

Furthermore, as Calvin says, there are more to it than just different data banks as it were. Apps launched via home screen appears to open more slowly, homescreen apps are always reloaded when launched suggesting no multi task support, etc. My conclusion: the program launching downloaded web apps != safari minus the address bar and hence should not be treated as such.

Although a nice feature by Apple, homescreen web apps don't quite perform as expected or as one would hope (like as it were opened in safari.) In your case, assuming you store LS data correctly and have tried different approaches to fix your particular problem, I would suggest one of the following alternatives:

  1. Use a mysql database to r/w from/to instead
  2. Force users to download the app before using it (like in this example)
  3. Don't encourage users to download the app and assume most of them will access it from mobile safari
  4. Accept the fact that data may differ (this may not be an alternative to you depending on the nature of your app)
  5. Take my approach, "convert" your web app to a native app via Phonegap's built in features. If so, take a look at this tutorial by Jonathan Stark.

Hope this helped clarifying at least parts of it.

Frazzled answered 23/7, 2012 at 0:13 Comment(2)
Phonegap seems like a lot of work, and I don't have freedom to make assumptions or accept inconsistency in this project. And it has to go offline with caching, so mysql isn't an option. So I went with 2 and it was really simple! Thank you!Rebel
@Frazzled the first link is no longer working, could you please update your answer? : )Sleeping

© 2022 - 2024 — McMap. All rights reserved.