iOS "веб-приложение" имеет другой localStorage, чем Mobile Safari

у меня есть webapp для iPad с метатегом:

<meta name="apple-mobile-web-app-capable" content="yes">

когда я открываю приложение с домашней страницы (версия с поддержкой веб-приложений) или набираю адрес в мобильном Safari, содержимое localStorage отличается. Я подтвердил, что адреса идентичны, распечатав местоположение.хреф.

все изменения, внесенные в localStorage при использовании Mobile safari, отражены в версии с поддержкой веб-приложений, но изменения, внесенные в версию с поддержкой веб-приложений, не отражены в мобильной версии "сафари".

Домены идентичны, localStorage должен быть идентичен. Что в мире творится? Это можно исправить?


Обновление - Решение: после предложения #2 из принятого ответа (заставляя пользователя находиться в полноэкранном режиме) я добавил этот бит кода:

if(("standalone" in window.navigator) && !window.navigator.standalone)
    window.location = "instructions.html";

Итак, если вы используете браузер, поддерживающий автономный режим, и вы не находитесь в автономном режиме, перенаправьте на страницу (инструкции.html), который показывает пользователю, как добавить приложение на главный экран.

спасибо всем за их вклад!

3 ответов


резюме:

Safari и полноэкранные веб-приложения (a.к. a. web-app-capable) имеют отдельные кэши записи в памяти данных localStorage. Каждый раз, когда полноэкранное приложение становится активным, оно перезагружает localStorage с диска (позволяя ему видеть изменения Safari). Однако, когда Safari становится активным, он не перезагружает данные localStorage с диска, поэтому он не увидит изменений, внесенных в полноэкранное приложение, если вы не убьете Safari и не перезапустите он.

Полное Описание:

есть только два трудные проблемы в информатике:

  1. очистку кэша
  2. называя вещи
  3. off-by-one ошибки

багги поведение в localStorage является результатом проблемы #1. Вот почему:

при загрузке браузера iOS он считывает данные для localStorage с диска и кэширует их в памяти. Тогда каждый раз Вы читаете данные (например,getItem), данные считываются из памяти, а не с диска, а при записи (например,setItem) данные записываются в память, а затем (асинхронно), записываемых на диск. Поскольку localStorage является синхронным, эта реализация является полностью разумной. Если он пошел на диск для всех чтения и записи, ваш javascript будет заблокирован на каждом чтении/записи для выполнения дорогостоящего ввода-вывода диска.

проблема в том, что полноэкранное веб-приложение (назовем его FSWA) использует отдельный экземпляр движка браузера iOS, и хотя FSWA разделяет то же расположение на диске для данных localStorage, он не разделяет кэш в памяти данных localStorage с Safari.

когда вы добавляете тот факт, что FSWA полностью перезагружается (что означает, что данные localStorage перезагружаются с диска) каждый раз, когда они становятся активным приложением, вы получаете поведение, которое вы видите.

вот за кулисами...

  1. пользователь изменение, которое записывает данные в localStorage в Safari
  2. Safari записывает данные в кэш локального хранилища в памяти Safari
  3. Safari сбрасывает данные localStorage из кэша на диск
  4. пользователь покидает safari и запускает FSWA
  5. FSWA загружает и считывает данные localStorage с диска в кэш в памяти
  6. пользователь видит данные, которые были изменены (в шаге 1) в сафари
  7. пользователь вносит изменения в FSWA, который пишет данные в localStorage
  8. FSWA записывает данные в кэш localStorage (кэш Safari не обновляется)
  9. FSWA сбрасывает данные кэша localStorage на диск
  10. пользователь переключается обратно в Safari
  11. Safari уже запущен, и он не перезагружает данные localStorage с диска
  12. Safari считывает старые данные из существующего кэша в памяти
  13. пользователь не видит изменений, внесенных в Шаг #7

в докажите это, вы можете убить сафари между шагом #4 и шагом #10. Затем, когда вы перезапустите Safari на шаге #11, он перезагрузит localStorage с диска, и вы увидите данные, записанные FSWA.


в iOS5 я смог иметь два полноэкранных веб-приложения в одном домене, которые могли видеть localStorage друг друга. Это преодолело разницу между полным экраном и Safari.

однако с iOS6 мне нужно объединить два полноэкранных веб-приложения в одно приложение.


предполагая, что вы сохраняете данные локального хранилища правильно, и если я не ошибаюсь, то вы испытываете довольно распространенная проблема среди разработчиков веб-приложений. Cookies, сеансы и локальное хранилище, похоже, хранятся по-разному в "веб-приложение" (запускается с рабочего стола), чтобы данные, сохраненные с помощью мобильного safari.

Я сделал несколько довольно тщательных тестов этого в прошлом и Мне кажется, что нет обходного пути хорошо достаточно. Просто чтобы дать вам пример, где мои коллеги и я столкнулись с аналогичной проблемой: в веб-приложении, которое мы недавно разработали, пользователь должен войти в систему, прежде чем получить доступ ко всем его функциям. Если вы входите в систему через mobile safari, а затем переключаетесь на загруженную версию приложения, вы ожидаете, что войдете в систему, но это не всегда так. Обычно нужно снова войти в систему, предполагая, что cookies могут храниться в разных "банках данных", в зависимости от того, как или откуда вы решите запустить приложение.

кроме того, как говорит Кальвин, есть еще чем просто разные банки данных, как это было. Приложения, запущенные через домашний экран, открываются медленнее, приложения на рабочем столе всегда перезагружаются при запуске, не предлагая поддержки нескольких задач и т. д. мой вывод: программа запуска веб-приложений != safari минус адресная строка и, следовательно, не должны рассматриваться как таковые.

Хотя хорошая функция от Apple, веб-приложения homescreen не работают так, как ожидалось, или как можно было бы надеяться (например, как это было открыто в safari.) В вашем случае, предполагая, что вы храните данные LS правильно и пробовали разные подходы, чтобы исправить вашу конкретную проблему,Я бы предложил одну из следующих альтернатив:

  1. использовать в MySQL база данных в r/w Из / В вместо
  2. заставить пользователей загрузить приложение перед использованием (например, в этот пример)
  3. Не поощряйте пользователей загружать приложение и предположим, что большинство из них получат доступ к нему с мобильного safari
  4. примите факт эти данные могут отличаться (это не может быть альтернативой для вас в зависимости от характера вашего приложения)
  5. принять мой подход, "конвертировать" ваше веб-приложение в родное приложение via по PhoneGap встроенные функции. Если это так, взгляните на в этом уроке Джонатан Старк.

надеюсь, это помогло прояснить хотя бы часть этого.