Pu sh Уведомления не отображаются в Chrome - PullRequest
1 голос
/ 22 марта 2020

Настройка

  1. Операционная система : OS X
  2. Версия узла : 12
  3. web -pu sh Версия : 3.4.3

Пожалуйста, выберите любые браузеры, с которыми у вас возникли проблемы:

  1. [x] Chrome версия 80.0 .3987.132 (Официальная сборка) (64-разрядная версия)
  2. [] Firefox Developer Edition
  3. [x] Safari на iPhone 8 +
  4. [x] Другое

Проблема

Service Worker регистрируется, но уведомления pu sh не появляются в Chrome версии 80.0.3987.132 (Официальная сборка) (64-разрядная версия), но это работает в Firefox Developers Edition. Я могу видеть данные уведомления pu sh, зарегистрированные в моей консоли на Chrome, но уведомление браузера не отображается. На вкладке «Приложение» в Chrome я могу получить уведомление в разделе сообщений и уведомлений Pu sh.

Ожидается

Я ожидаю увидеть уведомление браузера в Chrome и другие браузеры (включая мобильные)

Клиент

Кнопка включения уведомлений вызывает функцию attemptToRegisterSW.

const attemptToRegisterSW = async dispatch => {
  if (
    !('serviceWorker' in navigator) ||
    !('PushManager' in window) ||
    !('Notification' in window)
  ) {
    dispatch(setNotificationMessage(`Sorry, your browser doesn't support push notifications`));
    return;
  }

  try {
    const components = await Fingerprint2.getPromise({
      excludes: { webdriver: true, cpuClass: true, fonts: true },
    });

    const fingerPrint = Fingerprint2.x64hash128(
      components.map(component => component.value).join(''),
      31,
    );

    const register = await navigator.serviceWorker.register('/service-worker.js', { scope: '/' });

    await navigator.serviceWorker.ready;

    const permissionResult = await askPermission();

    if (permissionResult === 'granted') {
      const subscription = await register.pushManager.subscribe({
        userVisibleOnly: true,
        applicationServerKey: urlBase64ToUint8Array(publicVapidKey),
      });

      const token = getItemFromLocalStorage(INNERYOU_JWT);

      if (fingerPrint) {
        const req = await fetch('/api/alerts/subscribe', {
          method: 'POST',
          headers: {
            'content-type': 'application/json',
            accept: 'application/json',
            authorization: `Bearer ${token}`,
          },
          body: JSON.stringify({ subscription, fingerPrint }),
        });

        if (req.status === 201) dispatch(setNotificationMessage(`Push notifications turned on`));
      }
    } else {
      dispatch(
        setNotificationMessage(
          `Push notifications are either blocked or denied, please adjust your browser settings`,
        ),
      );
    }
  } catch (error) {
    dispatch(
      setNotificationMessage(`Error while turning on push notifications, please try again.`),
    );
    console.error(`Error while registering serviceWorker ${error}`);
  }
};

Вспомогательные функции

Проверьте, выдано ли уже разрешение

const getNotificationPermissionState = async () => {
  try {
    if (navigator.permissions) {
      const navigatorPermissions = await navigator.permissions.query({ name: 'notifications' });
      return navigatorPermissions.state;
    }

    return await Notification.permission;
  } catch (error) {
    console.error(`Error while getting notification status ${error}`);
    throw new Error("We weren't granted permission.");
  }
};

Запросите разрешение пользователя

export const askPermission = async () => {
  try {
    const notificationStatus = await getNotificationPermissionState();

    if (notificationStatus === 'granted') {
      return notificationStatus;
    }

    return await Notification.requestPermission();
  } catch (error) {
    console.error(`Error while requesting notification permission ${error}`);
    throw new Error("We weren't granted permission.");
  }
};

Сервер

import webpush from 'web-push';

const publicVapidKey = process.env.PUBLICVAPIDKEY;
const privateVapidKey = process.env.PRIVATEVAPIDKEY;

webpush.setVapidDetails('mailto:noresponse@inneryou.io', publicVapidKey, privateVapidKey);

alertRouter.post('/subscribe', verifyUserAuthStatus, async (req, res, next) => {
  try {
    const userId = res?.locals?.user?.id;
    const { subscription, fingerPrint } = req.body;

    if (!fingerPrint || !subscription) {
      res.status(400);
      res.locals.error = 'Bad Request';
      throw new Error('Bad Request');
    }

    const isExistingDevice: DeviceModel = await Devices.findOne({
      fingerPrint,
      'subscription.keys.auth': subscription.keys.auth,
    });
    let newDevice: DeviceModel = null;

    if (!isExistingDevice) {
      newDevice = await Devices.create({ user: userId, fingerPrint, subscription });
    }

    if (newDevice) {
      await User.findByIdAndUpdate(userId, {
        $push: {
          devices: newDevice._id,
        },
      });
    }

    res.status(201).json({});

    const notification = {
      title: 'Push Notification',
      body: 'Subscribed to push notifications',
      icon: '',
    };

    const payload = buildCommonMessage(notification);
    const devices: DeviceModel[] = await Devices.find({ user: userId }).lean();

    for (const device of devices) {
      await webpush.sendNotification(device.subscription, payload).catch(err => {
        if (err.statusCode === 410) {
          // DELETE DEVICE IF SUBSCRIPTION IS INVALID
          console.error(`Deleting invalid subscription: ${err}`);
          return Devices.findByIdAndRemove(device._id);
        } else {
          console.error(`Subscription is no longer valid: ${err}`);
        }
      });
    }
  } catch (error) {
    console.error(`Error with push notification ${error}`);
  }
});

Помощник сервера

export const buildCommonMessage = ({ title, body, icon }: CommonMessage): any => {
  return JSON.stringify({
    title: title,
    body: body,
    icon: icon || NOTIFICATION_IMAGE_URL,
  });
};

Сервисный работник

/* eslint-disable no-restricted-globals */

self.addEventListener('push', (e) => {
  console.log('[Service Worker] Push Received.');
  const data = e.data.json();
  const title = data.title || 'InnerYou Notification';
  self.registration.showNotification(title, {
    body: data.body,
    icon: data.icon,
  });
});
...