【问题标题】:Any way yet to auto-update (or just clear the cache on) a PWA on iOS?有什么方法可以在 iOS 上自动更新(或只是清除缓存)PWA?
【发布时间】:2018-09-07 11:38:46
【问题描述】:

我一直在努力在 iOS 上使用在 Android 上轻松运行的东西:让我的 PWA 在有新版本时自动更新。我完全不确定这在 iOS 上是否可行。我已经使用 vue.js 和 Quasar 来构建我的应用程序,并且一切都在 Android 上开箱即用。以下是 iOS 版本目前的(丑陋、可怕)方式:

  1. 我可以检查我自己的服务器的版本,并将其与存储在我的应用程序中的当前版本(在 indexedDB 中)进行比较,然后发出一个通知,指出有一个新版本。到目前为止一切顺利。
  2. 除了让用户手动清除 SAFARI 缓存 (!!) 之外,我无法弄清楚如何以编程方式从应用程序中清除 PWA 缓存或以其他方式强制上传。

所以在这一点上,我想我的问题是:

  1. 是否有人能够在 iOS(11.3 或更高版本)上获得 PWA 以在新版本可用时自动更新?
  2. 有没有办法从我的 PWA 中清除(Safari)应用缓存?

显然,通知用户为了更新他们必须在应用程序之外执行几个步骤才能刷新它,这是一种非常糟糕的用户体验,但似乎这就是 iOS 目前所处的位置,除非我是遗漏了什么。有没有人在任何地方完成这项工作?

【问题讨论】:

  • 我认为它应该在您打开应用程序时在后台更新。然后在您关闭应用程序后,下次打开它时,您应该会看到更改。这没有发生吗?
  • 是的,应该,但事实并非如此。而且我从任何地方的任何人那里都看到零证据表明这适用于 iOS。你有一个工作的例子吗? (顺便说一句,这是一个带有 Service Worker 的 PWA,所以它也应该是缓存的。)
  • 不,我没有当前的 iOS 设备。只是一个旧 iPod,抱歉。
  • iOS 14 的滑动应用移除状态,对于旧版本,手机应重新启动。

标签: ios vue.js progressive-web-apps quasar-framework


【解决方案1】:

经过数周又数周的搜索,我终于找到了解决方案:

  1. 我在服务器上添加了一个对版本字符串的检查,并将其返回给上面提到的应用程序。

  2. 我在 localtstorage (IndexedDB) 中查找它,如果找不到,我添加它。如果找到了,我会比较版本,如果服务器上有更新的版本,我会弹出一个对话框。

  3. 关闭此对话框(我的按钮标记为“更新”)运行window.location.reload(true),然后将新版本字符串存储在本地存储中

瞧!我的应用更新了!我不敢相信它归结为这么简单,我在任何地方都找不到解决方案。希望这对其他人有帮助!

2019 年 9 月更新:

上述技术存在一些问题,特别是它绕过了 PWA 服务工作者机制,并且有时重新加载不会立即加载新内容(因为当前的 SW 不会释放页面)。我现在有一个似乎适用于所有平台的新解决方案:

forceSWupdate () {
  if ('serviceWorker' in navigator) {
    navigator.serviceWorker.getRegistrations().then(function (registrations) {
      for (let registration of registrations) {
        registration.update()
      }
    })
  }
}

在我的 serviceworker 内部,如果有更新,我现在会弹出对话框,然后从那里执行我的location.reload(true)。这总是会导致我的应用程序立即刷新(重要的警告是,我已将 skipWaitingclientsClaim 指令添加到我的注册中)。

这在每个平台上都一样,我可以以编程方式检查更新或等待服务人员自行完成(尽管它检查的时间因平台、设备和其他未知因素而有很大差异。通常不会超过 24 小时。)

【讨论】:

  • 虽然不是真正的无声自动更新。如果您每天多次部署前端,我会看到用户已经厌倦了单击更新按钮。想法?
  • 是的,但在 Apple 解决此问题之前这是必要的解决方法,而且比什么都不做要好得多。
  • 您的应用能否就用户是否“处于中间状态”做出明智的决定?如果是这样,如果他们不做任何事情,它可以自动更新。如果他们正在做某事,它可能会等待(比如说)长达 24 小时,然后(如果他们还在做某事)会发出一条消息,要求他们更新。
  • 我认为这真的取决于应用程序。我实际上不能抛出更新通知,而是在发生特定保存后强制重新加载应用程序,但在这种情况下我选择了透明度(对于用户),因为它非常罕见。
  • 你是不是把你的forceSWupdate()放到版本检查方法里了?
【解决方案2】:

如果有人对此仍有疑问,registration.update() 对我不起作用。我使用了确切的解决方案,但是当我服务器上的版本与我的本地存储版本不匹配时,我必须取消注册服务人员才能使其工作。

  if ('serviceWorker' in navigator) {
   await this.setState({ loadingMessage: 'Updating Your Experience' })
   navigator.serviceWorker.getRegistrations().then(function(registrations) {
    registrations.map(r => {
      r.unregister()
    })
   })
   await AsyncStorage.setItem('appVersion', this.state.serverAppVersion)
   window.location.reload(true)
  } 

然后,当应用重新加载时,Service Worker 会重新注册,并且当前版本的应用在 iOS Safari 浏览器和“已添加书签”的 PWA 上可见。

【讨论】:

    【解决方案3】:

    除了提示用户有新版本可用之外,您还可以扩展“激活”事件侦听器,以便在发布新的 serviceworker 版本时删除旧缓存。

    1. 添加版本和名称变量
    var version = "v3" // increase for new version
    var staticCacheName = version + "_pwa-static";
    var dynamicCacheName = version + "_pwa-dynamic";
    
    1. 删除名称与当前版本不符的缓存:
    self.addEventListener('activate', function(event) {
        event.waitUntil(
            caches.keys().then(function(cacheNames) {
                return Promise.all(
                    cacheNames.filter(function(cacheName) {
                        if (!cacheName.startsWith(staticCacheName) &&
                            !cacheName.startsWith(dynamicCacheName)) {
                            return true;
                        }
                    }).map(function(cacheName) {
                        console.log('Removing old cache.', cacheName);
                        return caches.delete(cacheName);
                    })
                );
            })
        );
    });
    

    (学分:https://stackoverflow.com/a/45468998/14678591

    为了使这项功能也适用于 iOS Safari 浏览器和“书签”PWA,我刚刚添加了 @jbone107 略微简化的功能:

    self.addEventListener('activate', function(event) {
        event.waitUntil(
            caches.keys().then(function(cacheNames) {
                return Promise.all(
                    cacheNames.filter(function(cacheName) {
                        if (!cacheName.startsWith(staticCacheName) &&
                            !cacheName.startsWith(dynamicCacheName)) {
                            return true;
                        }
                    }).map(function(cacheName) {
                        // completely deregister for ios to get changes too
                        console.log('deregistering Serviceworker')
                        if ('serviceWorker' in navigator) {
                            navigator.serviceWorker.getRegistrations().then(function(registrations) {
                                registrations.map(r => {
                                    r.unregister()
                                })
                            })
                            window.location.reload(true)
                        }
    
                        console.log('Removing old cache.', cacheName);
                        return caches.delete(cacheName);
                    })
                );
            })
        );
    });
    

    这样你只需要增加版本号,更新由 serviceworker 自动完成。

    【讨论】:

      猜你喜欢
      • 2020-12-11
      • 1970-01-01
      • 1970-01-01
      • 2012-08-12
      • 1970-01-01
      • 2021-11-17
      • 1970-01-01
      • 2015-04-06
      • 1970-01-01
      相关资源
      最近更新 更多