웹 개발자를 위한 가이드

네이티브 앱에서 푸시 받기

네이티브 앱이 받은 푸시 알림을 WebView에서
web-bridge.js로 간단하게 처리하세요

동작 원리

네이티브 앱과 WebView 간의 푸시 알림 흐름

Firebase
→
네이티브 앱 (FCM)
→
web-bridge.js
→
WebView (당신의 웹앱)
네이티브 앱이 푸시를 받으면 자동으로 WebView로 전달됩니다
웹 개발자가 할 일:
네이티브 앱 코드는 건드리지 않습니다! web-bridge.js만 사용하면 끝입니다.

즉시 사용

네이티브 앱이 이미 FCM을 구현했다면 바로 사용 가능

설정 불필요

Firebase 설정, FCM 토큰 등 모두 Nativify가 처리

네이티브 성능

OS 레벨 푸시 알림의 빠른 성능과 배터리 효율

간단한 API

단 몇 줄의 코드로 푸시 수신 및 처리

3단계 구현 가이드

웹 개발자 관점에서 푸시 받기

전제 조건:
네이티브 앱 개발자가 이미 FCM을 구현해두었어야 합니다.
(pubspec.yaml에 firebase_messaging 패키지, FCM 토큰 발급 등)
1

web-bridge.js 로드

네이티브 앱 개발자가 제공한 web-bridge.js 파일을 HTML에 추가합니다.

<!-- HTML에 스크립트 추가 --> <script src="./web-bridge.js"></script> <!-- 또는 NPM 사용 --> <script> import WebBridge from './web-bridge.js'; </script>
참고: 네이티브 앱 빌드에 포함된 파일이므로 별도 설치 불필요합니다.
2

WebBridge 초기화

WebBridge 인스턴스를 생성합니다. FCM 설정은 필요 없습니다!

// JavaScript const bridge = new WebBridge({ debug: true }); // 네이티브 연결 확인 if (bridge.isAvailable()) { console.log('✅ 네이티브 앱 연결됨'); } else { console.log('⚠️ 네이티브 앱이 아님 (브라우저 모드)'); }

또는 Vue/React에서:

// Vue 3 Composition API import { ref, onMounted } from 'vue'; const bridge = ref(null); onMounted(() => { bridge.value = new WebBridge(); }); // React import { useEffect, useState } from 'react'; function App() { const [bridge, setBridge] = useState(null); useEffect(() => { setBridge(new WebBridge()); }, []); }
3

푸시 메시지 수신 리스너 등록

네이티브 앱이 푸시를 받으면 WebView로 자동 전달됩니다. 리스너만 등록하면 끝!

// 푸시 메시지 수신 bridge.on('response', (data) => { if (data.type === 'PUSH_NOTIFICATION') { console.log('📬 푸시 수신:', data); // 알림 정보 const title = data.title; const body = data.body; const customData = data.data; // 추가 데이터 // UI 업데이트 showNotificationBanner(title, body); // 배지 업데이트 updateBadgeCount(data.badge); // 사운드 재생 (선택사항) playNotificationSound(); } }); // 알림 배너 표시 함수 function showNotificationBanner(title, body) { // 화면 상단에 배너 표시 const banner = document.createElement('div'); banner.className = 'notification-banner'; banner.innerHTML = ` <strong>${title}</strong> <p>${body}</p> `; document.body.appendChild(banner); // 3초 후 자동 제거 setTimeout(() => banner.remove(), 3000); }
완료! 이제 네이티브 앱이 푸시를 받으면 WebView에서도 즉시 처리됩니다.

고급 사용법

푸시 데이터 활용

푸시 메시지에 포함된 커스텀 데이터로 다양한 동작을 수행할 수 있습니다.

bridge.on('response', (data) => { if (data.type === 'PUSH_NOTIFICATION') { const customData = data.data; // 푸시 타입에 따라 다른 동작 switch (customData.type) { case 'NEW_MESSAGE': // 메시지 페이지로 이동 router.push(`/messages/${customData.messageId}`); break; case 'NEW_ORDER': // 주문 상세 페이지로 이동 router.push(`/apps/${customData.appId}`); break; case 'PROMOTION': // 프로모션 모달 표시 showPromotionModal(customData.promotionId); break; default: // 기본 알림 배너 표시 showNotificationBanner(data.title, data.body); } } });

알림 권한 요청

사용자에게 알림 권한을 요청할 수 있습니다 (네이티브 브릿지를 통해).

// 네이티브 앱에 권한 요청 async function requestNotificationPermission() { try { const response = await bridge._request('REQUEST_NOTIFICATION_PERMISSION'); console.log('알림 권한:', response); } catch (error) { console.error('권한 요청 실패:', error); } }

로컬 알림 표시

WebView에서 네이티브 브릿지를 통해 로컬 알림을 표시할 수 있습니다.

// 네이티브 브릿지를 통해 로컬 알림 표시 async function showLocalNotification(title, body) { try { await bridge.showNotification(title, body); console.log('✅ 알림 표시 완료'); } catch (error) { console.error('❌ 알림 표시 실패:', error); } } // 사용 예시 showLocalNotification('배달 완료', '주문하신 음식이 도착했습니다!');

프레임워크별 예제

Vanilla JS, Vue, React, Angular, Svelte에서 사용하기

Vanilla JavaScript

// main.js // 알림 관리 클래스 class NotificationManager { constructor() { this.bridge = null; // WebBridge 인스턴스 this.notifications = []; // 받은 알림 목록 } // WebBridge 초기화 init() { this.bridge = new WebBridge(); // 네이티브 앱으로부터 메시지 수신 리스너 등록 this.bridge.on('response', this.handlePush.bind(this)); this.render(); } // 푸시 메시지 처리 handlePush(data) { if (data.type === 'PUSH_NOTIFICATION') { // 새 알림을 목록 맨 앞에 추가 this.notifications.unshift({ id: Date.now(), title: data.title, body: data.body, data: data.data, }); this.render(); // UI 업데이트 } } // UI 렌더링 render() { const container = document.getElementById('notifications'); // 알림 목록을 HTML로 변환 container.innerHTML = this.notifications.map(notif => ` <div class="notification-item"> <h3>${notif.title}</h3> <p>${notif.body}</p> </div> `).join(''); } } // 앱 초기화 const manager = new NotificationManager(); manager.init();

Vue 3

// useNotification.js (Composable) import { ref, onMounted, onUnmounted } from 'vue'; // 알림 관리 Composable export function useNotification() { const bridge = ref(null); // WebBridge 인스턴스 const notifications = ref([]); // 알림 목록 (반응형) // 푸시 메시지 처리 함수 const handlePush = (data) => { if (data.type === 'PUSH_NOTIFICATION') { // 새 알림을 목록 맨 앞에 추가 notifications.value.unshift({ id: Date.now(), title: data.title, body: data.body, data: data.data, timestamp: new Date(), }); } }; // 컴포넌트 마운트 시 WebBridge 초기화 onMounted(() => { bridge.value = new WebBridge(); bridge.value.on('response', handlePush); // 리스너 등록 }); // 컴포넌트 언마운트 시 리스너 정리 onUnmounted(() => { if (bridge.value) { bridge.value.off('response', handlePush); } }); return { notifications }; // 알림 목록 반환 } // App.vue <script setup> import { useNotification } from './composables/useNotification'; // Composable 사용 const { notifications } = useNotification(); </script> <template> <!-- 알림 목록 표시 --> <div v-for="notif in notifications" :key="notif.id"> <h3>{{ notif.title }}</h3> <p>{{ notif.body }}</p> </div> </template>

React

// useNotification.js (Hook) import { useState, useEffect } from 'react'; // 알림 관리 Custom Hook export function useNotification() { const [bridge, setBridge] = useState(null); // WebBridge 인스턴스 const [notifications, setNotifications] = useState([]); // 알림 목록 // 컴포넌트 마운트 시 실행 useEffect(() => { const WebBridge = new WebBridge(); setBridge(WebBridge); // 푸시 메시지 처리 함수 const handlePush = (data) => { if (data.type === 'PUSH_NOTIFICATION') { // 상태 업데이트: 새 알림을 목록 맨 앞에 추가 setNotifications(prev => [{ id: Date.now(), title: data.title, body: data.body, data: data.data, }, ...prev]); } }; // 네이티브 메시지 리스너 등록 WebBridge.on('response', handlePush); // 컴포넌트 언마운트 시 리스너 정리 return () => { WebBridge.off('response', handlePush); }; }, []); // 빈 의존성 배열: 한 번만 실행 return { notifications }; // 알림 목록 반환 } // App.jsx function App() { const { notifications } = useNotification(); // Hook 사용 return ( <div> {notifications.map(notif => ( <div key={notif.id}> <h3>{notif.title}</h3> <p>{notif.body}</p> </div> ))} </div> ); }

Angular

// notification.service.ts import { Injectable } from '@angular/core'; import { BehaviorSubject } from 'rxjs'; // \uc54c\ub9bc \uad00\ub9ac \uc11c\ube44\uc2a4 (Singleton) @Injectable({ providedIn: 'root' }) export class NotificationService { private bridge: any; // RxJS Subject\ub85c \uc54c\ub9bc \ubaa9\ub85d \uad00\ub9ac private notificationsSubject = new BehaviorSubject<any[]>([]); public notifications$ = this.notificationsSubject.asObservable(); // WebBridge \ucd08\uae30\ud654 init() { this.bridge = new (window as any).WebBridge(); // 네이티브 메시지 리스너 등록 this.bridge.on('response', (data: any) => { if (data.type === 'PUSH_NOTIFICATION') { const current = this.notificationsSubject.value; // \uc0c8 \uc54c\ub9bc\uc744 \ubaa9\ub85d \ub9e8 \uc55e\uc5d0 \ucd94\uac00 this.notificationsSubject.next([{ id: Date.now(), title: data.title, body: data.body, }, ...current]); } }); } } // app.component.ts @Component({ selector: 'app-root', template: ` <!-- \uc54c\ub9bc \ubaa9\ub85d \ud45c\uc2dc (async pipe \uc0ac\uc6a9) --> <div *ngFor="let notif of notifications$ | async"> <h3>{{ notif.title }}</h3> <p>{{ notif.body }}</p> </div> ` }) export class AppComponent implements OnInit { notifications$ = this.notificationService.notifications$; constructor(private notificationService: NotificationService) {} ngOnInit() { this.notificationService.init(); } // \ucd08\uae30\ud654 }

Svelte

// App.svelte <script> import { onMount, onDestroy } from 'svelte'; import { writable } from 'svelte/store'; // 알림 목록 저장소 (반응형) const notifications = writable([]); let bridge; // 푸시 메시지 처리 함수 function handlePush(data) { if (data.type === 'PUSH_NOTIFICATION') { // 저장소 업데이트: 새 알림을 목록 맨 앞에 추가 notifications.update(items => [{ id: Date.now(), title: data.title, body: data.body, }, ...items]); } } // 컴포넌트 마운트 시 WebBridge 초기화 onMount(() => { bridge = new WebBridge(); bridge.on('response', handlePush); // 리스너 등록 }); // 컴포넌트 파괴 시 리스너 정리 onDestroy(() => { if (bridge) bridge.off('response', handlePush); }); </script> {#each $notifications as notif (notif.id)} <div> <h3>{notif.title}</h3> <p>{notif.body}</p> </div> {/each}

지금 바로 시작하세요!

네이티브 앱의 푸시를 WebView에서 쉽게 받으세요