chyam

[Flutter+ Firebase] - 서버 연동 FCM 푸시 알림 본문

Web & Backend

[Flutter+ Firebase] - 서버 연동 FCM 푸시 알림

chyam_eun 2026. 5. 1. 15:34

먼저 Firebase에서 플러터를 선택해주고,

npm install -g firebase-tools

필수 CLI 도구를 설치해줍니다. 그런 뒤, 플러터 프로젝트의 터미널에서 아래 코드로 로그인을 해줍니다.

firebase login

그다음, 아래를 순서대로 해줍니다. 

그러면 lib.firebase_options.dart가 생성되는데, 이는 .gitignore에 추가해서 올라가지 않도록 해주었습니다.

파이어베이스의 프로젝트 설정-일반에 들어가면 아래에 google-services.json이 있습니다. 이를 다운로드해줍니다. 해당 파일을, android/app안에 넣어줍니다. ( configure을 하면 자동으로 설정되기도합니다. 혹시나 안됐다면 하시면됩니당)


그다음, pubspec.yaml의 dependencies에 아래 부분을 추가해줍니다! (버전이 다를수도 있습니다)

  firebase_core: ^4.7.0 # 파이어베이스 엔진
  firebase_auth: ^6.3.0 # 사용자 인증(필요 시)
  flutter_dotenv: ^6.0.1 # 환경변수 관리
  http: ^1.2.1 # FastAPI 서버로 토큰 전송
  firebase_messaging: ^16.2.0 # FCM 알림 수신 패키지

 

 

서버가 누구에게 알림을 보낼지 알려주기 위해 기기의 고유 토큰을 뽑아서 서버에 전송해야합니다. 아래와 같이 dart 파일에 추가해줍니다. 

...
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:http/http.dart' as http; // 서버 통신
import 'package:flutter_dotenv/flutter_dotenv.dart';
...




// FCM 토큰 가져오기
String? token = await FirebaseMessaging.instance.getToken();

// 서버 전송 로직
var request = http.MultipartRequest('POST', Uri.parse('your_url/upload'));
if (token != null) {
  request.fields['device_token'] = token; // 서버로 토큰 배달!
}
await request.send();

 

 

또한 main.dart의 main에서 먼저 파이어베이스를 초기화해야합니다.

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await dotenv.load(fileName: ".env");
  // Firebase 초기화 완료될 때까지 대기(await)
  await Firebase.initializeApp(
    options: DefaultFirebaseOptions.currentPlatform,
  );

  // 준비가 다 끝나면 앱을 실행
  runApp(const MyApp());
}

 

 

그리고, 서버에서 알림을 보냈을때 앱이 어떻게 반응할지 정해줍니다.

FirebaseMessaging.onMessage.listen((RemoteMessage message) {
      print('앱 실행 중 알림 수신: ${message.notification?.title}');
    });

위의 내용만 한다면, 앱이 켜져있을때만 알림이 오거나, 시스템 권한이 없어서 알림이 아예 오지 않을 수도 있습니다. 먼저, 알림을 보내기위해서 명시적으로 권한을 선언해줍니다.

android/app/src/main/AndroidManifest.xml에서 맨위의 밑에 아래와같이 추가해줍니다.

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
    ...

 

그리고 앱이 꺼져있을때(백그라운드) 알림을 받기 위해, main.dart 최상단에 백그라운드 핸들러를 정의해줍니다!

@pragma('vm:entry-point')
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
  await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
  print("백그라운드 메시지 처리 중: ${message.messageId}");
}

 

또한 main 함수 안에 사용자에게 권한을 요청하는 코드와 백그라운드 핸들러 연결 코드를 덧붙여서 완성해줍니다.

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await dotenv.load(fileName: ".env");
  
  await Firebase.initializeApp(
    options: DefaultFirebaseOptions.currentPlatform,
  );

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

  // 사용자에게 알림 권한 요청
  FirebaseMessaging messaging = FirebaseMessaging.instance;
  await messaging.requestPermission(
    alert: true,
    badge: true,
    sound: true,
  );

  runApp(const MyApp());
}

 

이제 플러터에서 설정하는것은 끝입니다! 


이제 서버에서 처리가 끝난 뒤, 아까 전달받은 토큰으로 알림을 보내는 로직을 작성해야합니다.

 

먼저, 파이어베이스 프로젝트 설정- 서비스 계정에서 python을 선택하고 새 비공개키 생성을 눌러서 serviceAccountKey로 이름을 변경해줍니다! 이또한 .gitignore에 추가해주어야합니다.

그리고 tasks.py(파이어베이스가 필요한 코드)에 아래와 같이 해줍니다.

import firebase_admin
from firebase_admin import credentials, messaging

# Firebase Admin 초기화
if not firebase_admin._apps:
    cred = credentials.Certificate("serviceAccountKey.json")
    firebase_admin.initialize_app(cred)

# ... 비동기 작업 로직 ...

def send_push_notification(token, video_name):
    if not token:
        print("토큰이 없어 알림을 보낼 수 없습니다.")
        return

    try:
        # 알림 메시지 구성
        message = messaging.Message(
            notification=messaging.Notification(
                title='완료!',
                body=f'[{video_name}] 처리가 끝났습니다.',
            ),
            token=token, # 플러터에서 받아온 바로 그 토큰
        )
        # FCM 서버로 알림 전송 요청
        response = messaging.send(message)
        print(f"알림 발송 성공: {response}")
    except Exception as e:
        print(f"알림 발송 실패: {e}")

만약 알림이 안온다면 프로젝트 ID가 일치하는지 확인해야합니다! ( 플러터 프로젝트의 id와 서버에있는 id )