clients.openWindow () Не разрешено открывать окно. на serviceWorker Google Chrome

Я тестирую Chrome версии 42.0.2311.152m и хочу реализовать открытие окна при нажатии на уведомление, как в этом примере: (источник: https://developer.mozilla.org/en-US/docs/Web/API/WindowClient)

self.addEventListener('notificationclick', function(event) {
  console.log('On notification click: ', event.notification.tag);
  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('/');
  }));
});

Моя файловая структура выглядит так:
https://myurl.no-ip.org/app/index.html
https://myurl.no-ip.org/app/manifest.json
https://myurl.no-ip.org/app/service-worker.js

У меня проблема в том, что я всегда получаю

InvalidAccessError

при вызове client.openWindow ('/') или clients.openWindow ('https://myurl.no-ip.org/app/index.html ') в service-worker.js, я получаю сообщение об ошибке:

{code: 15,
message: "Not allowed to open a window.",
name: "InvalidAccessError"}

Строка «return client.focus ()» никогда не достигается, потому что client.url никогда не бывает просто «/». Смотря на

clients.matchAll({type: "window"})
.then(function (clientList) {
console.log(clientList[0])});

Я вижу свой текущий WindowClient:

{focused: false,
frameType: "top-level",
url: "https://myurl.no-ip.org/app/index.html",
visibilityState: "hidden" }

Свойства "focus" и "visibilityState" верны и изменяются правильно.
Выполняя вызов фокуса вручную

clients.matchAll({type: "window"})
    .then(function (clientList) {
    clientList[0].focus()});

Я получаю сообщение об ошибке:

{code: 15,
message: "Not allowed to focus a window.",
name: "InvalidAccessError"}

Я думаю, проблема в том, что url - это не просто '/'. У вас есть идеи на этот счет?

Большое спасибо!
С уважением,
Andi


person user24502    schedule 18.05.2015    source источник
comment
Я раньше не видел этой конкретной ошибки и сам не могу ее воспроизвести. Chrome 43 скоро станет стабильным выпуском (и уже есть на некоторых платформах). Можете ли вы воспроизвести это там или в Chrome dev / Canary?   -  person Jeff Posnick    schedule 20.05.2015
comment
У нас есть аналогичный код, который, похоже, работает в Chrome на Mac, но не в Chrome в Windows. С какой ОС вы тестировали?   -  person Joel Duckworth    schedule 24.10.2016


Ответы (1)


Ваш код мне подходит, поэтому я объясню требования для использования openWindow / focus и как можно избежать сообщения об ошибке «Не разрешено [открыть | фокус] окно».

clients.openWindow() и windowClient.focus() разрешены только после нажатия на уведомление (по крайней мере, в Chrome 47), и может быть вызвано не более одного из этих методов на время действия обработчика кликов. Это поведение было указано в https://github.com/slightlyoff/ServiceWorker/issues/602.

Если ваш openWindow / focus вызов отклонен с сообщением об ошибке

«Не разрешено открывать окно». для openWindow
"Не разрешено фокусировать окно." для focus

значит, вы не соответствуете требованиям openWindow / focus. Например (все пункты также относятся к focus, а не только к openWindow).

  • openWindow был вызван, хотя уведомление не было нажато.
  • openWindow был вызван после возврата обработчика notificationclick, а вы не вызывали event.waitUntil с обещанием.
  • openWindow был вызван после выполнения обещания, переданного event.waitUntil.
  • Обещание не было выполнено, но потребовалось слишком много времени (10 секунд в Chrome), поэтому временное разрешение на вызов openWindow истекло.

Действительно необходимо, чтобы openWindow / focus вызывался не более одного раза, но до завершения обработчика notificationclick.

Как я уже сказал, код в вопросе работает, поэтому я покажу еще один аннотированный пример.

// serviceworker.js
self.addEventListener('notificationclick', function(event) {
    // Close notification.
    event.notification.close();

    // Example: Open window after 3 seconds.
    // (doing so is a terrible user experience by the way, because
    //  the user is left wondering what happens for 3 seconds.)
    var promise = new Promise(function(resolve) {
        setTimeout(resolve, 3000);
    }).then(function() {
        // return the promise returned by openWindow, just in case.
        // Opening any origin only works in Chrome 43+.
        return clients.openWindow('https://example.com');
    });

    // Now wait for the promise to keep the permission alive.
    event.waitUntil(promise);
});

index.html

<button id="show-notification-btn">Show notification</button>
<script>
navigator.serviceWorker.register('serviceworker.js');
document.getElementById('show-notification-btn').onclick = function() {
    Notification.requestPermission(function(result) {
        // result = 'allowed' / 'denied' / 'default'
        if (result !== 'denied') {
            navigator.serviceWorker.ready.then(function(registration) {
                // Show notification. If the user clicks on this
                // notification, then "notificationclick" is fired.
                registration.showNotification('Test');
            });
        }
    });
}
</script>

PS. Сервисные работники все еще находятся в разработке, поэтому стоит упомянуть, что я проверил, что приведенные выше замечания верны в Chrome 49 и что пример работает в Chrome 43+ (и открытие / вместо https://example.com также работает в Chrome 42).

person Rob W    schedule 13.12.2015
comment
Какова цель тайм-аута? Не могли бы вы сразу открыть окно? - person capouch; 20.05.2017
comment
@capouch Для демонстрации асинхронного поведения. - person Rob W; 20.05.2017
comment
Да, тайм-аут усложняет ситуацию, но это также хороший способ показать, что еще мы можем сделать. Если вы хотите сразу же открыть окно, выполните event.waitUntil(clients.openWindow('page.html')); @RobW, как узнать, когда нам нужно использовать waitUntil? - person jakubiszon; 18.06.2018
comment
Каково решение? Вы написали код вопроса правильный, но он не работает! Так как это может быть правильно? Кроме того, ваше решение не предлагает никакого решения! - person Federico Schiocchet; 03.02.2021
comment
Очевидно, что код вашего примера не работает - person Federico Schiocchet; 03.02.2021