IT기술/플러터 (flutter)

Flutter에서 Firebase Cloud Messaging(FCM)을 활용한 푸시 알림 완벽 구현 가이드

후스파 2025. 7. 4. 10:59
반응형

모바일 앱에서 사용자 참여도를 높이는 가장 효과적인 방법 중 하나가 바로 푸시 알림입니다. Firebase Cloud Messaging(FCM)을 사용하면 Flutter 앱에서 Android, iOS, 웹 플랫폼 모두에 일관된 푸시 알림을 구현할 수 있습니다. 이번 포스팅에서는 2025년 최신 정보를 바탕으로 FCM 푸시 알림을 단계별로 구현하는 방법을 자세히 알아보겠습니다.


Firebase 프로젝트 설정

Firebase 프로젝트 생성

먼저 Firebase 콘솔에 접속하여 새 프로젝트를 생성합니다.

  1. Firebase 콘솔 접속
  2. 프로젝트 추가 클릭
  3. 프로젝트 이름 입력 (예: "push-notifications")
  4. Google 애널리틱스 설정 (선택사항)
  5. 프로젝트 만들기 클릭

앱 등록 및 구성 파일 다운로드

Android 설정:

  1. Android 아이콘 클릭
  2. 패키지 이름 입력 (android/app/src/main/AndroidManifest.xml에서 확인 가능)
  3. google-services.json 파일 다운로드
  4. 파일을 android/app/ 디렉토리에 배치

iOS 설정:

  1. iOS 아이콘 클릭
  2. 번들 ID 입력
  3. GoogleService-Info.plist 파일 다운로드
  4. Xcode에서 Runner 프로젝트에 파일 추가

Flutter 프로젝트 설정

의존성 추가

pubspec.yaml 파일에 필요한 패키지들을 추가합니다:

dependencies:
  firebase_core: ^3.14.0
  firebase_messaging: ^15.2.7
  flutter_local_notifications: ^19.1.0

터미널에서 의존성을 설치합니다:

flutter pub get

Firebase 초기화

main.dart 파일을 수정하여 Firebase를 초기화합니다:

import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';

// 백그라운드 메시지 핸들러
@pragma('vm:entry-point')
Future _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
  await Firebase.initializeApp();
  print('백그라운드 메시지 처리: ${message.messageId}');
}

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();

  // 백그라운드 메시지 핸들러 등록
  FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);

  runApp(MyApp());
}

푸시 알림 핸들링 구현

권한 요청 및 FCM 토큰 획득

사용자에게 알림 권한을 요청하고 FCM 토큰을 획득합니다:

class NotificationService {
  static final FirebaseMessaging _firebaseMessaging = FirebaseMessaging.instance;

  // 알림 권한 요청
  static Future requestPermission() async {
    NotificationSettings settings = await _firebaseMessaging.requestPermission(
      alert: true,
      badge: true,
      sound: true,
      provisional: false,
    );

    print('권한 상태: ${settings.authorizationStatus}');
  }

  // FCM 토큰 획득
  static Future getToken() async {
    String? token = await _firebaseMessaging.getToken();
    print('FCM Token: $token');
    return token;
  }
}

알림 리스너 설정

포그라운드, 백그라운드, 종료 상태에서의 알림을 처리합니다:

class NotificationHandler {
  static void setupInteractedMessage() {
    // 포그라운드 메시지 처리
    FirebaseMessaging.onMessage.listen((RemoteMessage message) {
      print('포그라운드 메시지 수신: ${message.notification?.title}');
      _showLocalNotification(message);
    });

    // 백그라운드에서 알림 탭으로 앱 열기
    FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
      print('알림으로 앱 열기: ${message.notification?.title}');
      _handleNotificationTap(message);
    });
  }

  static void _showLocalNotification(RemoteMessage message) {
    // 로컬 알림 표시 로직
  }

  static void _handleNotificationTap(RemoteMessage message) {
    // 알림 탭 처리 로직
  }
}

로컬 알림 표시

포그라운드 상태에서 알림을 표시하기 위해 로컬 알림을 구현합니다:

import 'package:flutter_local_notifications/flutter_local_notifications.dart';

class LocalNotificationService {
  static final FlutterLocalNotificationsPlugin _notificationsPlugin = 
      FlutterLocalNotificationsPlugin();

  static Future initialize() async {
    const AndroidInitializationSettings initializationSettingsAndroid =
        AndroidInitializationSettings('@mipmap/ic_launcher');

    const DarwinInitializationSettings initializationSettingsIOS =
        DarwinInitializationSettings(
          requestSoundPermission: true,
          requestBadgePermission: true,
          requestAlertPermission: true,
        );

    const InitializationSettings initializationSettings =
        InitializationSettings(
          android: initializationSettingsAndroid,
          iOS: initializationSettingsIOS,
        );

    await _notificationsPlugin.initialize(initializationSettings);
  }

  static Future showNotification(RemoteMessage message) async {
    const AndroidNotificationDetails androidPlatformChannelSpecifics =
        AndroidNotificationDetails(
          'high_importance_channel',
          'High Importance Notifications',
          channelDescription: '이 채널은 중요한 알림에 사용됩니다.',
          importance: Importance.max,
          priority: Priority.high,
          showWhen: false,
        );

    const NotificationDetails platformChannelSpecifics =
        NotificationDetails(android: androidPlatformChannelSpecifics);

    await _notificationsPlugin.show(
      0,
      message.notification?.title,
      message.notification?.body,
      platformChannelSpecifics,
    );
  }
}

플랫폼별 추가 설정

Android 설정

android/app/build.gradle 파일에 Google Services 플러그인을 추가합니다:

apply plugin: 'com.google.gms.google-services'

android/build.gradle 파일의 dependencies에 추가:

dependencies {
    classpath 'com.google.gms:google-services:4.4.0'
}

iOS 설정

ios/Runner/AppDelegate.swift 파일을 수정합니다:

import UIKit
import Flutter
import Firebase

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    FirebaseApp.configure()

    if #available(iOS 10.0, *) {
      UNUserNotificationCenter.current().delegate = self as UNUserNotificationCenterDelegate
    }

    GeneratedPluginRegistrant.register(with: self)
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
}

Xcode에서 Signing & CapabilitiesPush Notifications 기능을 추가해야 합니다.


완전한 구현 예제

다음은 모든 기능을 통합한 완전한 예제입니다:

import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';

class PushNotificationApp extends StatefulWidget {
  @override
  _PushNotificationAppState createState() => _PushNotificationAppState();
}

class _PushNotificationAppState extends State {
  String? _token;

  @override
  void initState() {
    super.initState();
    _initializeNotifications();
  }

  Future _initializeNotifications() async {
    // 권한 요청
    await FirebaseMessaging.instance.requestPermission();

    // 토큰 획득
    String? token = await FirebaseMessaging.instance.getToken();
    setState(() {
      _token = token;
    });

    // 메시지 리스너 설정
    FirebaseMessaging.onMessage.listen((RemoteMessage message) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('알림 수신: ${message.notification?.title}')),
      );
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('푸시 알림 데모'),
        backgroundColor: Colors.blue,
      ),
      body: Padding(
        padding: EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            Card(
              child: Padding(
                padding: EdgeInsets.all(16.0),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      'FCM 토큰:',
                      style: TextStyle(fontWeight: FontWeight.bold),
                    ),
                    SizedBox(height: 8),
                    Text(
                      _token ?? '토큰을 가져오는 중...',
                      style: TextStyle(fontSize: 12),
                    ),
                  ],
                ),
              ),
            ),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: () async {
                String? newToken = await FirebaseMessaging.instance.getToken();
                setState(() {
                  _token = newToken;
                });
              },
              child: Text('토큰 새로고침'),
            ),
          ],
        ),
      ),
    );
  }
}

테스트 방법

Firebase 콘솔에서 테스트

  1. Firebase 콘솔 → Cloud Messaging 메뉴
  2. 새 알림 작성 클릭
  3. 제목과 내용 입력
  4. 대상 선택 (특정 토큰 또는 주제)
  5. 게시 클릭

cURL을 사용한 테스트

curl -X POST --header "Authorization: key=" \
    --header "Content-Type: application/json" \
    https://fcm.googleapis.com/fcm/send \
    -d '{
      "to":"",
      "notification":{
        "title":"테스트 알림",
        "body":"FCM 테스트가 성공했습니다!"
      }
    }'

주요 이슈 해결

일반적인 문제들

iOS에서 알림이 오지 않는 경우:

  • Xcode에서 Push Notifications capability 추가 확인
  • 개발자 계정의 APNs 인증서 설정 확인

백그라운드에서 알림을 받지 못하는 경우:

  • Background App Refresh 설정 확인
  • onBackgroundMessage 핸들러 등록 확인

토큰이 생성되지 않는 경우:

  • Firebase.initializeApp() 호출 확인
  • 네트워크 연결 상태 확인
  • 구성 파일 위치 확인

마무리

Flutter에서 Firebase Cloud Messaging을 활용한 푸시 알림 구현은 몇 가지 핵심 단계를 정확히 따르면 비교적 간단하게 구현할 수 있습니다. Firebase 프로젝트 설정부터 플랫폼별 구성, 권한 요청, 메시지 핸들링까지 각 단계를 꼼꼼히 진행하는 것이 중요합니다.

이렇게 구현된 푸시 알림 시스템을 통해 실시간 업데이트, 마케팅 메시지, 개인화된 알림 등 다양한 사용자 참여 기능을 앱에 추가할 수 있습니다. FCM의 강력한 기능들을 활용하여 사용자 경험을 한층 더 향상시켜보세요.

앞으로도 Flutter와 Firebase의 다양한 기능들을 적극 활용하여 더욱 스마트하고 사용자 친화적인 모바일 앱을 개발해나가시기 바랍니다.

 

 

 

[Flutter] 플러터와 피그마 연동하여 디자인을 코드로 변환하는 실전 가이드

플러터(Flutter)와 피그마(Figma)의 연동은 디자이너와 개발자 모두에게 생산성 혁신을 가져다주는 핵심 트렌드입니다. 이 글에서는 피그마에서 디자인한 UI를 플러터 코드로 자동 변환하는 대표적

hoosfa.tistory.com

 

반응형