Web - web push 구현

00_8_3·2023년 4월 10일
0

Web

목록 보기
1/1

web push

ios 16.4 업데이트로 애플 진영에서 web-push를 사용할 수 있게 되었습니다.

https://webkit.org/blog/13878/web-push-for-web-apps-on-ios-and-ipados/

web-push 하는 방법에 대해 알아보겠습니다.

구성

  • index.html

  • main.js

  • worker.js

  • server.js // express 서버

설치

npm i express web-push

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <button id="subs">Subs</button>
    <button id="unsubs">UnSubs</button>
    <script src="/main.js"></script>
    
</body>
</html>

worker.js

self.addEventListener("push", (e) => {
    const title = e.data.text();
    e.waitUntil(self.registration.showNotification(title));
})

main.js

if( "serviceWorker" in navigator) {
    navigator.serviceWorker.register("worker.js")
}

// 서버에서 생성한 publicKey
const apiKeys = "BKPtd6k1u55r_........P9zAS5IV10rO6nuO5s"

const subsBtn = document.getElementById("subs")
const unsubsBtn = document.getElementById("unsubs")
subsBtn.addEventListener("click", () => {
    navigator.serviceWorker.ready.then((regis) => {
        regis.pushManager.getSubscription().then(async (subs) => {

            if(!subs){
                subs = await regis.pushManager.subscribe({
                    userVisibleOnly: true,
                    applicationServerKey: urlBase64ToUint8Array(apiKeys)
                });
            }

            await fetch("http://localhost:3000/push", {
                        method: "POST",
                        body: JSON.stringify(subs),
                        headers: {
                            "content-type": "application/json"
                        }
                })
        }).catch(e => console.error(e))
    })
})

unsubsBtn.addEventListener("click", async () => {
    const regis = await navigator.serviceWorker.ready;
    const subs = await regis.pushManager.getSubscription()

    if(subs){
        await subs.unsubscribe()
        // console.log("구독 해제")
    }
})

function urlBase64ToUint8Array(base64String) {
    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;
  }

server.js

import webpush from "web-push"
import express from "express"
import cors from "cors"

const main = async () => {
    const app = express()

    app.use(cors({
        origin: "*"
    }))
    app.use(express.json())
    app.use(express.urlencoded({extended: false}))


  // vapid key 생성.
    const keys = webpush.generateVAPIDKeys()
    
    const subjects = "mailto:ehgks@gmail.com"
    webpush.setVapidDetails(
        subjects,
        keys.publicKey,
        keys.privateKey
    )

    app.post("/push", async (req, res) => {
        try {
            const {endpoint, keys} = req.body
            const msg = "asdfasdf"
            webpush.sendNotification({
                endpoint,
                keys,
            }, msg)

            res.json({msg: "noti success"})
        } catch (error) {
            console.log(error)
            res.json({msg: "error"})
        }
    })

    app.listen(3000, () => {
        console.log("ex open")
    })
}

main()
  • VAPID (Voluntary Application Server Identification)는 웹 푸시 프로토콜에 대한 자발적 신원 확인 메커니즘이며, 애플리케이션 서버와 푸시 서비스 간의 통신을 위한 것입니다.
    VAPID 키는 애플리케이션 서버를 푸시 서비스에 신원을 확인하는데 사용되는 공개 키와 개인 키로 구성됩니다.

실행

  1. 서버 실행

    node ./server.js

  2. index.html 실행

    vsCode Live Server로 실행했습니다.

  3. subs 버튼 클릭
    구독과 동시에 웹 브라우저로 Noti가 옵니다.

구독이 완료되었으면 curl을 통해 /push url로 POST 요청을 해도 Noti가 옵니다.

  1. unsubs 버튼 클릭
    구독 해제

아이폰 브라우저

  • 유저가 저장한 PWA에서만 작동합니다.
  • manifest.json 작성 후 html head link에 걸어준다.
    <link rel="manifest" href="/manifest.json" />
{
	"name": "my app",
  	"start_url": "/",
  	"id": "app",
  	"display": "standalone",
  	"icons": [
      {
        "src": "/icon.png",
        "type": "image/png",
        "sizes": "512x512",
      }
    ]
}

참고

https://www.npmjs.com/package/web-push

0개의 댓글