如何知道渐进式Web应用程序处于前台还是后台

pil*_*lau 3 progressive-web-apps

有没有办法知道渐进式Web应用程序是在后台还是在前台(即,它当前是该应用程序的焦点,还是“已最小化”)

在过去的两天中,对Google和SO进行搜索仅带来了有关如何在后台运行服务工作者的信息。谢谢!

abr*_*ham 5

从客户端,您可以使用Page Visibility API查询当前可见性,并在可见性更改时获取事件。

const state = document.visibilityState;

document.addEventListener('visibilitychange', () => {
  console.log(document.visibilityState);
});
Run Code Online (Sandbox Code Playgroud)

您还可以从Service Workers中使用WindowClient查询客户端的可见性状态。

event.waitUntil(
  clients.matchAll({ type: 'window' })
    .then(function(clientList) {
      for (var i = 0; i < clientList.length; i++) {
        const state = clientList[i].visibilityState;
      }
    })
);
Run Code Online (Sandbox Code Playgroud)


小智 5

我已经搜索了很多天,很多与上面相同的答案。虽然可见性 api 确实在一定程度上起作用,但它并不总是起作用。我想我会在这里发布我们的解决方案,用我们发现的最可靠的方法来补充上面的答案,该方法适用于大多数浏览器。

对我们来说,问题更在于移动设备。我们有一个可安装的 PWA,但问题也存在于移动浏览器中。一旦安装的 PWA(或在移动浏览器中打开的选项卡)被推送到后台,可见性 API 本身就不够用。我们的应用程序依赖于通过 graphql 订阅的实时数据更新,当应用程序/浏览器进入后台时,它不再获取这些数据。例如,如果用户在收到指示他们有新消息的推送通知后打开应用程序,则新消息不在应用程序中,因为它实际上处于睡眠状态并且 websockets 已关闭。我们不想每次用户在我们的应用程序和他们设备上的其他应用程序之间移动时都必须进行完全刷新,因此使用服务工作者中的低级别检查并重新加载页面,不会提供很好的体验并导致大量不必要的加载。我们需要在我们的 React 组件内部可靠地知道应用程序何时回到前台,以便我们可以从它进入后台时强制获取相关的缺失数据。

我们最终从关于页面生命周期的谷歌文档中调整了这一点。有人确实为它创建了一个小的 js 库,但我们无法让它工作。所以我们只是修改了示例代码,它运行得很好。

https://developers.google.com/web/updates/2018/07/page-lifecycle-api

下面的代码可以很容易地集成到反应组件中,并通过 useState 和 useEffect 钩子进行管理。

import MobileDetect from 'mobile-detect';
const md = new MobileDetect(window.navigator.userAgent);
const isMobile = md.mobile();

let standalone
if (navigator.standalone) {
  standalone = 'standalone-ios';
}
if (window.matchMedia('(display-mode: standalone)').matches) {
  standalone = 'standalone';
}

const getState = () => {
  if (document.visibilityState === 'hidden') {
    return 'hidden';
  }
  if (document.hasFocus()) {
    return 'active';
  }
  return 'passive';
};

let displayState = getState();

const onDisplayStateChange = () => {
  const nextState = getState();
  const prevState = displayState;

  if (nextState !== prevState) {
    console.log(`State changed: ${prevState} >>> ${nextState}`);
    displayState = nextState;

    //standalone will restrict to only running for an installed PWA on mobile
    if (nextState === 'active' && isMobile /* && standalone */) {  
      //The app/browser tab has just been made active and is visible to the user
      //do whatever you want in here to update dynamic content, call api etc
    }
  }
};

//subscribe to all of the events related to visibility
['pageshow', 'focus', 'blur', 'visibilitychange', 'resume'].forEach((type) => {
  window.addEventListener(type, onDisplayStateChange, {capture: true});
});
Run Code Online (Sandbox Code Playgroud)