웹 푸시 구현 예제
npm install @nativify/notifications firebase rxjs
// services/notification.service.ts
import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs';
import { getNotificationService } from '@nativify/notifications';
export interface Notification {
id: number;
title: string;
body: string;
timestamp: Date;
}
@Injectable({ providedIn: 'root' })
export class NotificationService {
private service: any = null;
// RxJS Subjects
private notificationsSubject = new BehaviorSubject([]);
private tokenSubject = new BehaviorSubject(null);
private permissionSubject = new BehaviorSubject('default');
// Public Observables
public notifications$ = this.notificationsSubject.asObservable();
public token$ = this.tokenSubject.asObservable();
public permission$ = this.permissionSubject.asObservable();
constructor() {}
// Firebase 설정
private initFirebase(): void {
(window as any).firebaseConfig = {
apiKey: 'YOUR_API_KEY',
authDomain: 'YOUR_PROJECT.firebaseapp.com',
projectId: 'YOUR_PROJECT_ID',
storageBucket: 'YOUR_PROJECT.appspot.com',
messagingSenderId: 'YOUR_SENDER_ID',
appId: 'YOUR_APP_ID',
vapidKey: 'YOUR_VAPID_KEY'
};
}
// 서비스 초기화
async initialize(): Promise {
try {
this.initFirebase();
this.service = getNotificationService();
await this.service.initialize();
// 메시지 수신 리스너 등록
this.service.onMessageReceived(this.handleMessage.bind(this));
} catch (error) {
console.error('초기화 실패:', error);
}
}
// 권한 요청
async requestPermission(): Promise {
if (!this.service) return;
try {
const permission = await this.service.requestPermission();
this.permissionSubject.next(permission);
if (permission === 'granted') {
const token = await this.service.getToken();
this.tokenSubject.next(token);
console.log('FCM Token:', token);
// 서버에 토큰 등록
await this.registerToken(token);
}
} catch (error) {
console.error('권한 요청 실패:', error);
}
}
// 토큰 서버 등록
private async registerToken(token: string): Promise {
const appId = 'delivery_app_001'; // Console 앱 ID
const appUserId = 'user123'; // 실제 앱 사용자 ID
try {
await this.service.registerUserToken(
appId,
appUserId,
'https://your-server.com/api/notifications'
);
} catch (error) {
console.error('토큰 등록 실패:', error);
}
}
// 메시지 수신 처리
private handleMessage(message: any): void {
const notification: Notification = {
id: Date.now(),
title: message.notification?.title || '알림',
body: message.notification?.body || '',
timestamp: new Date()
};
const current = this.notificationsSubject.value;
this.notificationsSubject.next([notification, ...current]);
}
}
// app.component.ts
import { Component, OnInit } from '@angular/core';
import { NotificationService, Notification } from './services/notification.service';
import { Observable } from 'rxjs';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
notifications$: Observable;
token$: Observable;
permission$: Observable;
constructor(private notificationService: NotificationService) {
this.notifications$ = this.notificationService.notifications$;
this.token$ = this.notificationService.token$;
this.permission$ = this.notificationService.permission$;
}
async ngOnInit() {
await this.notificationService.initialize();
}
requestPermission() {
this.notificationService.requestPermission();
}
}
<!-- app.component.html -->
<div class="app">
<h1>웹 푸시 알림 데모</h1>
<!-- 권한 요청 버튼 -->
<button
*ngIf="(permission$ | async) !== 'granted'"
(click)="requestPermission()"
class="btn-primary"
>
알림 권한 요청
</button>
<!-- FCM 토큰 표시 -->
<div *ngIf="token$ | async as token" class="token-display">
<strong>FCM Token:</strong>
<code>{{ token }}</code>
</div>
<!-- 알림 목록 -->
<div class="notifications">
<h2>받은 알림</h2>
<div
*ngFor="let notif of notifications$ | async"
class="notification-item"
>
<h3>{{ notif.title }}</h3>
<p>{{ notif.body }}</p>
<small>{{ notif.timestamp | date:'medium' }}</small>
</div>
<p *ngIf="(notifications$ | async)?.length === 0" class="empty">
받은 알림이 없습니다.
</p>
</div>
</div>
.notification-item {
background: #f7fafc;
border-left: 4px solid #dd0031;
padding: 15px;
margin: 10px 0;
border-radius: 8px;
}
.token-display {
background: #ebf8ff;
padding: 15px;
border-radius: 8px;
margin: 20px 0;
}
.btn-primary {
background: #dd0031;
color: white;
padding: 12px 24px;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 16px;
}
environment.ts에 Firebase 설정 추가public/firebase-messaging-sw.js 생성npm installng serve