woolta

pwa - push 이벤트 구현하기

wooltaUserImgjavaScript | 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' 정보를 가져와서 해당 정보가 존재하면 서버로 해당 키를 삭제하도록 처리하는 코드입니다. 위와같이 작성할 경우 사용자가 직접 구현한 기능으로 알림 취소를 하는것이 아닌 브라우저에서 알림 거부 를 설정해도 정상적으로 알림설정을 처리할 수 있는 장점이 있습니다.

참조