Firebase Cloud Messaging(FCM) 완벽 설정 가이드
푸시 알림의 모든 것
Angular + Ionic + Capacitor 프로젝트에 Firebase Cloud Messaging을 연동하는 방법을 실제 프로덕션 환경에서 사용하는 패턴으로 설명한다. 토큰 관리부터 알림 수신 처리, Android/iOS 설정까지 모든 것을 다룬다.
목차
1. Firebase Console 설정
Firebase Console에서 Cloud Messaging을 활성화한다.
1.1 Cloud Messaging 활성화
- 1Firebase Console 접속
- 2프로젝트 선택
- 3좌측 메뉴에서 "Cloud Messaging" 선택
- 4Cloud Messaging API 활성화 (자동으로 활성화됨)
1.2 서버 키 확인
서버에서 푸시 알림을 보낼 때 필요한 서버 키를 확인한다:
- 프로젝트 설정 (⚙️) → 클라우드 메시징 탭
- "클라우드 메시징 API 서버 키" 복사
2. 필요한 패키지 설치
FCM을 사용하기 위해 필요한 패키지를 설치한다.
2.1 Firebase 패키지
Firebase는 이미 설치되어 있다면 생략:
npm install firebase @angular/fire
2.2 Capacitor 플러그인 (선택사항)
네이티브 앱에서 푸시 알림을 받으려면 Capacitor 플러그인이 필요하다:
npm install @capacitor/push-notifications
npx cap sync
@angular/fire/messaging만으로도 충분하다. 네이티브 앱에서만 Capacitor 플러그인이 필요하다.3. AppModule 설정
app.module.ts에 Messaging 모듈을 추가한다.
3.1 Messaging 모듈 추가
import { NgModule } from '@angular/core';
import { provideMessaging, getMessaging } from '@angular/fire/messaging';
import { provideFirebaseApp, initializeApp } from '@angular/fire/app';
import { environment } from 'src/environments/environment';
@NgModule({
imports: [
// ... other imports
// Firebase 초기화
provideFirebaseApp(() => initializeApp(environment.firebaseConfig)),
// Messaging 초기화
provideMessaging(() => getMessaging()),
],
})
export class AppModule {}
getMessaging()는 Firebase App이 먼저 초기화되어 있어야 한다.4. FCM 서비스 구현
FCM 토큰 관리와 알림 수신을 처리하는 서비스를 만든다.
4.1 FCMService 기본 구조
import { Injectable } from '@angular/core';
import { Messaging, getToken, onMessage } from '@angular/fire/messaging';
import { Platform } from '@ionic/angular';
import { Capacitor } from '@capacitor/core';
@Injectable({
providedIn: 'root',
})
export class FCMService {
constructor(
private messaging: Messaging,
private platform: Platform
) {}
/**
* FCM 토큰 가져오기
*/
async getToken(): Promise<string | null> {
try {
// 웹 환경에서만 동작
if (!Capacitor.isNativePlatform()) {
const token = await getToken(this.messaging, {
vapidKey: '[VAPID_KEY]', // Firebase Console에서 발급받은 키
});
return token;
}
// 네이티브 앱은 Capacitor 플러그인 사용
return null;
} catch (error) {
console.error('토큰 가져오기 실패:', error);
return null;
}
}
/**
* 포그라운드에서 알림 수신 처리
*/
onMessage() {
return onMessage(this.messaging);
}
}
4.2 VAPID 키 발급
웹에서 FCM을 사용하려면 VAPID 키가 필요하다:
- Firebase Console → 프로젝트 설정 (⚙️)
- 클라우드 메시징 탭
- "웹 푸시 인증서" 섹션에서 키 생성 또는 복사
5. 토큰 가져오기 및 저장
앱 시작 시 FCM 토큰을 가져와서 Firestore에 저장한다.
5.1 AppComponent에서 토큰 가져오기
import { Component, OnInit } from '@angular/core';
import { FCMService } from './core/services/fcm.service';
import { AuthService } from './core/services/auth.service';
import { DbService } from './core/services/db.service';
@Component({
selector: 'app-root',
templateUrl: 'app.component.html',
})
export class AppComponent implements OnInit {
constructor(
private fcm: FCMService,
private auth: AuthService,
private db: DbService
) {}
async ngOnInit() {
await this.initializeFCM();
}
async initializeFCM() {
// 알림 권한 요청 (웹)
if ('Notification' in window) {
const permission = await Notification.requestPermission();
if (permission === 'granted') {
await this.saveToken();
}
} else {
// 네이티브 앱
await this.saveToken();
}
}
async saveToken() {
try {
const token = await this.fcm.getToken();
if (!token) return;
const user = await this.auth.getUser();
if (!user) return;
// Firestore에 토큰 저장
await this.db.updateAt(`members/${user.uid}`, {
pushId: token,
pushIdUpdatedAt: new Date(),
});
console.log('FCM 토큰 저장 완료:', token);
} catch (error) {
console.error('토큰 저장 실패:', error);
}
}
}
5.2 토큰 갱신 처리
토큰이 갱신될 때 자동으로 저장하도록 처리:
import { onTokenRefresh } from '@angular/fire/messaging';
async initializeFCM() {
// 초기 토큰 가져오기
await this.saveToken();
// 토큰 갱신 감지
onTokenRefresh(this.messaging).subscribe(async (token) => {
console.log('토큰 갱신됨:', token);
await this.saveToken();
});
}
6. 푸시 알림 수신 처리
앱이 포그라운드에 있을 때와 백그라운드에 있을 때 알림을 다르게 처리한다.
6.1 포그라운드 알림 처리
앱이 열려있을 때 알림을 받으면 onMessage로 처리한다:
import { Component, OnInit } from '@angular/core';
import { FCMService } from './core/services/fcm.service';
import { Router } from '@angular/router';
@Component({
selector: 'app-root',
templateUrl: 'app.component.html',
})
export class AppComponent implements OnInit {
constructor(
private fcm: FCMService,
private router: Router
) {}
ngOnInit() {
this.setupMessageListener();
}
setupMessageListener() {
this.fcm.onMessage().subscribe((payload) => {
console.log('포그라운드 알림 수신:', payload);
// 알림 데이터 추출
const notification = payload.notification;
const data = payload.data;
// 커스텀 알림 표시 (선택사항)
if (Notification.permission === 'granted') {
new Notification(notification?.title || '알림', {
body: notification?.body,
icon: '/assets/icon/favicon.png',
});
}
// 알림 클릭 시 페이지 이동
if (data && data.url) {
this.router.navigateByUrl(data.url);
}
});
}
}
6.2 백그라운드 알림 처리 (Service Worker)
앱이 백그라운드에 있을 때는 Service Worker에서 처리한다.
1. src/firebase-messaging-sw.js 파일 생성:
// firebase-messaging-sw.js
importScripts('https://www.gstatic.com/firebasejs/10.7.1/firebase-app-compat.js');
importScripts('https://www.gstatic.com/firebasejs/10.7.1/firebase-messaging-compat.js');
firebase.initializeApp({
apiKey: '[apiKey]',
authDomain: '[authDomain]',
projectId: '[projectId]',
storageBucket: '[storageBucket]',
messagingSenderId: '[messagingSenderId]',
appId: '[appId]',
});
const messaging = firebase.messaging();
// 백그라운드 알림 수신 처리
messaging.onBackgroundMessage((payload) => {
console.log('백그라운드 알림 수신:', payload);
const notificationTitle = payload.notification.title;
const notificationOptions = {
body: payload.notification.body,
icon: '/assets/icon/favicon.png',
};
return self.registration.showNotification(notificationTitle, notificationOptions);
});
2. angular.json에 Service Worker 등록:
{
"projects": {
"app": {
"architect": {
"build": {
"options": {
"serviceWorker": true,
"assets": [
"src/firebase-messaging-sw.js"
]
}
}
}
}
}
}
7. Android 설정
Android 앱에서 FCM을 사용하려면 google-services.json 파일이 필요하다.
7.1 google-services.json 다운로드
- 1Firebase Console → 프로젝트 설정
- 2Android 앱 추가 (또는 기존 앱 선택)
- 3패키지 이름 입력 (예:
com.mycarbon.knc) - 4
google-services.json다운로드
7.2 파일 배치
다운로드한 파일을 다음 위치에 배치:
android/app/google-services.json
7.3 build.gradle 설정
android/build.gradle (프로젝트 레벨):
buildscript {
dependencies {
classpath 'com.google.gms:google-services:4.4.0'
}
}
android/app/build.gradle (앱 레벨):
plugins {
id 'com.android.application'
id 'com.google.gms.google-services' // 추가
}
dependencies {
implementation 'com.google.firebase:firebase-messaging:23.4.0'
}
8. iOS 설정
iOS 앱에서 FCM을 사용하려면 GoogleService-Info.plist 파일이 필요하다.
8.1 GoogleService-Info.plist 다운로드
- 1Firebase Console → 프로젝트 설정
- 2iOS 앱 추가 (또는 기존 앱 선택)
- 3번들 ID 입력 (예:
com.mycarbon.knc) - 4
GoogleService-Info.plist다운로드
8.2 파일 배치
다운로드한 파일을 Xcode 프로젝트에 추가:
ios/App/App/GoogleService-Info.plist
8.3 Push Notifications 활성화
- Xcode에서 프로젝트 열기
- Target 선택 → Signing & Capabilities
- "+ Capability" 클릭 → "Push Notifications" 추가
- "Background Modes" 추가 → "Remote notifications" 체크
8.4 Podfile 설정
ios/App/Podfile에 Firebase 추가:
platform :ios, '13.0'
use_frameworks!
target 'App' do
pod 'Firebase/Messaging'
end
Pod 설치:
cd ios/App
pod install
9. 실전 팁과 주의사항
9.1 토큰 관리 전략
- 로그인 시 토큰 저장: 사용자가 로그인할 때마다 최신 토큰을 저장
- 로그아웃 시 토큰 삭제: 보안을 위해 로그아웃 시 토큰을 제거
- 토큰 갱신 감지:
onTokenRefresh로 자동 갱신
9.2 알림 페이로드 구조
효과적인 알림을 위해 페이로드를 구조화한다:
{
"notification": {
"title": "알림 제목",
"body": "알림 내용"
},
"data": {
"url": "/tabs/home",
"type": "alarm",
"id": "123"
}
}
9.3 자주 하는 실수
- VAPID 키 누락: 웹에서 토큰을 가져오려면 VAPID 키가 필수
- Service Worker 미등록: 백그라운드 알림을 받으려면 Service Worker 필요
- 권한 미요청: 웹에서는 사용자에게 알림 권한을 요청해야 함
- 토큰 미갱신: 토큰이 변경되어도 갱신하지 않으면 알림을 받을 수 없음
9.4 테스트 방법
- 1Firebase Console → Cloud Messaging
- 2"새 알림" 클릭
- 3알림 제목, 내용 입력
- 4대상 선택 (단일 기기 또는 토픽)
- 5"테스트 메시지 보내기" 클릭
마무리
Firebase Cloud Messaging을 설정하면 사용자에게 푸시 알림을 보낼 수 있다. 웹, Android, iOS 모두에서 동작하도록 설정하는 것이 중요하다.
토큰 관리와 알림 수신 처리를 제대로 구현하면 사용자 경험이 크게 향상된다. 특히 토큰 갱신을 자동으로 처리하고, 알림 클릭 시 적절한 페이지로 이동하는 것이 중요하다.
- Firebase Console에서 Cloud Messaging 활성화
provideMessaging()로 Messaging 모듈 초기화- 웹에서는 VAPID 키 필요, 네이티브는 설정 파일 필요
- 토큰은 로그인 시 저장, 로그아웃 시 삭제
- 포그라운드는
onMessage(), 백그라운드는 Service Worker
'개발 > FRONT' 카테고리의 다른 글
| Android Error : NullPointerException 완전 정리 (0) | 2025.12.23 |
|---|---|
| 휴대폰 본인인증 완벽 구현 가이드 - 아임포트로 끝내는 인증 시스템 예제 (0) | 2025.12.21 |
| async/await로 완성하는 비동기 조회 마스터 클래스 - Promise 지옥에서 벗어나기 (0) | 2025.12.21 |
| Firebase Storage 파일 업로드 완벽 마스터하기 - 실전 코드로 배우는 업로드 전략 (0) | 2025.12.21 |
| Ionic 프로젝트의 핵심 설정 파일, ionic.config.json 완벽 가이드 (0) | 2025.12.21 |