웹 앱에 푸시알림 추가


웹 앱에 푸시알림 추가 글을 통해서 상세한건 보면 되지만 내가 어떻게 했는지 기억이 안나니 기록용으로…

샘플코드를 다운받는다. 혹은 git 복사

git clone https://github.com/GoogleChrome/push-notifications.git

나같은 경우는 https 자체서버를 가지고 있기때문에 따로 웹서버는 설정안해줘도 되었다.

그 경로로 들어가면 파란 push codelab을 볼수있다. 아직 푸시메세지알림은 비활성화되어있음.

서비스워커는 항상 업데이트하는것이 좋은데, Chrome에서 이를 설정하려면 DevTools(마우스 오른쪽 버튼 클릭 > Inspect)를 열고 Application 패널로 이동하고 Service Workers 탭을 클릭한 후 Update on Reload 확인란을 선택하면 된다.

다운받은 샘플코드에 보면 sw.js파일이 있다. 아직은 빈내용임.

서비스워커 등록


다운받은 코드에서 scripts폴더에가면 main.js가 있는데

if ('serviceWorker' in navigator && 'PushManager' in window) {
  console.log('Service Worker and Push is supported');

  navigator.serviceWorker.register('sw.js')
  .then(function(swReg) {
    console.log('Service Worker is registered', swReg);

    swRegistration = swReg;
  })
  .catch(function(error) {
    console.error('Service Worker Error', error);
  });
} else {
  console.warn('Push messaging is not supported');
  pushButton.textContent = 'Push Not Supported';
}

이 내용(서비스워커 등록 코드)을 넣고 콘솔창에 Service Worker is registered 가 뜨는지 확인한다.

애플리케이션 서버키 가져오기


[서버키생성 도우미사이트](https://web-push-codelab.glitch.me/ ) 에서 공개키쌍, 비공개키쌍 생성

공개키를 복사한뒤에

const applicationServerPublicKey = '<Your Public Key>';

(<>도 삭제할것!) 작은따옴표안에 넣어준다. 절대 비공개키를 웹앱에 공개하면 안된다고 하니 주의할것!

상태초기화


sw가 활성화가 되면 main.js에 아래 코드를 추가한다.

//유저가 알림을 허용했는지 안했는지 상태를 확인하는 함수
function initialiseUI() {
  // Set the initial subscription value
  swRegistration.pushManager.getSubscription()
  .then(function(subscription) {
    isSubscribed = !(subscription === null);

    if (isSubscribed) {
      console.log('User IS subscribed.');
    } else {
      console.log('User is NOT subscribed.');
    }

    updateBtn();
  });
}

main.js에 아래코드 추가

//비활성화되어있는버튼을 활성화시 or likewise
function updateBtn() {
  if (isSubscribed) {
    pushButton.textContent = 'Disable Push Messaging';
  } else {
    pushButton.textContent = 'Enable Push Messaging';
  }

  pushButton.disabled = false;
}

main.js에 아래코드추가

//서비스워커가 있는지 감지하면 initialseUI를 실행해라
navigator.serviceWorker.register('sw.js')
.then(function(swReg) {
  console.log('Service Worker is registered', swReg);

  swRegistration = swReg;
  initialiseUI();
})

사용자구독


아직은 버튼이 작동하지 않으므로 main.js에서 initaliseUI()함수를 찾아 아래코드를 추가한다.

//버튼에 클릭 리스너를 추가
  pushButton.addEventListener('click', function() {
    pushButton.disabled = true;
    if (isSubscribed) {
      // TODO: Unsubscribe user
    } else {
      subscribeUser();
    }
  });

그렇다면 최종적으로 initaliseUI()함수는

//유저가 알림을 허용했는지 안했는지 상태를 확인하는 함수
function initialiseUI() {
  //버튼에 클릭 리스너를 추가
  pushButton.addEventListener('click', function() {
    pushButton.disabled = true;
    if (isSubscribed) {
      // TODO: Unsubscribe user
    } else {
      subscribeUser();
    }
  });
  // Set the initial subscription value
  swRegistration.pushManager.getSubscription()
  .then(function(subscription) {
    isSubscribed = !(subscription === null);

    if (isSubscribed) {
      console.log('User IS subscribed.');
    } else {
      console.log('User is NOT subscribed.');
    }

    updateBtn();
  });
}

이런코드가 될것이다.

그런다음 사요자가 현재 구독하지 않은 상태임을 확인하면 subscribeUser()를 호출하기 위해 main.js에 아래코드추가

//사용자가 현재 구독하지 않은 상태임을 알 때 subscribeUser()를 호출
function subscribeUser() {
  const applicationServerKey = urlB64ToUint8Array(applicationServerPublicKey);
  swRegistration.pushManager.subscribe({
    userVisibleOnly: true,
    applicationServerKey: applicationServerKey
  })
  .then(function(subscription) {
    console.log('User is subscribed:', subscription);

    updateSubscriptionOnServer(subscription);

    isSubscribed = true;

    updateBtn();
  })
  .catch(function(err) {
    console.log('Failed to subscribe the user: ', err);
    updateBtn();
  });
}

콘솔에 에러없이 잘 js가 돌아가고, 버튼이 활성화되면서 enable push message가 뜨겠지만 버튼을 누르면 콘솔창에 Failed to subscribe the user 가 뜰것이다. 이건 아직 사용자가 알림을 허용하지 않았기 때문인데, 이 설정은 url을 치는곳 옆에 자물쇠버튼(https일경우), i가 있는 원(local일경우)를 누르면 알림을 허용할지, 차단할지 설정하는 곳이 뜬다. 기본 디폴트값은 차단으로 되어있다.

웹 앱에 푸시알림 추가 글에서는 ‘메서드 updateSubscriptionOnServer는 실제 애플리케이션에서 백엔드로 구독을 보내는 메서드이지만, 이 코드랩에서는 나중에 도움이 되도록 UI에 구독을 출력하겠습니다 ‘ 라고 나와있는데.. 아래 코드를 main.js에 추가한뒤 활성화되어있는 버튼을 누르면 권한프롬프트가 자동으로 뜬다고 하는데 나같은 경우는 안뜨던데………. 그래서 자물쇠아이콘누른뒤에 그냥 ‘‘알림허용’‘을 눌러줬다.

function updateSubscriptionOnServer(subscription) {
  // TODO: Send subscription to application server

  const subscriptionJson = document.querySelector('.js-subscription-json');
  const subscriptionDetails =
    document.querySelector('.js-subscription-details');

  if (subscription) {
    subscriptionJson.textContent = JSON.stringify(subscription);
    subscriptionDetails.classList.remove('is-invisible');
  } else {
    subscriptionDetails.classList.add('is-invisible');
  }
}

그리고 새로고침 한 뒤에 enable push messaging을 눌렀더니 콘솔에서 PushSubscription과 함께 User is subscribed:를 출력하고 버튼의 텍스트가 ‘Disable Push Messaging’으로 바뀌는 것을 알 수 있고 페이지 하단에서 구독을 JSON 볼 수 있었다.

거부된 권한 처리


여기서, 만약 사용자가 계속해서 알림을 허용하지 않은 상태였을때를 고려해야하는데, 사용자에게 본인이 알림을 허용하지 않았을때 푸시버튼을 사용할수없다는것을 알려주기 위해서 버튼을 비활성화 시켜야한다. 이건 updateBtn() 함수에 설정코드를 추가해주면된다. main.js에 updatBtn()함수를 찾아서

if (Notification.permission === 'denied') {
    pushButton.textContent = 'Push Messaging Blocked.';
    pushButton.disabled = true;
    updateSubscriptionOnServer(null);
    return;
  }

아래코드를 추가한다. 그러면 최종적으로 updateBtn()함수는

function updateBtn() {
  if (Notification.permission === 'denied') {
    pushButton.textContent = 'Push Messaging Blocked.';
    pushButton.disabled = true;
    updateSubscriptionOnServer(null);
    return;
  }

  if (isSubscribed) {
    pushButton.textContent = 'Disable Push Messaging';
  } else {
    pushButton.textContent = 'Enable Push Messaging';
  }

  pushButton.disabled = false;
}

가 되겠다. 권한이 ‘‘차단’‘으로 되어있을 경우에는 알림이 불가능하므로 개발자가 할 수 있는 일은 없다…..

권한을 ‘차단’,’허용’을 번갈아가면서 테스트를 해보면 차단했을때는 버튼이 비활성화되면서 push messaging blocked(푸시 메세지가 차단됨) 라고 뜨고, 권한을 허용했으면disable push messaging(푸시메세지 비활성화하기) 이라고 뜬다.(권한을 허용했으니 당연히 반대 버튼은 비활성화를 만드는것이기 때문!)

푸시이벤트 처리


드디어 기다리고기다리던 푸시이벤트처리를 할 차례다. 푸시알림이 작동하는 원리는

  1. 관리자가 푸시메세지를 발송할때
  2. 브라우저는 푸시메지시를 수신하고
  3. 푸시의 대상이 되는 서비스워커를 발견한뒤,
  4. 그 서비스워커를 깨워서 푸시 이벤트를 발송한다.
  5. 서비스워커는 이 이벤트를 수신하고 그 결과로서 알림을 표시한다.

아까 빈칸이었던 sw.js에 아래코드를 추가한다.

self.addEventListener('push', function(event) {
  console.log('[Service Worker] Push Received.');
  console.log(`[Service Worker] Push had this data: "${event.data.text()}"`);

  const title = 'congrats!';
  const options = {
    body: 'this is push msg!',
    icon: 'images/icon.png',
    badge: 'images/badge.png'
  };
const notificationPromise = self.registration.showNotification(title, options);
event.waitUntil(notificationPromise);
});

원글에서는 이 코드만 추가하고나서 개발자도구에 Application-service worker에 들어간뒤 push버튼을 누르면 push msg가 뜬다는데, 도대체 어디가 뭐가 뭐가 뜬다는거지??????????? 절대안뜸. 아무 반응도 없고 콘솔에 찍는 내용도 없고… 그러니까 self.addEventListener 에서 push 이벤트를 감지를 못해서 그러는건데, 원글에서의 화면과 달라서 그런가 push이벤트가 먹지를 않는다!!!!!

나중에 실습하고나서 안 사실이지만 푸시메시지를 보내야지만 푸시이벤트를 감지한다.

푸시메시지 보내기


코드랩 도우미사이트 에 들어가면 codelab message sending이 있다. 여태 작업했던 화면에서 활성화된 버튼을 누르면 밑에

Once you’ve subscribed your user, you’d send their subscription to your server to store in a database so that when you want to send a message you can lookup the subscription and send a message to it.

To simplify things for this code lab copy the following details into the Push Companion Site and it’ll send a push message for you, using the application server keys on the site - so make sure they match.

라는 글이 뜨면서 밑에 {endpoint:——–} 라는 json이 뜨는데, 그 json을 복사해서 도우미사이트의 subscription to Send To 에 붙여넣고 Text to Send 에다가는 아무내용을 적는다(콘솔창에 나타나는 내용이다)

그리고 하단의 SEND PUSH MESSAGE를 클릭하면 브라우저 하단에

pushnoti

이렇게 푸시알람이 온다. 여기서 아이콘바꾸고, 내용바꿔서 알림을 보내면되는데 아까 Text to Send에 적었던 아무내용이 콘솔에 찍히는것을 알 수 있다.

console1

사용자 구독 취소


아직 끝나지 않았다….. 만약 사용자가 처음에는 알림을 허용했는데, 알림오는걸 더이상 원하지 않는다면? 그 작업을 해보자.

main.js로 가서 initaliseUI()함수에서 pushButton의 클릭리스너를 아래코드로..

pushButton.addEventListener('click', function() {
  pushButton.disabled = true;
  if (isSubscribed) {
    unsubscribeUser();
  } else {
    subscribeUser();
  }
});

바꿔준다.

그리고 새로운 함수인 unsubscribeUser() 를 만들어준다. main.js에 추가!

function unsubscribeUser() {
  swRegistration.pushManager.getSubscription()
  .then(function(subscription) {
    if (subscription) {
      return subscription.unsubscribe();
    }
  })
  .catch(function(error) {
    console.log('Error unsubscribing', error);
  })
  .then(function() {
    updateSubscriptionOnServer(null);

    console.log('User is unsubscribed.');
    isSubscribed = false;

    updateBtn();
  });
}

그러면 버튼을 누를때마다 콘솔에서

console2

이렇게, 구독합니다, 구독하지않습니다. 라고 변경된다.

이렇게 완성!!!!


원글이 너무 친절하게 잘 되어있어서 따라하기 어렵지 않았지만, 안될때는 도대체 똑같이 했는데 뭐가 안되는건지..그게 더 답답하고 일주일뒤에 내가 도대체 어떻게 이걸 만들어냈는지 저번에 분명히 2번이나 테스트했는데 기억이 1도 안나서 다시 만들어본… 그리고 내가 이 기술을 알려줘야하기때문에 적은 나의 버전 웹앱 푸시알림 보내기이다.




© 2018. by sora

Powered by sora