깜지
팀은 카톡 채팅방을 통해 스터디 챌린지를 진행한다. 사용자들은 매주 서포터즈의 안내 카톡을 받고 문제 제출 미션을 잊지 않고 수행한다. 매주 진행되고 있는 이 일을 자동화하여 깜지 서포터즈 없이도 사용자들이 꾸준히 문제를 제출하는 환경을 만들고 싶었다.
Service Worker
를 활용하면 Push API와 Notifications API를 통해 웹에서도 앱처럼 백그라운드 Push 알림을 보낼 수 있다. Push 알림은 Progressive Web App의 필수 조건이기도 하며, 사용자를 재참여(re-engageable)하게 하는 것을 목적으로 한다.
사실 웹 푸시 알림을 받으려면 PWA로 개발된 페이지를 휴대폰에 설치해야 한다. 해외에서는 많이 활용되고 있지만, 국내에서 이런 형태로 앱을 사용하는 것은 대부분의 사용자에게 익숙지 않을 것이다.
그럼에도 불구하고 PWA를 통한 웹 푸시 알림을 개발했던 이유가 있다.
예를 들어, 문제를 제출할 때는 코드나 사진을 첨부하는 일이 빈번하게 발생하기 때문에 PC 환경에서 진행하는 게 편하다. 반면 틈틈이 문제를 풀거나 미션 현황을 확인할 때는 모바일로 접속하는 게 편리하다.
프론트엔드 1명, 백엔드 1명, 인프라 엔지니어 1명으로 구성된 팀이었기에 웹으로 기능을 개발하고 배포하는 것만 해도 시간이 모자란 상황이었다. 2주에 한 번씩은 계속해서 개발 사이클이 돌아가면서 기능 개발과 수정이 반복되다 보니, 앱 개발 또는 웹 뷰 개발을 학습해서 도입할 상황이 아니었다.
이러한 이유로 Web Push Notification을 지원하게 되었다.
브라우저가 백그라운드에서 실행시키는 스크립트이다. 기본적으로 웹 애플리케이션, 브라우저, 네트워크 사이에서 프록시 서버 역할을 한다.
fetch
이벤트의 중간자 역할로 캐시를 수행할 수 있다.브라우저와 네트워크 사이 새로운 계층에 존재하기 때문에, 브라우저를 종료해도 네트워크와 통신할 수 있다. 따라서 브라우저가 종료된 상태에서도 푸시 알림을 수신할 수 있는 것이다.
백그라운드 웹 푸시 알림을 위해 다음과 같은 컴포넌트들이 필요하다.
requestPersmission
메서드를 사용해 권한을 요청한다.Push 알림을 수신하는 브라우저, 발송하는 서버 사이 규약이 있어야 상호작용이 가능하다.
안전한 Push 메시지를 전송하기 위해 VAPID(Voluntary Application Server Identification) 인증 방식을 사용한다.
서버에서 Push 서비스로 메시지를 전달할 때, VAPID 명세에 따른 정보가 담긴 JWT를 함께 전달하고, 이 JWT를 VAPID의 비공개 키로 서명(암호화)한다.
위 그림에서 암호화 과정을 포함하여 표현했다.
Web Push Protocol을 쉽게 구현할 수 있게 해주는 솔루션 중 FCM이 있다. 클라우드를 이용해 메시지를 전송할 수 있다. 장점은 무료라는 것과, 특정 플랫폼에 종속적이지 않기 때문에 확장성이 높다는 것이다.
FCM을 이용해서 프론트엔드에서 Web Push Notification을 구현하는 방법에 대해 알아보자.
SDK를 import 하고 다음 코드를 작성하면 FCM 라이브러리가 Service Worker를 설정해준다. public
안에 포함시켜야 제대로 동작한다.
importScripts("https://www.gstatic.com/firebasejs/8.10.0/firebase-app.js");
importScripts(
"https://www.gstatic.com/firebasejs/8.10.0/firebase-messaging.js"
);
// [1]
const firebaseConfig = {
apiKey: `${API_KEY}`,
projectId: `${PROJECT_ID}`,
messagingSenderId: `${MESSAGING_SENDER_ID}`,
appId: `${APP_ID}`,
};
firebase.initializeApp(firebaseConfig);
const messaging = firebase.messaging();
// [2]
messaging.onBackgroundMessage(messaging, (payload) => {
const notificationTitle = "깜지";
const notificationOptions = {
body: payload,
icon: "/kkamji-logo.png",
};
self.registration.showNotification(notificationTitle, notificationOptions);
});
config
는 Firebase Console에서 확인할 수 있다. onMessage
를 통해 포그라운드에서 메시지를 수신할 수 있다.
import { FirebaseApp, initializeApp } from "firebase/app";
import { getMessaging, onMessage } from "firebase/messaging";
function MyApp(){
useEffect(()=>{
const app = initializeApp(firebaseConfig);
setNotification(app);
}, []);
const setNotification = (app: FirebaseApp) => {
const messaging = getMessaging(app);
onMessage(messaging, (payload) => {});
};
}
로그인한 사용자에게만 알림 전송이 필요하기 때문에, 로그인을 할 때 토큰을 서버로 전달했다. 로그인 환경이 변경되었을 때도 새로운 브라우저에 대한 토큰을 전송할 수 있다.
useEffect(() => {
const messaging = getMessaging(app);
// [1]
getToken(messaging, {
vapidKey: ${VAPID_KEY},
})
.then((currentToken) => {
setFcmToken(currentToken);
})
.catch((err) => {});
}, []);
const onLoginValid: SubmitHandler<LoginValidForm> = async (data) => {
const { email, password } = data;
const loginBody: LoginBody = {
email,
password,
fcmToken,
platform: navigator.platform, // [2]
};
mutateLogin({ loginBody });
};
getToken
에서 VAPID 키를 통해 클라이언트를 식별할 수 있는 JWT를 생성하고, 서버에 전달한다.Web Push를 도입하고 사용자들에게 배포해본 결과, 실제로 사용되기 어려운 기술이라는 것을 느꼈다.
깜지 유저 중 과반수 이상이 아이폰 유저였기 때문에, 해당 기능을 이용할 수 있는 사용자가 적었다. 하지만 현재는 iOS에서도 Web Push를 지원하기 때문에 다시 기대를 걸어볼 수 있을 것 같다.
사실 나도 웹 사이트를 바탕화면에 설치해서 사용해본 경험이 많이 없다. 자주 방문하는 웹 사이트는 북마크를 해놓고 들어가는 플로우가 익숙하다. 깜지는 모든 유저가 스터디원처럼 관리되고 있었기 때문에 설치 독려가 충분히 가능했지만, 범용적 서비스의 경우 사용자가 웹을 화면에 설치하도록 만드는 것이 어렵다고 생각한다.
처음 개발을 했을 때 PC환경에서는 알림을 받을 수 없었다. 그 이유는 PC에서 기본적으로 브라우저 알림이 비허용돼있기 때문이다. 시스템 환경설정에서 다음과 같이 브라우저의 알림을 허용해줘야 알림을 수신할 수 있는데, 웹 사이트의 알림을 수신하기 위해 이 설정을 허용으로 바꿀 유저는 많지 않을 것 같다. 나도 평소에 앱 알림은 대부분 꺼놓는 편이기 때문에.
PWA를 통해 Web Push Notification을 주는 것은 등장한지 오래되지 않은 기술인 만큼 사용자들이 익숙하게 여기기까지 시간이 걸릴 것 같다.
하지만 PWA는 현재 해외에서 많이 사용되고 있다. 우리나라와 다르게 열악한 네트워크 환경을 가진 국가가 많기 때문에, 오프라인 지원 등의 이점이 있는 PWA의 활용도가 높다고 한다. 그런만큼 해당 기술을 학습한 뒤 직접 서비스를 만들어보고, 한계에 부딪혀보는 것도 좋은 경험이었다고 생각한다.
감사합니다^^