如何通过单击推送通知启动 PWA(渐进式 Web 应用程序)打开?

How can I initiate a PWA (progressive webapp) open from a click on a push notification?

Following this example,我知道 PWA 如何打开 url,但我如何使用推送通知启动应用程序本身?不是浏览器而是全屏版PWA。

摘自 Jake Archibald 的 emojoy 演示:

self.addEventListener('notificationclick', event => {
    const rootUrl = new URL('/', location).href;
    event.notification.close();
    // Enumerate windows, and call window.focus(), or open a new one.
    event.waitUntil(
      clients.matchAll().then(matchedClients => {
        for (let client of matchedClients) {
          if (client.url === rootUrl) {
            return client.focus();
          }
        }
        return clients.openWindow("/");
      })
    );
});

这由浏览器控制。 此外,在决定打开 window 时,可能值得检查所需的目标 URL 是否已经存在在不同的 tab/window 中打开,以便您可以根据情况聚焦或打开它。检查此 book here for some code samples.

例如在 Chrome 中,如果用户将一个 Web 应用程序添加到他们的主屏幕,并且在他们的清单中显示为“独立”,那么当用户单击该 Web 应用程序图标时,它将在没有 URL 的情况下打开酒吧.

当收到推送消息并打开同一个网络应用程序时,如果用户“最近”从主屏幕图标打开了网络应用程序(目前在最后一个10天)。如果用户在该时间段内未使用主页图标,将打开通知点击并显示 URL 栏。

参见for more info on this Chrome issue here

具体来说:

The web app must be added to home screen, capable of opening in standalone mode, and have been opened from the home screen within the last ten days. If any of these conditions are not met, the notification will fall back to the existing behaviour.

同样值得注意的是,PWA 与浏览器本身并不是正确的思考方式。您总是在浏览器中启动,只是在不同的模式下,例如“独立”与“浏览器”。

PWA(渐进式 Web 应用程序)在很大程度上是一个术语,用于描述使用一组 API 来通过新的网络技术(即服务工作者、推送、网络应用程序清单)创造良好的用户体验等)。

截至 Oct/2018:

我使用 Chrome 69.

让它工作

在这个例子中,它是一个子应用程序 (www.example.com/application).

In short: double check the paths!

此外,每当我从推送通知启动该应用程序时,我都会遇到未加载 cookie(登录信息)的问题,它可以正常打开,但未登录。如果您关闭它并点击之前在主屏幕上添加的应用程序图标,该应用已启动并已登录。

我使用以下方法完成了它(见评论):

1) serviceworker.js

self.addEventListener('notificationclick', function (event)
{
    //For root applications: just change "'./'" to "'/'"
    //Very important having the last forward slash on "new URL('./', location)..."
    const rootUrl = new URL('./', location).href; 
    event.notification.close();
    event.waitUntil(
        clients.matchAll().then(matchedClients =>
        {
            for (let client of matchedClients)
            {
                if (client.url.indexOf(rootUrl) >= 0)
                {
                    return client.focus();
                }
            }

            return clients.openWindow(rootUrl).then(function (client) { client.focus(); });
        })
    );
});

2) manifest.json

{
    "short_name": "AppNickName",
    "name": "ApplicationName",
    "icons": [
        {
            "src": "./icon.png",
            "sizes": "36x36",
            "type": "image/png",
            "density": 0.75
        }
    ],
    "start_url": "./",  //This matters
    "display": "standalone",  //This also matters
    "gcm_sender_id": "103953800507", //FCM always uses this number (April 2019)
    "background_color": "#c8c8c8",
    "theme_color": "#c8c8c8",
    "orientation": "any"
}

找到适合我的解决方案here

只需将此添加到您的服务工作者:

self.addEventListener('notificationclick', function(event) {
  console.log('On notification click: ', event.notification.tag);
  // Android doesn't close the notification when you click on it
  // See: http://crbug.com/463146
  event.notification.close();

  // This looks to see if the current is already open and
  // focuses if it is
  event.waitUntil(
    clients.matchAll({
      type: "window"
    })
    .then(function(clientList) {
      for (var i = 0; i < clientList.length; i++) {
        var client = clientList[i];
        if (client.url == '/' && 'focus' in client)
          return client.focus();
      }
      if (clients.openWindow) {
        return clients.openWindow('/');
      }
    })
  );
});