스트리밍은 대부분의 브라우저와
Developer 앱에서 사용할 수 있습니다.
-
Safari의 웹 푸시 소개
웹 푸시를 통해 macOS의 Safari에서 웹 사이트 및 웹 앱에 더 우수한 알림 기능을 구현할 수 있습니다. 푸시 API, 알림 API 및 서비스 워커의 웹 표준 기반 조합을 통해 사용자에게 원격으로 알림을 보내는 방법을 보여드리겠습니다.
리소스
- Learn more about bug reporting
- Notifications API
- Push API
- Sending web push notifications in web apps and browsers
- Service Worker API
관련 비디오
WWDC23
WWDC22
-
다운로드
♪♪
안녕하세요 저는 Brady Eidson입니다 WebKit Architecture 팀의 엔지니어죠 Safari의 웹 푸시(Web Push)를 소개하게 되어 정말 기쁘군요 웹 푸시를 통해 웹 응용 프로그램 사용자들에게 원격으로 알림을 보낼 수 있습니다 화면 오른쪽 위에 webkit.org의 알림이 나타났습니다 알림을 클릭하면 WebKit의 글이 새 창에 열리죠 어떻게 작동되는 건지 자세히 설명하기 전에 여러분께서 궁금해할 몇 가지 질문에 답해 드릴게요
웹 푸시는 macOS Ventura부터 Mac Safari에서 지원됩니다 그리고 iOS와 iPadOS에도 내년부터 지원을 시작할 겁니다
Apple의 Safari 푸시 알림은 Mac Safari 사용자들에게 꽤 오랫동안 제공된 옵션이었죠 그 옵션도 계속 제공되긴 하겠지만 웹 푸시에 대한 지원이 추가된 걸 알려 드리게 돼 기쁩니다 이제 진정한 웹 푸시가 된 거죠 다른 브라우저에 구현되는 것처럼 다양한 웹 표준을 동일하게 조합했습니다 이 표준에 대해서는 나중에 자세히 알아볼 겁니다 그보다 중요한 내용이 있습니다 여러분이 웹 표준에 맞게 코딩한 응용 프로그램의 경우에도 Safari에서 작동하게 하려고 변경할 필요가 없단 겁니다 물론 브라우저 감지 기능에서 Safari를 제외한다면 과정이 좀 복잡해지겠죠 지금이 browser detection에서 feature detection으로 전환하기 좋은 타이밍입니다 feature detection은 늘 최고라고 여겨지죠 우리는 동일한 Apple Push Notification Service를 사용하는데 모든 Mac과 iOS 기기에서 기본적인 푸시 기능을 제공합니다 하지만 Safari 사용자들과 연결되기 위해서 Apple 개발자 계정이 필요하진 않습니다 우리는 웹 푸시에 새 엔드포인트 URL을 사용하는데 의도치 않게 Safari를 제외하는 일이 생길 수도 있죠 여러분이 서버의 엔드포인트를 엄격하게 관리하고 있다면 push.apple.com의 모든 서브 도메인에서 URL을 허용해야 합니다 이제 중요한 질문에 답은 했으니 세부 사항으로 넘어가 보도록 하죠 우선, 사용자의 입장으로 Safari에서 웹 푸시 경험에 대해 살펴볼 겁니다 그다음 웹 푸시의 전체적인 흐름의 다룰 겁니다 권한을 요청하는 것부터 알림 센터에서 항목을 처리하는 것까지요
마지막으로는 기존 웹 앱에 웹 푸시를 추가하는 데 필요한 것들을 알아볼 겁니다 첫 번째는 Mac Safari의 사용자 경험입니다 데모만큼 잘 보여 주는 것도 없죠 이건 macOS Ventura의 Safari입니다 제가 브라우저 탭에 webkit.org를 열어 놨어요 전 WebKit open source project를 최신 상태로 유지해야 하는데 웹 푸시가 그걸 도와줍니다 webkit.org는 사용자 제스처로 요청하지 않으면 푸시 권한을 받을 수 없습니다 구독 알림을 위해 있는 종 모양을 눌러 보겠습니다 지금 나타난 건 시스템 알림 프롬프트입니다 다른 응용 프로그램에서 보는 것과 같은 것이죠 이 경우에는 webkit.org를 대신하는 겁니다 '허용'을 클릭할게요 이제 다 됐어요 webkit.org에서는 새로운 블로그 글에 대해 알림과 소스 코드 저장소에 대한 알림을 받을 수 있도록 하고 있습니다 모든 알림을 받으면 일할 때 집중이 안 될 수 있지만 새로운 블로그 게시물에 대해선 꼭 알려 드리고 싶어요 알림창을 확인해 볼게요 공교롭게도 방금 누가 WebKit 블로그에 웹 푸시 관련해서 글을 올렸네요 이런 알림은 다른 알림과 똑같이 표시되고 webkit.org가 보낸 것으로 여겨집니다 이걸 클릭해서 활성화시킬 수 있죠 Safari에 블로그 글이 올라왔네요 사용자가 웹 사이트에 대한 권한을 부여받으면 그 권한에 대한 통제권이 유지됩니다 저는 macOS 사용자로서 시스템 설정에서 알림 설정을 관리하는 데 익숙합니다 여기에서 webkit.org의 알림을 제어할 수 있습니다 다른 앱이나 서비스와 설정 창의 구조가 동일합니다 저는 Safari 사용자라서 웹 사이트 설정을 변경하는 게 익숙합니다 webkit.org의 권한을 설정하거나 해제할 수도 있죠
이게 웹 푸시가 Mac Safari에서 작동하는 방식입니다 다음으로 넘어가기 전에 영상을 통해 몇 가지 사항을 복기해 보도록 하죠 우선, 우리는 사용자가 요청하지 않은 구독 요청에 의해 스팸 처리가 되는 건 원치 않습니다 따라서 웹 사이트에서는 푸시 구독 요청만 할 수 있습니다 마우스 클릭이나 키보드 타건에 반응하는 거죠 웹 사이트에서 사용자에게 알림을 표시할 권한이 생기면 사용자가 그 권한을 제어합니다 Safari 설정이나 시스템 설정에서 제어할 수 있죠 두 군데에서 제어하는 경우 설정은 동기화된 채로 유지됩니다 마지막으로 다양한 유형의 이벤트에 알림을 제공하는 경우 세밀하게 제어할 수 있도록 하는 게 좋습니다 웹 앱 내의 알림 유형에 대해 말이죠 다른 앱과 마찬가지입니다 이제 웹 푸시가 실행되는 걸 봤으니 각 단계에서 어떤 일이 일어나는지 자세히 살펴보죠 여러분 중에 이미 익숙한 분도 있겠지만 웹 푸시를 처음 접하는 분들을 위해 차근차근 살펴보겠습니다 관련 기준이나 서류도 참고하도록 하죠 우선 사용자가 브라우저 탭에서 사이트를 방문하는 경우를 보죠 Safari에서 webkit.org를 열었습니다 탭에서 열렸기 때문에 Service Worker를 설치할 수 있습니다 Service Worker는 전체 도메인 대신 작동하는 JavaScript 단위로 현재 열려 있는 브라우저 탭과 구분됩니다 Service Worker 스크립트가 설치되면 여러분의 웹 앱에서 푸시 구독 요청을 할 수 있습니다 앞서 말씀드렸듯이 이 요청은 사용자 제스처와 연결돼야 합니다 webkit.org는 종 모양을 눌러 허가를 요청하기 때문에 사용자 제스처 요구 사항을 충족시킵니다 여러분의 사이트에서 푸시 구독 요청을 하면 사용자에게는 시스템 프롬프트가 나타납니다 사용자는 여기에서 최종 결정을 하고 이 웹 사이트에 강한 기능을 부여할 수 있습니다
사용자가 요청을 거부할 수도 있으니 여러분의 JavaScript도 대처할 준비가 돼 있어야 합니다 하지만 사용자가 권한을 부여했다고 하면 PushSubscription 객체를 JavaScript가 반환합니다 브라우저에 있는 사용자에게 서버에서 보내는 푸시 메시지에 필요한 모든 항목이 포함돼 있습니다 정확한 URL 엔드포인트 같은 정보가 포함되죠 PushSubscription 페이로드를 여러분의 웹 앱을 위해 가장 적합한 방식으로 서버로 다시 보냅니다 인기 있는 서버 패키지들은 구독 관리를 위해 웹 푸시를 지원합니다 아니면 직접 관리할 수도 있죠 이는 푸시 메시지를 서버에 기록된 URL 엔드포인트로 보내는 방법과 시간에도 동일하게 적용됩니다 그 시기는 여러분과 웹 사이트에 달려 있습니다 하지만 푸시 메시지를 보내기로 결정했다면 다음 단계는 제가 도와드릴 수 있습니다 푸시를 보낼 때 Service Worker가 얼마나 필요한지 기억하세요? 서버에서 푸시 메시지를 보내고 Safari가 그걸 수신하면 Safari에서 Service Worker를 깨우고 JavaScript 푸시 이벤트로 그 메시지를 보냅니다 알림 센트에서 사용자에게 알림을 보여 주는 건 푸시 이벤트를 처리할 때 필수적입니다 푸시 이벤트 및 알림 창은 현재 웹 사이트가 브라우저 탭에 열려 있는 경우 보여집니다 웹 사이트가 브라우저 탭에 열려 있지 않아도 보여집니다 macOS Ventura에 있는 Safari의 경우 Safari가 실행 중이 아닐 때도 이런 일이 발생합니다 마지막으로 사용자가 해당 알림을 클릭하면 notificationclick event가 Service Worker에 전송되어 적절한 반응을 보이도록 합니다 예를 들어, 새 창을 열 때 해당 알림과 관련된 URL로 이동하는 거죠 우리가 쓰는 웹 푸시 흐름을 이해하기 위해 더 자세한 내용을 알아보도록 하죠 웹 푸시 지원 기능을 기존 웹 앱에 추가하는 겁니다 webkit.org 외에도 Browser Pets는 Safari와 WebKit팀에게 없어서는 안 될 내부 도구입니다 모두 좋아하는 WebKittens와 Pups의 상태를 업데이트하는 건 늘 Browser Pets의 사명이었습니다 그리고 웹 푸시가 그걸 쉽게 만들어 줬죠 이미 내부 BrowserPets 도메인에 ServiceWorker 스크립트가 있어서 페이지 로딩 속도를 높이고 여러 탭을 동기화하고 있습니다 조금 더 상위 단계로 가면 ServiceWorker 스크립트는 다음과 같습니다 엔지니어가 Browser Pets 페이지를 방문하면 이 JavaScript는 Service Worker 스크립트가 이미 등록된 것인지 확인하거나 필요한 경우라면 등록합니다 지금 보고 있는 건 feature detection 방식으로 최고의 방식이라고 앞서 말씀드렸죠 Service Worker의 전제 조건을 처리하면 푸시 구독 준비는 끝난 겁니다 명확한 사용자 제스처가 없으면 푸시 구독을 요청할 수 없습니다 버튼을 누른 데 대한 응답으로 스트립트를 실행하는 건 그 요구 사항을 충족하는 여러 방법 중 하나입니다 사용자가 버튼을 클릭하면 푸시 구독 요청을 위한 코드가 뜹니다 이에 대해 더 자세히 설명해 드릴게요 우선 푸시 구독 요청을 설정해야 합니다 여기서 중요한 건 공개 키입니다 우린 Apple의 push server를 통해 서버를 식별할 수 있습니다 우린 다른 브라우저와 마찬가지로 VAPID란 표준 기술을 사용합니다 VAPID의 자세한 내용은 나중에 설명하도록 하겠습니다 어쨌든 웹에는 서버 설정에 가장 적합한 솔루션을 제공하는 리소스가 있습니다 VAPID 키를 설정하면 구독 요청을 보낼 준비가 끝납니다 우리가 정확하게 공지해야 할 것은 푸시는 항상 사용자에게 보여진다는 겁니다 JavaScript Push API의 기준에서 본다면 JavaScript runtime은 푸시에 대해서 선택적으로 응답하는 걸 허락하지만 대부분 브라우저에서는 지원하지 않습니다 Safari에서는 그 기능을 지원하지 않습니다 대부분 웹 사이트와 마찬가지로 Browser Pets에도 필요하지 않죠 그다음에 푸시 허가를 요청합니다 이 JavaScript는 사용자가 승인하거나 거절할 수 있는 권한 프롬프트를 표시합니다 사용자가 권한을 허가했다고 가정해 보겠습니다 Safari팀이 Browser Pets를 위해 하는 일이죠 그럼 브라우저에서 사용자에게 보여지는 자세한 방법이 담긴 PushSubscription 객체를 제공합니다 URL 엔드포인트나 전송을 위한 푸시 메시지 암호화에 사용하는 키 같은 거죠 마지막으로 모든 세부 사항을 우리 서버로 전송해야 합니다 앞서 언급한 바와 같이 이에 대한 세부 내용은 응용 프로그램에 따라 다양합니다 BrowserPets 서버는 WordPress를 이용하며 이미 표준 웹 푸시를 지원하는 몇 가지 플러그인이 있습니다 여러분의 백엔드에서도 마찬가지일 겁니다 웹에는 어떤 환경에서도 올바른 솔루션을 찾아 주는 리소스가 있습니다 이제 Service Worker JavaScript 코드를 다시 살펴보도록 하죠 푸시 이벤트를 포함해서 새로운 이벤트를 처리해야 합니다 푸시 메시지가 Browser Pets 서버에서 다른 브라우저로 전송되면 Service Worker가 푸시 이벤트를 전송합니다 그 이벤트에는 PushMessageData 객체도 포함되는데 여러분의 서버에서 보낸 데이터에 접근하는 여러 가지 방법이 있죠 우리는 JSON accessor를 사용합니다 우리가 푸시 구독을 허용하면 JavaScript가 푸시를 사용자한테 띄운다고 했던 거 기억나세요? platform native notification을 항상 표시해야 한다는 겁니다 푸시를 누를 때마다 반응하도록 말이죠 그게 푸시 이벤트 핸들러에서 빨리 이 작업을 수행하는 게 좋죠 우리는 JSON blob에서 필요한 모든 걸 수행합니다 URL로 작업 설정을 하는 것도 포함되죠 그렇게 하면 바로 도움이 됩니다 우리는 알림이 표시되고 사용자가 그 알림을 클릭하는 걸 처리해야 합니다 Service Worker 스크립트가 처리할 이벤트가 더 있는 거죠 notificationclick 핸들러에서는 BrowserPets가 새 창을 열기 위해 클릭한 알림의 URL을 가져옵니다 아주 흔한 패턴이니까 잘 알아두세요 웹 푸시를 지원하기 위해 쓰는 JavaScript는 이게 다예요 물론 개발 중에 도움을 받는 게 가장 좋습니다 늘 그렇듯이 이럴 때 Web Inspector가 필요하죠 브라우저 탭에서 연 웹 사이트의 디버그를 돕는 것 외에 Web Inspector는 Service Worker 인스턴스를 검사할 수 있고 이벤트 핸들러의 breakpoints를 설정합니다 이 모든 걸 사용해 JavaScript를 검사하고 디버그해 푸시를 띄울 수도 있고 Service Worker 코드를 이용해 푸시와 알림 이벤트도 처리할 수 있죠 그뿐만 아니라 Apple Push Notification 서버는 여러분이 푸시 메시지를 띄우려고 할 때 문제가 발생하면 확인할 수 있도록 해 줍니다 자세한 내용은 이 세션과 관련된 링크를 참고하세요 여러분께 알려 드릴 사항이 더 있습니다 사용자의 개인 정보 보호와 가용 전력에 대한 코드를 작성과 관련해 얘기하고자 합니다 중요한 건 제가 이 말을 처음 하는 게 아니란 겁니다 푸시 알림을 보려면 사용자 제스처가 필요합니다 웹 플랫폼의 다른 특별한 기능과 마찬가지로 사용자의 신뢰를 얻기 위해서는 사용자가 웹 푸시의 사용을 요청하도록 요구해야 합니다 푸시 구독을 요청하는 코드를 생성하는 걸 보여 드리면서 사용자에게 알림이 보여야 한다고 말씀드렸었죠 푸시 이벤트를 처리하는 건 여러분의 JavaScript가 백그라운드에서 작동되도록 하는 게 아닙니다 그러면 사용자의 신뢰를 잃고 배터리 수명도 닳게 될 겁니다 푸시 이벤트를 처리할 때는 알림 센터에 알림을 게시해야 합니다 다른 브라우저들은 사용자에 대한 푸시 표시 규정 위반 방침이 있으며 Safari도 마찬가지입니다 macOS Ventura의 beta build에선 세 번의 푸시 이벤트 후 적시에 알림을 게시하지 않으면 여러분 사이트의 푸시 구독은 취소될 겁니다 그렇게 되면 권한을 얻는 과정을 다시 진행해야 합니다 이번 세션은 여기서 끝입니다 우리는 웹 푸시 지원을 진심으로 자랑스럽게 생각하며 모든 사이트에서 사용하길 기대하고 있습니다 Apple 개발자 계정은 필요 없습니다 표준에 맞춰 코드를 생성하고 feature detection을 이용하면 의도치 않게 Safari를 제외하는 일도 없을 테고 여러분 앱의 사용자들은 macOS Ventura의 Safari 16에서 웹 푸시의 이점을 누리게 될 겁니다 여느 때처럼 올해도 Safari와 WebKit에 새 기능을 추가했으니 해당 세션에서 자세한 내용을 확인하시기 바랍니다 시청해 주셔서 감사합니다 2022 WWDC 남은 기간도 잘 마치시길 바랍니다
-
-
8:27 - BrowserPetsWorker.js
// BrowserPetsWorker.js function handleMessageEvent(event) { // ... }; self.addEventListener('message', (event) => { handleMessageEvent(event); }); function primeCaches() { // ... }; self.addEventListener('install', (event) => { primeCaches(); }); self.addEventListener('fetch', (event) => { event.respondWith(caches.match(event.request)); });
-
8:42 - BrowserPetsMain.js
// BrowserPetsMain.js var registration; if ('serviceWorker' in navigator) { let registration = await navigator.serviceWorker.getRegistration(); if (!registration) registration = await navigator.serviceWorker.register('BrowserPetsWorker.js'); }
-
9:00 - BrowserPetsMain.js subscribeToPush()
// BrowserPetsMain.js async function subscribeToPush() { // ... } // BrowserPetsMain.html <button onclick="subscribeToPush()">Register for Updates</button>
-
9:19 - BrowserPetsMain.js subscribe
// BrowserPetsMain.js async function subscribeToPush() { let serverPublicKey = VAPID_PUBLIC_KEY; let subscriptionOptions = { userVisibleOnly: true, applicationServerKey: serverPublicKey }; let subscription = await swRegistration.pushManager.subscribe(subscriptionOptions); sendSubcriptionToServer(subscription); }
-
9:36 - BrowserPetsMain.js subscriptionOptions
// BrowserPetsMain.js async function subscribeToPush() { let serverPublicKey = VAPID_PUBLIC_KEY; let subscriptionOptions = { userVisibleOnly: true, applicationServerKey: serverPublicKey }; let subscription = await swRegistration.pushManager.subscribe(subscriptionOptions); sendSubcriptionToServer(subscription); }
-
10:21 - BrowserPetsMain.js request permission to push
// BrowserPetsMain.js async function subscribeToPush() { let serverPublicKey = VAPID_PUBLIC_KEY; let subscriptionOptions = { userVisibleOnly: true, applicationServerKey: serverPublicKey }; let subscription = await swRegistration.pushManager.subscribe(subscriptionOptions); sendSubcriptionToServer(subscription); }
-
11:13 - BrowserPetsWorker.js push
// BrowserPetsWorker.js self.addEventListener('push', (event) => { let pushMessageJSON = event.data.json(); // Our server puts everything needed to show the notification // in our JSON data. event.waitUntil(self.registration.showNotification(pushMessageJSON.title, { body: pushMessageJSON.body, tag: pushMessageJSON.tag, actions: [{ action: pushMessageJSON.actionURL, title: pushMessageJSON.actionTitle, }] })); }
-
12:06 - BrowserPetsWorker.js notification click
// BrowserPetsWorker.js self.addEventListener('notificationclick', async function(event) { if (!event.action) return; // This always opens a new browser tab, // even if the URL happens to already be open in a tab. clients.openWindow(event.action); });
-
-
찾고 계신 콘텐츠가 있나요? 위에 주제를 입력하고 원하는 내용을 바로 검색해 보세요.
쿼리를 제출하는 중에 오류가 발생했습니다. 인터넷 연결을 확인하고 다시 시도해 주세요.