본문 바로가기

[PWA] FCM으로 알림 기능 구현하기 (3) : 포그라운드

[PWA] FCM으로 알림 기능 구현하기 (3) : 포그라운드
[단어 정의]
Non-persistent notification : a notification without an associated service worker registration.
Persistent notification : a notification with an associated service worker registration.

 

구현 코드

 

의사 코드 발췌

 

To create a notification, given a string title, NotificationOptions dictionary options, environment settings object settings, and optionally a ServiceWorkerRegistration object serviceWorkerRegistration, run these steps:

 

  1. Let notification be a new notification.
  2. If a serviceWorkerRegistration was provided, then set notification’s service worker registration to serviceWorkerRegistration.
  3. 타입 에러가 나는 경우 
    • If a serviceWorkerRegistration was not provided and options["actions"] is not empty, then throw a TypeError.
      -> Actions are only currently supported for persistent notifications.
    • If options["silent"] is true and options["vibrate"] exists, then throw a TypeError.
    • If options["renotify"] is true and options["tag"] is the empty string, then throw a TypeError.
  4. 알림 세팅
    • Set notification’s data to StructuredSerializeForStorage(options["data"]).
    • Set notification’s title to title.
    • Set notification’s direction to options["dir"].
    • Set notification’s language to options["lang"].
    • Set notification’s origin to settings’s origin.
    • Set notification’s body to options["body"].
    • Set notification’s tag to options["tag"].
    • Let baseURL be settings’s API base URL.
      • If options["image"] exists, then parse it using baseURL, and if that does not return failure, set notification’s image URL to the return value. (Otherwise image URL is not set.)
      • If options["icon"] exists, then parse it using baseURL, and if that does not return failure, set notification’s icon URL to the return value. (Otherwise icon URL is not set.)
      • If options["badge"] exists, then parse it using baseURL, and if that does not return failure, set notification’s badge URL to the return value. (Otherwise badge URL is not set.)
      • If options["vibrate"] exists, then validate and normalize it and set notification’s vibration pattern to the return value.
    • If options["timestamp"] exists, then set notification’s timestamp to the value. Otherwise, set notification’s timestamp to the number of milliseconds from the Unix epoch to settings’s current wall time, rounded to the nearest integer.
    • Set notification’s renotify preference to options["renotify"].
    • Set notification’s silent preference to options["silent"].
    • Set notification’s require interaction preference to options["requireInteraction"].
    • Set notification’s list of actions to an empty list, then for each entry in options["actions"], up to the maximum number of actions supported (skip any excess entries):
      1. Let action be a new action.
      2. Set action’s name to entry["action"].
      3. Set action’s title to entry["title"].
      4. If entry["icon"] exists, then parse it using baseURL, and if that does not return failure, set action’s icon URL to the return value. (Otherwise icon URL is not set.)
      5. Append action to notification’s list of actions.
  5. Return notification.

 

구현 코드

  • 'firebase.js' 파일 내에 FCM에서 제공해주는 onMessage 메서드를 이용해 구현하였다.
  • 주의해야할 점은 notification API안드로이드 모바일(삼성 인터넷 등)에서는 TypeError를 출력하며 동작하지 않는다는 것이다.
    • 따라서 안드로이드 모바일일 때의 로직은 서비스 워커를 이용하여 구현했다.
/**
 * onMessageListener - 앱 사용 중 메시지 수신 (포그라운드)
 */
export const onMessageListener = () => {
    if (process.client) {

        // firebase FCM 기능 사용
        const app = initializeApp(firebaseConfig);
        const messaging = getMessaging(app);

        // foreground 메시지 수신 로직 
        onMessage(messaging, (payload) => {

            const notificationTitle = payload.data.title;
            const notificationOptions = {
                body: payload.data.body,
                image: payload.data.image_url,
                icon: "https://주소/icon.png",
            };

           // 웹일 때 
            if (!isMobile) {
                const notif = new Notification(
                    notificationTitle,
                    notificationOptions,
                );

                notif.onclick = (event) => {
                    event.preventDefault();
                    const landing_url = payload.data.landing_url;
                    const newPath = landing_url ? landing_url : "/chat";
                    window.location.href = `${BASE_FRONT_URL}${newPath}`;
                    notif.close();
                };
                
            // 모바일 중에서도 안드로이드(모바일웹 또는 PWA)일 때    
            } else if (!isIOSApp()) {
                // 서비스 워커 로직으로 구현
                navigator.serviceWorker.ready.then(function (registration) {
                    registration.showNotification(
                        notificationTitle,
                        notificationOptions,
                    );
                });
            }
        });
    }
};

 

 

트러블 슈팅

 

구현 코드 카테고리에서 이미 언급했던 것처럼 notification API가 아래와 같이 안드로이드 모바일(삼성 인터넷 등)에서는 TypeError를 출력하며 동작하지 않았다.

Failed to construct 'Notification': Illegal constructor. Use ServiceWorkerRegistration.showNotification() instead.

 

 

관련 이슈 내용 

 

결론적으로는 안드로이드 모바일에서 서비스 워커를 통한 알림 기능을 구현하여 해결하였다. 현재는 onClick 이벤트 일부 구현으로 웹 / 모바일 분기를 해놨지만 서비스 워커로 onClick까지 로직을 넣어둔다면 디바이스와 상관없이 서비스 워커로 통일하는 방법이 최선인 것으로 보인다.

 

 

Throws exception on Android/Chrome · Issue #1 · aaronccasanova/use-notification

When triggering a notification from the examples on Chrome for Android, the following exception is thrown: Failed to construct 'Notification': Illegal constructor. Use ServiceWorkerRegistration.sho...

github.com

 

레퍼런스 

 

Notifications API Standard

Abstract This standard defines an API to display notifications to the end user, typically outside the top-level browsing context’s viewport. It is designed to be compatible with existing notification systems, while remaining platform-independent. Table o

notifications.spec.whatwg.org

 

728x90
⬆︎