woolta

pwa - push 이벤트 구현하기

wooltaUserImgb00032 | javaScript | 2019-11-17

PWA - Push Notification?

Javascript로 를 통해 웹과 모바일에 푸쉬 메세지를 발송하는 PWA 기능입니다. 즉 브라우저에서 네이티브와 마찬가지로 사용자에게 알림 메세지를 보낼 수 있습니다. 아직 사파리 계열은 제대로 지원되고 있지 않지만 크롬, 안드로이드 에서는 네이티브와 같은 알림 메세지를 받아보실 수 있습니다. 이제 PWA의 푸쉬 메세지 기능을 추가해 보도록 하겠습니다.

FCM 키 발급.

우선 웹에서 푸쉬메세지를 받으려면 서버와 클라이언트(웹브라우저) 사이의 메세지가 필요한데 이를 위해 FCM을 사용합니다.

FCM 이란??

구글에서 제공하는 Server 와 Client app 간에 푸쉬 메시지를 보낼 수 있는 서비스로 웹, IOS, ANDROID 모두 지원 합니다.

1. FCM 프로젝트 생성

FCM을 사용하기 위해 https://console.firebase.google.com 로 접속하겠습니다.

https://image.woolta.com/3fe805c200d983c9.png

해당 영역에서 푸쉬서비스를 위한 프로젝트 생성을 위해 프로젝트 추가를 클릭해주도록 하겠습니다.

https://image.woolta.com/3fd2e5b648556154.png

프로젝트에 대한 이름을 설정후 GA설정은 원한다면 선택후 프로젝트를 생성하게 되면 간단하게 프로젝트가 생성되게 됩니다.

2. FCM 서버 키 발급

생성된 프로젝트의 설정 메뉴 에서 클라우드 메세지 탭으로 이동합니다.

https://image.woolta.com/3fee1fba7629303c.png 위의 메뉴에서 서버 키 를 사용하기 위해 해당 키를 복사해 두도록 하겠습니다. :)

service-worker 알림설정

서비스워커에 알림 허용 설정.

이제 service-worker 에서 알림 설정 세팅을 위해 코드를 작성해 보도록 하겠습니다.

export const PUSH_APPLICATION_SERVER_KEY = 'FCM 서버키를 넣어주세요.';

// 해시 처리
const urlB64ToUint8Array = (base64String: string) => {
  const padding = '='.repeat((4 - base64String.length % 4) % 4);
  const base64 = (base64String + padding)
    .replace(/\-/g, '+')
    .replace(/_/g, '/');

  const rawData = window.atob(base64);
  const outputArray = new Uint8Array(rawData.length);

  for (let i = 0; i < rawData.length; ++i) {
    outputArray[i] = rawData.charCodeAt(i);
  }
  return outputArray;
};

// 구독하기
export const subscribeUser = (swRegistration) => {

  const applicationServerKey = urlB64ToUint8Array(PUSH_APPLICATION_SERVER_KEY);
  const ACCESS_PUSH_TOKEN = 'ACCESS_PUSH_TOKEN'; 

  swRegistration.pushManager.subscribe({
    userVisibleOnly: true,
    applicationServerKey: applicationServerKey, // 서버 키 등록
  }).then((subscription) => {
    const pwaSubscription = JSON.parse(JSON.stringify(subscription));
    localStorage.setItem(ACCESS_PUSH_TOKEN, pwaSubscription.keys.auth); // 추후 코드 제거를 위해 저장합니다.
    pushSubscription(pwaSubscription);
  }).catch(e => console.log(`subscribe error`, e));
};

export const pushSubscription = (subscription) => {
  // 서버로 구독 정보 전송 
};

서비스 워커의 pushManager 를 통해 위에서 설정한 FCM 키를 통해 푸쉬메세지 구독에 대한 함수를 요청하였습니다. 이때 pushSubscription 을 통해 서버로 전송해 DB에 해당 값을 저장해 두도록 하겠습니다.

https://image.woolta.com/3fe2bf507e28a66c.png 위에서의 pushManager 의 파라미터를 그대로 저장하게 되면 위의 구조처럼 정보가 저장됩니다.

위의 코드를 서비스 워커가 로드될때 불러주도록 설정하겠습니다.

if ('serviceWorker' in navigator && 'PushManager' in window) {
      window.addEventListener('load', () => {
        navigator.serviceWorker.register('/service-worker.js')
          .then(reg => subscribeUser(reg))
          .catch(e => console.log(e));
      });
    }

여기까지 설정후 프로젝트를 실행하면 알림 허용여부에 대한 창이 나오게 됩니다.

https://image.woolta.com/3fd9747e1ed54e92.png

Push 메세지 처리

이제 서버에서 메세지가 내려올 경우의 처리를 하도록 하겠습니다.

브라우저에서는 서버에서 푸쉬가 오면 이를 service-worker에서 감지하는 함수가 존재합니다. 각 함수의 역할은 다음과 같습니다.

함수명역활
push서버에서 알림 메세지가 오는것을 감지합니다.
notificationclick알림창을 클릭했을때의 이벤트를 감지합니다.

클라이언트

// 서버에서 푸쉬가 왔을때 감지하는 이벤트.
self.addEventListener('push', function (event) {
    console.log(`Push had this data: "${event.data.text()}"`);
    const pushInfo = JSON.parse(event.data.text());

    const options = { // 푸쉬 알림창에 대한 각종 설정
        body: pushInfo.content, // 푸쉬 매세지에 대한 설정.
        icon: 'static/main-icon192x192.png', // 알림 아이콘 사이즈
        data: {// 푸쉬메세지에 필요한 커스텀값들을 obj 형태로 전달 가능.
            url: pushInfo.url // 알림 클릭시 필요한 url 세팅. 커스텀 데이터
        }
    };

    //showNotification 에 첫 파라미터는 제목, 두번째는 위의 옵션 데이터를 넣어줍니다.
    event.waitUntil(self.registration.showNotification(pushInfo.title, options));
});

// 알림 메세지를 클릭했을때의 이벤트.
self.addEventListener('notificationclick', function (event) {
    event.notification.close(); // 푸쉬 종료 처리

    event.waitUntil(
      // `push` 에서 받은 url로 새창으로 열어 이동
        clients.openWindow(event.notification.data.url) 
    );
});

알림 서비스의 옵션은 진동 등 좀더 여러가지가 존재합니다. 이는 pwa-push-noti-guide 에서 좀더 자세히 보실 수 있습니다.

이제 서버에서 푸쉬메세지를 보내게 되면 다음과 같이 알림 설정이 오는것을 확인하실 수 있습니다.

https://image.woolta.com/push.gif

알림 취소 작업

사용자는 웹어플리케이션 내부 혹은 브라우저 에서 알림을 취소 할 수 있습니다. 지금부터는 해당 기능을 추가해 보도록 하겠습니다.

push 알림 상태

pwa 의 push 에는 다음과 같은 3가지의 상태가 존재합니다. 해당 상태는 Notification 객체를 을 통해 알 수 있습니다.

함수명역활
default알림 허용, 알림 거부 그 어떤것도 안한 기본 상태
granted알림 허용 상태
denied알림 거부 상태

서비스 워커 등록 수정

서비스워커에서 알림 기본상태일때만 구독함수를 실행하고 허용상태가 아닐 경우 존재하는 알람 설정을 삭제하는 작업을 하도록 하겠습니다.

if ('serviceWorker' in navigator && 'PushManager' in window) {
      window.addEventListener('load', () => {
        navigator.serviceWorker.register('/service-worker.js')
          .then(reg => initSubscribe(reg)) // 바로 subscribeUser 를 호출하지 않고 권한을 통해 판단.
          .catch(e => console.log(e));
      });
    }

export const initSubscribe = (swRegistration) => {

  // 사용자가 브라우저에서 강제로 알람 차단 할 경우 남아있는 키 제거
  if (Notification.permission !== 'granted') {
    removeAccessPushToken();
  }

  // 알림 기본 설정일 경우 구독 시켜주기.
  if (Notification.permission === 'default') {
    subscribeUser(swRegistration);
  }
};

위의 설정을 작성시 권한 설정을 안한 경우에만 subscribeUser 를 호출하고 권한 허용상태가 아닌 경우 토큰을 삭제 하도록 처리하도록 합니다. 이젠 발급된 키를 삭제하는 removeAccessPushToken 를 작성하도록 하겠습니다.

removeAccessPushToken 작성

const removeAccessPushToken = () => {
  const pwaSubscriptionKey = localStorage.getItem(ACCESS_PUSH_TOKEN); // subscribeUser 에서 저장한 키 가져오기
  if (!pwaSubscriptionKey) {
    return;
  }
  pushUnsubscription(pwaSubscriptionKey);
  localStorage.removeItem(ACCESS_PUSH_TOKEN);
};

cosnt pushUnsubscription = pwaSubscriptionKey => '서버로 해당 키 제거 요청'

위의 코드는 이전 subscribeUser 를 통해 구독이 완료되면 브라우저에 저장한 'auth' 정보를 가져와서 해당 정보가 존재하면 서버로 해당 키를 삭제하도록 처리하는 코드입니다. 위와같이 작성할 경우 사용자가 직접 구현한 기능으로 알림 취소를 하는것이 아닌 브라우저에서 알림 거부 를 설정해도 정상적으로 알림설정을 처리할 수 있는 장점이 있습니다.

참조

Copyright © 2018 woolta.com

gommpo111@gmail.com