Другое

notificationclick не работает в Flutter Web debug?

Узнайте, почему событие notificationclick не срабатывает в debug‑сборках Flutter Web из‑за ограничений Chrome на localhost и различий в работе Service Worker.

Почему событие notificationclick не вызывается в отладочной сборке Flutter Web приложения?

Я пытаюсь открыть новую страницу при клике по уведомлению в моём Flutter Web приложении. Уведомление отображается корректно, но обратный вызов не срабатывает в отладочных сборках. В релизных сборках всё работает нормально.

Код Service Worker

javascript
console.log("SW: test.js loaded");

self.addEventListener("push", event => {
  console.log("SW: Push event received:", event);

  let data = {};
  try {
    data = event.data ? event.data.json() : {};
  } catch (err) {
    console.warn("SW: Push data not JSON, using empty object");
  }

  const title = data.title || "Test Push Title";
  const options = {
    body: data.body || "This notification came from the push event.",
    icon: "/icons/icon-192.png",
    tag: "push-demo",
    data: {
      url: "/"
    }
  };

  console.log("SW: Showing notification:", title, options);

  event.waitUntil(
    self.registration.showNotification(title, options)
  );
});

self.addEventListener("notificationclick", event => {
  console.log("SW: Notification clicked event:", event);

  event.notification.close();

  const url = event.notification.data.url || "/";

  event.waitUntil(
    clients.openWindow(url)
  );
});

Регистрация Service Worker

html
<script>
    if ('serviceWorker' in navigator) {
      window.addEventListener('load', function () {
        navigator.serviceWorker.register('test.js').then(reg => {
          console.log("SW registered:", reg);
        }).catch(err => {
          console.error("SW failed:", err);
        });
      });
    }
</script>

Описание проблемы

При запуске приложения на localhost уведомление отображается, но обратный вызов при клике не срабатывает. Вот вывод консоли в отладочной сборке:

SW: test.js loaded
test.js:4 SW: Push event received: PushEvent {isTrusted: true, data: PushMessageData, type: 'push', target: ServiceWorkerGlobalScope, currentTarget: ServiceWorkerGlobalScope, …}
test.js:10 SW: Push data not JSON, using empty object
(anonymous) @ test.js:10
test.js:23 SW: Showing notification: Test Push Title {body: 'This notification came from the push event.', icon: '/icons/icon-192.png', tag: 'push-demo', data: {…}}

В релизной сборке всё работает корректно. Как можно протестировать событие notificationclick в отладочной сборке?

Содержание

Основная проблема: ограничение localhost в Chrome

Основная причина, по которой событие notificationclick не срабатывает в сборках отладки, заключается в том, что Google Chrome не поддерживает взаимодействие с уведомлениями на localhost. Это целенаправленное ограничение безопасности в реализации Push API и Service Workers в Chrome.

Согласно обсуждениям на StackOverflow по этой же проблеме, Chrome блокирует событие notificationclick, когда приложение работает на localhost или 127.0.0.1 источник. Это объясняет, почему уведомление отображается корректно (события push работают), но обратный вызов клика никогда не срабатывает.

Важно: Это ограничение касается только браузеров на основе Chrome. Другие браузеры, такие как Firefox или Edge, могут обрабатывать клики по уведомлениям по-разному на localhost, но поведение Chrome является стандартом, с которым сталкиваются большинство разработчиков.

Вывод консоли подтверждает эту схему – сервис-воркер загружается, получает событие push и отображает уведомление, но обработчик события клика никогда не срабатывает.

Различия в компиляции сервис-воркера Flutter Web

Flutter web приложения обрабатывают сервис-воркеры по-разному в режиме отладки и релиза, что вносит свой вклад в эту проблему. В режиме отладки Flutter использует другую стратегию компиляции, которая может влиять на поведение сервис-воркера.

Как отмечено в документации пакета service_worker, необходимо принудительно компилировать сервис-воркер с помощью dart2js в режиме отладки источник. По умолчанию компиляция в режиме отладки может не корректно обрабатывать события сервис-воркера, такие как notificationclick.

При сборке релиза Flutter оптимизирует и полностью компилирует сервис-воркер, поэтому он работает корректно в этом окружении. В режиме отладки часто используются карты исходников и инкрементальная компиляция, которые могут мешать обработке событий сервис-воркера.


Регистрация сервис-воркера в режиме отладки

Способ, которым вы регистрируете сервис-воркер в режиме отладки, также может влиять на обработку уведомлений. Загрузчик Flutter для веба имеет собственную систему управления сервис-воркерами, отличающуюся от ручной регистрации.

В вашем текущем подходе вы вручную регистрируете сервис-воркер. Однако загрузчик Flutter для веба имеет собственную систему управления сервис-воркерами. Рассмотрите возможность интеграции с системой управления сервис-воркерами Flutter:

html
<script>
  window.addEventListener('load', function(ev) {
    // Рекомендованная регистрация сервис-воркера Flutter
    _flutter.loader.loadEntrypoint({
      entrypointUrl: "/main.dart.js",
      serviceWorker: {
        serviceWorkerVersion: serviceWorkerVersion,
        serviceWorkerUrl: "/flutter_service_worker.js"
      }
    }).then(function(engineInitializer) {
      return engineInitializer.initializeEngine();
    }).then(function(appRunner) {
      return appRunner.runApp();
    });
  });
</script>

Этот подход гарантирует, что ваш сервис-воркер корректно управляется инфраструктурой Flutter для веба, что может решить проблемы с таймингом и регистрацией, влияющие на события уведомлений.


Решения для тестирования во время разработки

Поскольку Chrome блокирует клики по уведомлениям на localhost, вот несколько эффективных подходов для тестирования функциональности уведомлений во время разработки:

1. Используйте HTTPS-домен вместо localhost

Настройте локальный HTTPS-сервер для тестирования взаимодействия с уведомлениями. Инструменты вроде mkcert позволяют создать локальные сертификаты для разработки:

bash
# Установить mkcert
npm install -g mkcert

# Создать локальный CA и сертификат
mkcert -install
mkcert localhost 127.0.0.1 ::1

# Запустить приложение с HTTPS
npx serve -s build -l 4430 -c https.json

2. Флаги командной строки Chrome

Вы можете обойти ограничения localhost в Chrome, используя флаги командной строки:

bash
# Запустить Chrome с флагом для небезопасных источников
chrome --unsafely-treat-insecure-origin-as-secure=http://localhost:3000

3. Используйте ngrok для тестирования

Создайте защищённый туннель к вашему локальному серверу разработки:

bash
# Установить ngrok
npm install -g ngrok

# Создать HTTPS-туннель
ngrok http 3000

Затем протестируйте приложение, используя HTTPS‑URL от ngrok.


Альтернативные подходы

Если вам нужно часто разрабатывать и тестировать функциональность уведомлений, рассмотрите следующие альтернативные подходы:

Пользовательский сервис-воркер с интеграцией Flutter

Вместо отдельного файла сервис-воркера интегрируйте обработку уведомлений в сгенерированный сервис-воркер Flutter. Это потребует модификации процесса генерации сервис-воркера Flutter или использования пользовательского процесса сборки.

Мок‑тестирование во время разработки

Создайте мок‑систему уведомлений для разработки, которая имитирует поведение клика по уведомлению:

javascript
// Мок‑клик уведомления для разработки на localhost
if (window.location.hostname === 'localhost') {
  // Симулировать клик по уведомлению через 2 секунды
  setTimeout(() => {
    console.log('Мок‑клик уведомления сработал');
    // Вызвать вашу логику обработчика клика здесь
  }, 2000);
}

Используйте выделенную тестовую среду

Настройте выделенную тестовую среду на реальном HTTPS‑домене (например, развертывание на Vercel или Netlify), где взаимодействие с уведомлениями работает корректно, и используйте её для тестирования вашего потока уведомлений.


Пошаговый процесс отладки

Ниже приведён систематический подход к отладке и решению проблемы с кликом по уведомлению:

  1. Проверьте регистрацию сервис-воркера

    javascript
    // Проверить, активен ли сервис-воркер
    navigator.serviceWorker.ready.then(registration => {
      console.log('Сервис-воркер активен:', registration);
    });
    
  2. Проверьте в разных браузерах

    • Попробуйте Firefox или Edge на localhost, чтобы увидеть, поддерживают ли они клики по уведомлениям
    • Поведение Chrome не является представительным для всех браузеров
  3. Проверьте консоль сервис-воркера

    • Откройте Chrome DevTools > Application > Service Workers
    • Убедитесь, что ваш сервис-воркер активен и не выбрасывает ошибок
  4. Проверьте разрешения уведомлений

    javascript
    // Проверить статус разрешения уведомлений
    console.log('Разрешение уведомлений:', Notification.permission);
    
  5. Тестируйте с упрощённым обработчиком

    javascript
    self.addEventListener('notificationclick', event => {
      console.log('Клик по уведомлению - упрощённый тест');
      event.notification.close();
      event.waitUntil(clients.openWindow('/'));
    });
    
  6. Принудительная компиляция Dart2JS

    bash
    flutter build web --web-renderer canvaskit --dart-define=FLUTTER_WEB_CANVASKIT_URL=/canvaskit/
    

Заключение

Событие notificationclick не работает в сборках Flutter Web в режиме отладки, в основном из‑за ограничений безопасности localhost в Chrome и различий в компиляции сервис-воркера между режимами отладки и релиза. Чтобы эффективно тестировать функциональность уведомлений:

  1. Используйте HTTPS‑домены вместо localhost для корректного тестирования взаимодействия с уведомлениями.
  2. Используйте флаги командной строки Chrome или инструменты вроде ngrok для разработки на localhost.
  3. Рассмотрите интеграцию сервис-воркера Flutter для лучшей совместимости.
  4. Создайте мок‑системы тестирования для сред разработки, где применяются ограничения localhost.
  5. Пошагово отлаживайте, следуя предложенному процессу.

Помните, что то, что работает в релизных сборках (оптимизированная компиляция, корректная работа сервис-воркера), не всегда напрямую переносится в сборки отладки из‑за оптимизаций разработки Flutter и политик безопасности браузера.

Источники

  1. StackOverflow - событие notificationclick не вызывается в сборке Flutter web app debug build (https://stackoverflow.com/questions/79827261/javascript-notificationclick-is-not-called-on-flutter-web-app-debug-build)
  2. StackOverflow - ограничение notificationclick на localhost в Chrome (https://stackoverflow.com/questions/75126791/how-to-do-something-when-user-clicks-on-notification-on-flutter-web-using-fireba)
  3. Документация пакета Service Worker - требования к компиляции Dart (https://pub.dev/packages/service_worker)
  4. FAQ Flutter Web - ограничения сервис-воркера (https://docs.flutter.dev/platform-integration/web/faq)
  5. GitHub Flutter - проблемы генерации сервис-воркера (https://github.com/flutter/flutter/issues/145492)
Авторы
Проверено модерацией
Модерация