4

我已经为网站构建了一个服务,可以轻松地将推送通知集成到他们的网站中,但当前的 Chrome 实现还要求他们设置清单和服务工作者。

有没有办法只用一行 Javascript 设置服务工作者和清单?

4

1 回答 1

7

是的,您可以减少让他们在其来源上托管服务工作者文件的步骤,并在他们的页面中包含一行 Javascript。

您可以使用它们包含的 Javascript 来做到这一点:

  1. 注册一个服务工作者
  2. 将指向不存在的清单的链接注入头部
  3. 使用您的服务人员拦截对该清单的请求,并使用您的自定义清单进行响应

您的 Javascript 应如下所示:

navigator.serviceWorker.register('sw.js').then(function(registration) {
    console.log('ServiceWorker registration successful with scope: ', registration.scope);
    var head = document.head;
    var noManifest = true;
    // Walk through the head to check if a manifest already exists
    for (var i = 0; i < head.childNodes.length; i++) {
        if (head.childNodes[i].rel === 'manifest') {
            noManifest = false;
            break;
        }
    }
    // If there is no manifest already, add one.
    if (noManifest) {
        var manifest = document.createElement('link');
        manifest.rel = 'manifest';
        manifest.href = 'manifest.json';
        document.head.appendChild(manifest);
    }
});

请注意,如果清单标签已经存在,我是如何避免添加清单标签的。

您的服务人员应该类似于:

self.addEventListener('fetch', function(e) {
    if (e.request.context === 'manifest') {
        e.respondWith(new Promise(function(resolve, reject) {
            fetch(e.request).then(function(response) {
                if (response.ok) {
                    // We found a real manifest, so we should just add our custom field
                    response.json().then(function(json) {
                        json.custom_field = 'Hello world';
                        var blob = new Blob([JSON.stringify(json)], { type: 'application/json' });
                        console.log('Appended a custom field to the pre-existing manifest');
                        resolve(new Response(blob));
                    });
                } else {
                    // There was no manifest so return ours
                    console.log('Injected a custom manifest');
                    resolve(new Response('{ "custom_field": "Hello world" }'));
                }
            });
        }));
    }
});

// These pieces cause the service worker to claim the client immediately when it is registered instead of waiting until the next load. This means this approach can work immediately when the user lands on your site.
if (typeof self.skipWaiting === 'function') {
    console.log('self.skipWaiting() is supported.');
    self.addEventListener('install', function(e) {
        // See https://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html#service-worker-global-scope-skipwaiting
        e.waitUntil(self.skipWaiting());
    });
} else {
    console.log('self.skipWaiting() is not supported.');
}

if (self.clients && (typeof self.clients.claim === 'function')) {
    console.log('self.clients.claim() is supported.');
    self.addEventListener('activate', function(e) {
        // See https://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html#clients-claim-method
        e.waitUntil(self.clients.claim());
    });
} else {
    console.log('self.clients.claim() is not supported.');
}

请注意它如何只拦截对清单的请求,并检查是否确实存在。如果是这样,服务工作者只需将我们的自定义字段附加到它。如果清单尚不存在,我们将自定义字段作为整个清单返回。

更新(2015 年 8 月 25 日):我刚刚读到Request.context 已被弃用,所以不幸的是,您需要找到一种新方法来发现请求是针对清单还是其他东西来代替 line if (e.request.context === 'manifest')

于 2015-07-07T21:53:33.817 回答