16

我有一个带有元标记的 iPad 网络应用程序:

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

当我从主页打开应用程序(支持网络应用程序的版本)或在 Mobile Safari 中输入地址时,localStorage 的内容不同。我已通过打印 location.href 确认地址相同。

使用 Mobile Safari 时对 localStorage 所做的所有更改都会反映在支持 Web 应用的版本中,但在支持 Web 应用的版本中所做的更改不会反映在 Mobile Safari 版本中。

域是相同的,localStorage 应该是相同的。世界上到底发生了什么?这可以解决吗?


更新 - 解决方案:根据接受的答案中的建议 #2(强制用户处于全屏模式),我添加了这段代码:

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

因此,如果您使用的是支持独立模式的浏览器,并且您未处于独立模式,请重定向到一个页面 (instructions.html),该页面向用户展示如何将应用程序添加到主屏幕。

感谢大家的意见!

4

3 回答 3

31

概括:

Safari 和全屏 Web 应用程序(又名支持 Web 应用程序)具有 localStorage 数据的单独的内存直写缓存。每次全屏应用程序激活时,它都会从磁盘重新加载 localStorage(允许它看到 Safari 的更改)。但是,当 Safari 激活时,它不会从磁盘重新加载 localStorage 数据,因此除非您杀死 Safari 并重新启动它,否则它不会看到全屏应用程序中所做的更改。

完整解释:

计算机科学只有两个难题:

  1. 缓存失效
  2. 命名事物
  3. 一个错误

localStorage 中的错误行为是问题 #1 的结果。原因如下:

当 iOS 浏览器引擎加载时,它会从磁盘读取 localStorage 的数据并将其缓存在内存中。然后每次读取数据(例如getItem)时,数据都是从内存中读取的,而不是从磁盘中读取的;并且在写入(例如setItem)时,数据被写入内存,然后(异步)刷新到磁盘。由于 localStorage 是同步的,所以这种实现是完全合理的。如果所有读写都进入磁盘,您的 javascript 将在每次读/写时被阻止以执行昂贵的磁盘 IO。

问题是全屏 Web 应用程序(我们称之为 FSWA)使用 iOS 浏览器引擎的单独实例,虽然 FSWA 为 localStorage 数据共享磁盘上的相同位置,但它不共享内存缓存Safari 的 localStorage 数据。

当您添加 FSWA 每次成为活动应用程序时完全重新加载(这意味着 localStorage 数据从磁盘重新加载)的事实时,您会得到您所看到的行为。

这里是幕后...

  1. 用户进行更改,将数据写入 Safari 中的 localStorage
  2. Safari 将数据写入 Safari 的内存中 localStorage 缓存
  3. Safari 将 localStorage 数据从缓存刷新到磁盘
  4. 用户离开 safari 并启动 FSWA
  5. FSWA 将 localStorage 数据从磁盘加载并读取到内存缓存中
  6. 用户在 Safari 中看到更改的数据(在步骤 #1 中)
  7. 用户在将数据写入 localStorage 的 FSWA 中进行更改
  8. FSWA 将数据写入其 localStorage 缓存(Safari 的缓存未更新)
  9. FSWA 将其 localStorage 缓存数据刷新到磁盘
  10. 用户切换回 Safari
  11. Safari 已经在运行,它不会从磁盘重新加载 localStorage 数据
  12. Safari 从其现有的内存缓存中读取旧数据
  13. 用户看不到在步骤 #7 中所做的更改

为了证明这一点,您可以在第 4 步和第 10 步之间杀死 Safari 。然后,当您在步骤 #11 中重新启动 Safari 时,它将从磁盘重新加载 localStorage,您将看到 FSWA 写入的数据。

于 2012-08-25T15:32:04.253 回答
5

在 iOS5 中,我能够在同一个域上拥有两个全屏 Web 应用程序,它们能够看到彼此的 localStorage。这克服了全屏和 Safari 之间的差异。

但是,在 iOS6 中,我不得不将我的两个全屏 Web 应用程序合并到一个应用程序中。

于 2012-10-24T11:48:22.887 回答
3

假设您正确保存本地存储数据,如果我没记错的话,您遇到的问题在网络应用程序开发人员中是一个常见问题。Cookie、会话和本地存储在“网络应用程序”(从主屏幕启动)中的存储方式似乎与通过移动 safari 保存的数据不同。

我过去对此进行了一些相当彻底的测试,在我看来,没有足够好的解决方法。举个例子,我和我的同事都遇到过类似的问题:在我们最近开发的一个网络应用程序中,用户必须先登录才能访问其所有功能。如果通过移动 safari 登录,然后切换到下载的应用程序版本,则希望登录,但情况并非总是如此。通常必须再次登录,这表明 cookie 可能存储在不同的“数据库”中,具体取决于您选择启动应用程序的方式或位置。

此外,正如 Calvin 所说,不仅仅是不同的数据库。通过主屏幕启动的应用程序似乎打开得更慢,启动时总是重新加载主屏幕应用程序,表明不支持多任务等等。我的结论:启动下载的网络应用程序的程序!= safari 减去地址栏,因此不应被视为这样.

尽管 Apple 提供了一项不错的功能,但主屏幕网络应用程序的性能并没有达到预期或希望的那样(就像它在 safari 中打开一样。)在您的情况下,假设您正确存储 LS 数据并尝试了不同的方法来修复您的特别的问题,我会建议以下替代方案之一:

  1. 改为使用mysql数据库从/到 r/w
  2. 强制用户在使用前下载应用程序(如本例所示
  3. 不要鼓励用户下载应用程序并假设他们中的大多数人会通过移动 Safari 访问它
  4. 接受数据可能不同的事实(这可能不是您的替代方案,具体取决于您的应用程序的性质)
  5. 采用我的方法,通过Phonegap 的内置功能将您的 Web 应用程序“转换”为本机应用程序。如果是这样,请查看 Jonathan Stark 的本教程

希望这有助于澄清至少部分内容。

于 2012-07-23T00:13:19.840 回答