如果选项卡关闭,添加到主屏幕提示不会再次出现
Add to home screen prompt doesn't show up again if tab is closed
我已将服务-worker.js 和清单添加到我的网站,并使用 lighthouse 测试了页面,这表明我的网页已准备好向用户显示 "Add to home screen"。
但是,如果用户关闭选项卡而不先关闭提示,则提示不会出现两次 time.Is 还有其他方法可以实现此目的吗?。
这是我的清单
{
"short_name": "TestApp",
"name": "Long Name",
"icons": [
{
"src":"images/favicon-192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src":"images/favicon-256.png",
"sizes": "256x256",
"type": "image/png"
},
{
"src":"images/favicon-384.png",
"sizes": "384x384",
"type": "image/png"
},
{
"src":"images/favicon-512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"start_url": "/",
"background_color": "#fff",
"theme_color": "#d2d2d2",
"display": "standalone"
}
这是我的 service worker javascript 文件
/*
Copyright 2015 Google Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
'use strict';
// Incrementing CACHE_VERSION will kick off the install event and force previously cached
// resources to be cached again.
const CACHE_VERSION = 3;
let CURRENT_CACHES = {
offline: 'offline-v' + CACHE_VERSION
};
const OFFLINE_URL = 'offline.html';
function createCacheBustedRequest(url) {
let request = new Request(url, {cache: 'reload'});
// See https://fetch.spec.whatwg.org/#concept-request-mode
// This is not yet supported in Chrome as of M48, so we need to explicitly check to see
// if the cache: 'reload' option had any effect.
if ('cache' in request) {
return request;
}
// If {cache: 'reload'} didn't have any effect, append a cache-busting URL parameter instead.
let bustedUrl = new URL(url, self.location.href);
bustedUrl.search += (bustedUrl.search ? '&' : '') + 'cachebust=' + Date.now();
return new Request(bustedUrl);
}
self.addEventListener('install', event => {
event.waitUntil(
// We can't use cache.add() here, since we want OFFLINE_URL to be the cache key, but
// the actual URL we end up requesting might include a cache-busting parameter.
fetch(createCacheBustedRequest(OFFLINE_URL)).then(function(response) {
return caches.open(CURRENT_CACHES.offline).then(function(cache) {
return cache.put(OFFLINE_URL, response);
});
})
);
});
self.addEventListener('activate', event => {
// Delete all caches that aren't named in CURRENT_CACHES.
// While there is only one cache in this example, the same logic will handle the case where
// there are multiple versioned caches.
let expectedCacheNames = Object.keys(CURRENT_CACHES).map(function(key) {
return CURRENT_CACHES[key];
});
event.waitUntil(
caches.keys().then(cacheNames => {
return Promise.all(
cacheNames.map(cacheName => {
if (expectedCacheNames.indexOf(cacheName) === -1) {
// If this cache name isn't present in the array of "expected" cache names,
// then delete it.
console.log('Deleting out of date cache:', cacheName);
return caches.delete(cacheName);
}
})
);
})
);
});
self.addEventListener('fetch', event => {
// We only want to call event.respondWith() if this is a navigation request
// for an HTML page.
// request.mode of 'navigate' is unfortunately not supported in Chrome
// versions older than 49, so we need to include a less precise fallback,
// which checks for a GET request with an Accept: text/html header.
if (event.request.mode === 'navigate' ||
(event.request.method === 'GET' &&
event.request.headers.get('accept').includes('text/html'))) {
console.log('Handling fetch event for', event.request.url);
event.respondWith(
fetch(event.request).catch(error => {
// The catch is only triggered if fetch() throws an exception, which will most likely
// happen due to the server being unreachable.
// If fetch() returns a valid HTTP response with an response code in the 4xx or 5xx
// range, the catch() will NOT be called. If you need custom handling for 4xx or 5xx
// errors, see https://github.com/GoogleChrome/samples/tree/gh-pages/service-worker/fallback-response
console.log('Fetch failed; returning offline page instead.', error);
return caches.match(OFFLINE_URL);
})
);
}
// If our if() condition is false, then this fetch handler won't intercept the request.
// If there are any other fetch handlers registered, they will get a chance to call
// event.respondWith(). If no fetch handlers call event.respondWith(), the request will be
// handled by the browser as if there were no service worker involvement.
});
这个我可能是错的,但如果你的用户没有点击接受按钮,我认为这被认为是被驳回了。
您的用户唯一能够再次看到的情况是他们清除了该特定站点的缓存和浏览器设置。
Google 还记录了:
您可以创建更好的用户体验,例如询问用户是否要安装应用程序或通过在某处显示安装应用程序图标然后要求浏览器显示横幅。
现在(2018 年 4 月)Google updated PWA documentations,这表明开发人员可以决定何时提示 "Add to Home Screen",他们提供了示例代码。
相同的用户体验提示 described here 请求用户通知权限。
这是他们提供的示例代码:
var deferredPrompt;
window.addEventListener('beforeinstallprompt', function(e) {
console.log('beforeinstallprompt Event fired');
e.preventDefault();
// Stash the event so it can be triggered later.
deferredPrompt = e;
return false;
});
btnSave.addEventListener('click', function() {
if(deferredPrompt !== undefined) {
// The user has had a positive interaction with our app and Chrome
// has tried to prompt previously, so let's show the prompt.
deferredPrompt.prompt();
// Follow what the user has done with the prompt.
deferredPrompt.userChoice.then(function(choiceResult) {
console.log(choiceResult.outcome);
if(choiceResult.outcome == 'dismissed') {
console.log('User cancelled home screen install');
}
else {
console.log('User added to home screen');
}
// We no longer need the prompt. Clear it up.
deferredPrompt = null;
});
}
});
我已将服务-worker.js 和清单添加到我的网站,并使用 lighthouse 测试了页面,这表明我的网页已准备好向用户显示 "Add to home screen"。 但是,如果用户关闭选项卡而不先关闭提示,则提示不会出现两次 time.Is 还有其他方法可以实现此目的吗?。 这是我的清单
{
"short_name": "TestApp",
"name": "Long Name",
"icons": [
{
"src":"images/favicon-192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src":"images/favicon-256.png",
"sizes": "256x256",
"type": "image/png"
},
{
"src":"images/favicon-384.png",
"sizes": "384x384",
"type": "image/png"
},
{
"src":"images/favicon-512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"start_url": "/",
"background_color": "#fff",
"theme_color": "#d2d2d2",
"display": "standalone"
}
这是我的 service worker javascript 文件
/*
Copyright 2015 Google Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
'use strict';
// Incrementing CACHE_VERSION will kick off the install event and force previously cached
// resources to be cached again.
const CACHE_VERSION = 3;
let CURRENT_CACHES = {
offline: 'offline-v' + CACHE_VERSION
};
const OFFLINE_URL = 'offline.html';
function createCacheBustedRequest(url) {
let request = new Request(url, {cache: 'reload'});
// See https://fetch.spec.whatwg.org/#concept-request-mode
// This is not yet supported in Chrome as of M48, so we need to explicitly check to see
// if the cache: 'reload' option had any effect.
if ('cache' in request) {
return request;
}
// If {cache: 'reload'} didn't have any effect, append a cache-busting URL parameter instead.
let bustedUrl = new URL(url, self.location.href);
bustedUrl.search += (bustedUrl.search ? '&' : '') + 'cachebust=' + Date.now();
return new Request(bustedUrl);
}
self.addEventListener('install', event => {
event.waitUntil(
// We can't use cache.add() here, since we want OFFLINE_URL to be the cache key, but
// the actual URL we end up requesting might include a cache-busting parameter.
fetch(createCacheBustedRequest(OFFLINE_URL)).then(function(response) {
return caches.open(CURRENT_CACHES.offline).then(function(cache) {
return cache.put(OFFLINE_URL, response);
});
})
);
});
self.addEventListener('activate', event => {
// Delete all caches that aren't named in CURRENT_CACHES.
// While there is only one cache in this example, the same logic will handle the case where
// there are multiple versioned caches.
let expectedCacheNames = Object.keys(CURRENT_CACHES).map(function(key) {
return CURRENT_CACHES[key];
});
event.waitUntil(
caches.keys().then(cacheNames => {
return Promise.all(
cacheNames.map(cacheName => {
if (expectedCacheNames.indexOf(cacheName) === -1) {
// If this cache name isn't present in the array of "expected" cache names,
// then delete it.
console.log('Deleting out of date cache:', cacheName);
return caches.delete(cacheName);
}
})
);
})
);
});
self.addEventListener('fetch', event => {
// We only want to call event.respondWith() if this is a navigation request
// for an HTML page.
// request.mode of 'navigate' is unfortunately not supported in Chrome
// versions older than 49, so we need to include a less precise fallback,
// which checks for a GET request with an Accept: text/html header.
if (event.request.mode === 'navigate' ||
(event.request.method === 'GET' &&
event.request.headers.get('accept').includes('text/html'))) {
console.log('Handling fetch event for', event.request.url);
event.respondWith(
fetch(event.request).catch(error => {
// The catch is only triggered if fetch() throws an exception, which will most likely
// happen due to the server being unreachable.
// If fetch() returns a valid HTTP response with an response code in the 4xx or 5xx
// range, the catch() will NOT be called. If you need custom handling for 4xx or 5xx
// errors, see https://github.com/GoogleChrome/samples/tree/gh-pages/service-worker/fallback-response
console.log('Fetch failed; returning offline page instead.', error);
return caches.match(OFFLINE_URL);
})
);
}
// If our if() condition is false, then this fetch handler won't intercept the request.
// If there are any other fetch handlers registered, they will get a chance to call
// event.respondWith(). If no fetch handlers call event.respondWith(), the request will be
// handled by the browser as if there were no service worker involvement.
});
这个我可能是错的,但如果你的用户没有点击接受按钮,我认为这被认为是被驳回了。
您的用户唯一能够再次看到的情况是他们清除了该特定站点的缓存和浏览器设置。
Google 还记录了:
您可以创建更好的用户体验,例如询问用户是否要安装应用程序或通过在某处显示安装应用程序图标然后要求浏览器显示横幅。
现在(2018 年 4 月)Google updated PWA documentations,这表明开发人员可以决定何时提示 "Add to Home Screen",他们提供了示例代码。
相同的用户体验提示 described here 请求用户通知权限。
这是他们提供的示例代码:
var deferredPrompt;
window.addEventListener('beforeinstallprompt', function(e) {
console.log('beforeinstallprompt Event fired');
e.preventDefault();
// Stash the event so it can be triggered later.
deferredPrompt = e;
return false;
});
btnSave.addEventListener('click', function() {
if(deferredPrompt !== undefined) {
// The user has had a positive interaction with our app and Chrome
// has tried to prompt previously, so let's show the prompt.
deferredPrompt.prompt();
// Follow what the user has done with the prompt.
deferredPrompt.userChoice.then(function(choiceResult) {
console.log(choiceResult.outcome);
if(choiceResult.outcome == 'dismissed') {
console.log('User cancelled home screen install');
}
else {
console.log('User added to home screen');
}
// We no longer need the prompt. Clear it up.
deferredPrompt = null;
});
}
});