Recently I had been working on a little mobile web app that fetches JSON data, puts it in localStorage, and then renders the views for it. Since the data could get large, there is a check that occurs before the full JSON dump. If we have localStorage data, then the app asks the server what version is the latest. The app will then either render the data if it’s the latest or pull more data down from the server and stash it away and render it to the screen.
Upon attempting a pairing of the device with the Safari desktop browser for the inspector use (more info on that feature here), we finally had a break. Safari was not pairing properly because the device was in Private Browsing mode. When we turned off Private Browsing mode, the pairing with Safari worked, and the application ran fine. Further investigation into the problem showed that every device affected had Private Browsing enabled.
iOS Private Browsing + localStorage
Whats the problem with iOS Private Browsing? As you would expect, it clears cookies and history and doesn’t allow it to persist after closing mobile Safari. One would assume that localStorage would be accessible and cleared after close of the app, but there interesting caveats.
In Private Browsing mode, localStorage can be read but not written. Our code was attempting to write to the localStorage upon successful download of the JSON data. After many attempts at decent workarounds, we came up with a helper function that can be called to return the reading and writing state of localStorage:
hasStorage = -> try mod = new Date localStorage.setItem mod, mod.toString() result = localStorage.getItem(mod) == mod.toString() localStorage.removeItem mod return result
As you can see, we check to make sure localStorage is defined by writing to localStorage and making sure that object comes back out the same. The reason we had to do this in a try/catch block is because iOS localStorage writes operations throw an exception when attempted in Private Browsing mode. We can call this helper to give the state of localStorage and conditionally read and write to localStorage depending on the capability we have available.