localStorage is not saved correctly on iOS using Cordova

0

I am developing an app for iOS and Android using Cordova. Everything works well, except for a part that works on Android but not on iOS: the persistent storage of data.

In my code I have this:

storage = {
    save: function(name, value) {
        window.localStorage.setItem(name, JSON.stringify(value));
    },
    load: function(name) {
        var aux = window.localStorage.getItem(name);
        if (aux && aux != "") { return JSON.parse(aux); } else { return false; }
    }
}

Then in my app, to save some data I do storage.save("nombre", json_con_datos) and to recover it afterwards I just do storage.load("nombre") . This works well on Android where I can save and recover data without problems, but it fails on iOS, where it seems that nothing is saved.

I'm doing tests on iOS 9.3 (both device and emulator) and Android 4.1 (on device) and 5.0 (on emulator).

And now the questions: What is wrong? Does iOS support the use of localStorage ? Should I store the data in a different way? (And how would it be?) Is there a method that works on both Android and iOS?

    
asked by Alvaro Montoro 09.08.2016 в 15:52
source

1 answer

0

Support for sessionStorage and localStorage is quite broad, so it should not cause problems in most of the browsers / devices on which you use them. The other part that your code depends on is the JSON parsing API which also has broad support. Here is the details of the versions that you can find in caniuse for Storage and JSON

Storage and JSON

  • Android 2.1 +
  • IOS 3.2 +
  • Chrome 4 +
  • Firefox 3.5 +
  • There is an alternative when you want to increase the support for these APIs that is to create a polyfill in memory but keep in mind that this is not a 100% equivalent replacement since

      

    The data stored in localStorage does not have an expiration date

    and

      

    The information stored in sessionStorage is deleted at the end of the session of the page. The session of the page lasts while the browser is open, and remains above the reloads and reopenings of the page

    Creating an in-memory storage will allow you to use the API but as soon as you update the page all that information will be erased. You can use cookies to get around this obstacle but remember that cookies have security considerations and the storage size is much lower (~ 5Mb total localStorage => ~ 4 kb per cookie, 20 cookies per domain).

    Here is the pollyfill for localStorage . This is a variant of the MDN officer to support events and the clear method (in addition to not use obsolete methods like escape and unescape ).

    if (!window.localStorage) {
        Object.defineProperty(window, 'localStorage', new (function () {
            var aKeys = [], oStorage = {};
    
            var dispatchStorageEvent = function (key, newValue) {
                var oldValue = (key == null) ? null : oStorage.getItem(key);
                var url = location.href.substr(location.origin.length);
                var storageEvent = document.createEvent('StorageEvent');
    
                storageEvent.initStorageEvent('storage', false, false, key, oldValue, newValue, url, null);
                window.dispatchEvent(storageEvent);
            };
    
            Object.defineProperty(oStorage, 'getItem', {
                value: function (sKey) {
                    return sKey ? this[sKey] : null;
                },
                writable: false,
                configurable: false,
                enumerable: false
            });
            Object.defineProperty(oStorage, 'key', {
                value: function (nKeyId) {
                    return aKeys[nKeyId];
                },
                writable: false,
                configurable: false,
                enumerable: false
            });
            Object.defineProperty(oStorage, 'setItem', {
                value: function (sKey, sValue) {
                    if (!sKey) {
                        return;
                    }
                    document.cookie = encodeURIComponent(sKey) + "=" + encodeURIComponent(sValue) + '; expires=Tue, 19 Jan 2038 03:14:07 GMT; path=/';
                    dispatchStorageEvent(sKey, sValue);
                },
                writable: false,
                configurable: false,
                enumerable: false
            });
            Object.defineProperty(oStorage, 'length', {
                get: function () {
                    return aKeys.length;
                },
                configurable: false,
                enumerable: false
            });
            Object.defineProperty(oStorage, 'removeItem', {
                value: function (sKey) {
                    if (!sKey) {
                        return;
                    }
                    document.cookie = encodeURIComponent(sKey) + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/';
                    dispatchStorageEvent(sKey, null);
                },
                writable: false,
                configurable: false,
                enumerable: false
            });
            Object.defineProperty(oStorage, 'clear', {
                value: function () {
                    document.cookie.split(/\s*;\s*/).forEach(function (c) {
                        document.cookie = c.replace(/^ +/, '').replace(/=.*/, '=;expires=' + new Date().toUTCString() + ';path=/');
                    });
                    dispatchStorageEvent(null, null);
                },
                writable: false,
                configurable: false,
                enumerable: false
            });
    
            this.get = function () {
                var iThisIndx;
                for (var sKey in oStorage) {
                    iThisIndx = aKeys.indexOf(sKey);
                    if (iThisIndx === -1) {
                        oStorage.setItem(sKey, oStorage[sKey]);
                    }
                    else {
                        aKeys.splice(iThisIndx, 1);
                    }
                    delete oStorage[sKey];
                }
                for (aKeys; aKeys.length > 0; aKeys.splice(0, 1)) {
                    oStorage.removeItem(aKeys[0]);
                }
                for (var aCouple, iKey, nIdx = 0, aCouples = document.cookie.split(/\s*;\s*/); nIdx < aCouples.length; nIdx++) {
                    aCouple = aCouples[nIdx].split(/\s*=\s*/);
                    if (aCouple.length > 1) {
                        oStorage[iKey = decodeURIComponent(aCouple[0])] = decodeURIComponent(aCouple[1]);
                        aKeys.push(iKey);
                    }
                }
                return oStorage;
            };
            this.configurable = false;
            this.enumerable = true;
        })());
    }
    
      

    Note: Using the clear method will remove all cookies from the document including those that were not created with setItem

    Here is a polyfill for JSON

    if (!window.JSON) {
      window.JSON = {
        parse: function(sJSON) { return eval('(' + sJSON + ')'); },
        stringify: (function () {
          var toString = Object.prototype.toString;
          var isArray = Array.isArray || function (a) { return toString.call(a) === '[object Array]'; };
          var escMap = {'"': '\"', '\': '\\', '\b': '\b', '\f': '\f', '\n': '\n', '\r': '\r', '\t': '\t'};
          var escFunc = function (m) { return escMap[m] || '\u' + (m.charCodeAt(0) + 0x10000).toString(16).substr(1); };
          var escRE = /[\"\u0000-\u001F\u2028\u2029]/g;
          return function stringify(value) {
            if (value == null) {
              return 'null';
            } else if (typeof value === 'number') {
              return isFinite(value) ? value.toString() : 'null';
            } else if (typeof value === 'boolean') {
              return value.toString();
            } else if (typeof value === 'object') {
              if (typeof value.toJSON === 'function') {
                return stringify(value.toJSON());
              } else if (isArray(value)) {
                var res = '[';
                for (var i = 0; i < value.length; i++)
                  res += (i ? ', ' : '') + stringify(value[i]);
                return res + ']';
              } else if (toString.call(value) === '[object Object]') {
                var tmp = [];
                for (var k in value) {
                  if (value.hasOwnProperty(k))
                    tmp.push(stringify(k) + ': ' + stringify(value[k]));
                }
                return '{' + tmp.join(', ') + '}';
              }
            }
            return '"' + value.toString().replace(escRE, escFunc) + '"';
          };
        })()
      };
    }
    
        
    answered by 09.08.2016 / 19:15
    source