javaScript | 2019-11-17Javascript로 를 통해 웹과 모바일에 푸쉬 메세지를 발송하는 PWA 기능입니다. 즉 브라우저에서 네이티브와 마찬가지로 사용자에게 알림 메세지를 보낼 수 있습니다. 아직 사파리 계열은 제대로 지원되고 있지 않지만 크롬, 안드로이드 에서는 네이티브와 같은 알림 메세지를 받아보실 수 있습니다. 이제 PWA의 푸쉬 메세지 기능을 추가해 보도록 하겠습니다.
우선 웹에서 푸쉬메세지를 받으려면 서버와 클라이언트(웹브라우저) 사이의 메세지가 필요한데 이를 위해 FCM을 사용합니다.
구글에서 제공하는 Server 와 Client app 간에 푸쉬 메시지를 보낼 수 있는 서비스로 웹, IOS, ANDROID 모두 지원 합니다.
FCM을 사용하기 위해 https://console.firebase.google.com 로 접속하겠습니다.

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

프로젝트에 대한 이름을 설정후 GA설정은 원한다면 선택후 프로젝트를 생성하게 되면 간단하게 프로젝트가 생성되게 됩니다.
생성된 프로젝트의 설정 메뉴 에서 클라우드 메세지 탭으로 이동합니다.
위의 메뉴에서 서버 키 를 사용하기 위해 해당 키를 복사해 두도록 하겠습니다. :)
이제 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에 해당 값을 저장해 두도록 하겠습니다.
위에서의 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)); }); }
여기까지 설정후 프로젝트를 실행하면 알림 허용여부에 대한 창이 나오게 됩니다.

이제 서버에서 메세지가 내려올 경우의 처리를 하도록 하겠습니다.
브라우저에서는 서버에서 푸쉬가 오면 이를 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 에서 좀더 자세히 보실 수 있습니다.
이제 서버에서 푸쉬메세지를 보내게 되면 다음과 같이 알림 설정이 오는것을 확인하실 수 있습니다.

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