이슈 발생
Flutter 앱 개발 중 iOS 푸시알림 설정을 구현하면서 생긴 이슈이다. 잘 동작하던 앱이었는데 flutter_local_notifications나 flutter_foreground_task 같은 라이브러리를 추가하거나 iOS Deployment Target을 15.0으로 올린 이후 갑자기 FCM 메시지가 수신되지 않는 이슈가 발생했다.
문제 상황
- Podfile 업데이트 및 iOS 타겟 버전을 다른 라이브러리에 맞게 15.0으로 사향 조정
- APNS 토큰은 정상적으로 발급이 되나 onMessage, onBackgroundMessage에서 로그가 전혀 찍히지 않고 Firebase Console에서 테스트 메시지를 보내도 반응이 없었음
원인 분석
1. iOS 앱의 생명주기를 관리하는 AppDelegate는 하나뿐인데 firebase_messaging, flutter_local_notifications, flutter_foreground_task 등 여러 플러그인이 서로 "내가 알림 권한(Delegate)을 처리할게!" 라고 경쟁
기본적으로 Firebase는 Method Swizzling(자동으로 메서드를 가로채는 기술)을 통해 APNs 토큰을 가져가는데, iOS 버전이 올라가고 다른 플러그인들이 업데이트되면서 Firebase의 자동 연결 고리가 끊어진 것이라고 원인을 분석했다.
2. 또한, APNs 환경 불일치를 원인으로 생각했다.
- Debug 빌드: Apple의 Sandbox (개발용) APNs 서버를 사용
- Release 빌드: Apple의 Production (배포용) APNs 서버를 사용
Firebase SDK가 업데이트되면서 자동으로 환경을 감지하지 못하고, Debug 빌드임에도 Production 서버로 메시지를 보내는 경우가 발생했다. 애플 서버 입장에서는 "샌드박스용 토큰인데 왜 프로덕션으로 보냄?" 하고 메시지를 폐기해버린 것이 문제의 원인이라고 생각했다.
해결 방법
Firebase의 Method Swozzling 기능을 수동으로 명확하게 처리해줬다.
STEP 1.
일단 Xcode 설정을 재확인해보자. Target 버전을 변경하면 그에 따라 Xcode 설정이 풀리는 경우가 있다.
Runner -> Signing & Capabilities 탭에서 다음 두 가지가 켜져 있는지 아래 이미지처럼 확인해본다.
1) Push Notifications: 없으면 + Capability로 추가.
2) Background Modes: Remote notifications 체크 확인.

STEP 2.
ios/Runner/Info.plist 파일을 열어 Firebase가 자동으로 AppDelegate를 건드리지 못하게 설정했다.
<key>FirebaseAppDelegateProxyEnabled</key>
<false/>
STEP 3.
AppDelegate.swift에서 APNs 토큰을 직접 Firebase에 꽂아준다. 이 때, Debug 모드일 때는 .sandbox라고 명시해주는 것이 핵심이다.
import Flutter
import UIKit
import flutter_local_notifications
import flutter_foreground_task
// 👇 Firebase 모듈 추가
import Firebase
import FirebaseMessaging
@main
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
// 플러그인 등록
GeneratedPluginRegistrant.register(with: self)
// Foreground Task 등록 (사용하는 경우)
SwiftFlutterForegroundTaskPlugin.setPluginRegistrantCallback { registry in
GeneratedPluginRegistrant.register(with: registry)
}
// 알림 Delegate 설정
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().delegate = self as? UNUserNotificationCenterDelegate
}
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
// APNs 토큰 수동 매핑 로직 추가
override func application(_ application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
// 1. 빌드 모드에 따라 토큰 타입(Sandbox/Prod) 강제 지정
#if DEBUG
// 개발(Debug) 모드 -> Sandbox (aps-environment: development)
Messaging.messaging().setAPNSToken(deviceToken, type: .sandbox)
#else
// 배포(Release) 모드 -> Prod
Messaging.messaging().setAPNSToken(deviceToken, type: .prod)
#endif
// 2. 다른 플러그인들도 토큰을 쓸 수 있게 부모 메서드 호출
super.application(application, didRegisterForRemoteNotificationsWithDeviceToken: deviceToken)
}
}
마무리
이제 기존앱을 삭제하고 flutter clean, flutter run 후 확인해보고ㅓ
'Flutter' 카테고리의 다른 글
| [Flutter] Widget, Element, RenderObject 정리 (0) | 2025.11.17 |
|---|




