如何使用单个Javascript标记安装服务工作者和清单?

owe*_*ncm 4 javascript google-chrome service-worker web-push push-api

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

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

owe*_*ncm 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);
    }
});
Run Code Online (Sandbox Code Playgroud)

请注意我已经避免添加清单标记(如果已存在).

您的服务人员应该看起来像:

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.');
}
Run Code Online (Sandbox Code Playgroud)

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

更新(2015年8月25日):我刚刚读到Request.context已被弃用,所以遗憾的是,您需要找到一种新方法来发现请求是用于清单还是代替该行的其他内容if (e.request.context === 'manifest').