[firebase_messaging]: iOS plugin labels the APNs token as Prod on every non-DEBUG build, so development-signed release builds register a sandbox token as production and FCM sends fail (invalid-argument) on about half the launches
Maintainer thường phản hồi trong vòng 1 ngày
Chưa có ai nhận issue này.
Đánh giá
- Độ khó
- 2/5
- Thời gian dự kiến
- 1-3 giờ
- Mức phù hợp với người mới
- 72/100
Hướng nghiên cứu
Đọc ios/firebase_messaging/Sources/firebase_messaging/FLTFirebaseMessagingPlugin.m, tập trung vào application:didRegisterForRemoteNotificationsWithDeviceToken: và ensureAPNSTokenSetting. Kiểm tra cách cả hai vị trí gọi thiết lập loại token APNs và so sánh với hành vi của Firebase iOS SDK được mô tả trong issue. Hoàn tất khi các bản build release được ký cho mục đích phát triển đăng ký chính xác token sandbox và lỗi gửi FCM được báo cáo được khắc phục, đồng thời các bản build store và debug vẫn giữ hành vi như mong đợi.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
Is there an existing issue for this?
- I have searched the existing issues.
Which plugins are affected?
Messaging
Which platforms are affected?
iOS
Description
On iOS the plugin decides the APNs token type at compile time:
// ios/firebase_messaging/Sources/firebase_messaging/FLTFirebaseMessagingPlugin.m (17.0.1)
// application:didRegisterForRemoteNotificationsWithDeviceToken: and ensureAPNSTokenSetting
#ifdef DEBUG
[messaging setAPNSToken:deviceToken type:FIRMessagingAPNSTokenTypeSandbox];
#else
[messaging setAPNSToken:deviceToken type:FIRMessagingAPNSTokenTypeProd];
#endif
DEBUG is only a proxy for the APNs environment. A release build installed with a development provisioning profile (what flutter run --release on a physical device does with automatic signing) has aps-environment = development and therefore a sandbox APNs token, but the plugin registers it as Prod. The same holds for a profile build. The Firebase iOS SDK already knows the right answer: FIRMessagingAPNSTokenTypeUnknown makes FIRMessagingIsSandboxApp() read aps-environment from embedded.mobileprovision (and defaults to production when the profile is stripped, i.e. App Store / TestFlight), which is exactly what the SDK's own FIRMessagingRemoteNotificationsProxy passes ([FIRMessaging messaging].APNSToken = deviceToken).
Because both hooks run as GoogleUtilities app-delegate interceptors on the same callback, and setAPNSToken:type: returns early when the token data is unchanged, whichever interceptor runs first decides the environment for that launch. GULAppDelegateSwizzler notifies interceptors from an NSDictionary keyed by object address, so the order is not stable. With FirebaseMessagingInstallationIdEnabled = YES the registration (FIRMessagingFIDRegisterOperation) sends apns_environment: PROD for a sandbox token on the launches where the plugin wins, and every send to that Installation ID then fails:
FCM HTTP v1 messages:send -> 400 INVALID_ARGUMENT "APNs device token is invalid."
Admin SDK sendEachForMulticast -> messaging/invalid-argument
On the launches where the SDK's proxy wins, the same install works. Across 11 apps on one iPhone we saw both outcomes on the same app and build, in streaks (one app lost 4 launches in a row, then won; another: 2 wins, 7 losses, 2 wins ...). A debug build of the same app (plugin says Sandbox) delivers every time.
Store builds are not affected (both paths say production). The impact is on development-signed release/profile builds, i.e. every flutter run --release smoke test and every internal app that is sideloaded rather than published, and it is silent on the device: the registration succeeds, only the server sees the 400.
Expected: the plugin passes FIRMessagingAPNSTokenTypeUnknown (let the SDK derive the environment from the provisioning profile, as the SDK does itself) or otherwise derives the type from aps-environment rather than from DEBUG. One-line change in both call sites; behaviour for App Store / TestFlight / Ad Hoc / Debug builds is unchanged, since the SDK's detection gives the same answer there.
Workaround we use: FirebaseMessagingAutoInitEnabled = NO in Info.plist (the plugin's interceptor is a no-op while auto-init is off, and register() is called from Dart as documented under "Prevent auto initialization"), plus a native call to registerForRemoteNotifications() once the default FirebaseApp exists, so the SDK's proxy is the only one that labels the token. It works deterministically, but it should not be necessary.
Reproducing the issue
- New Flutter app,
firebase_core5.1.0,firebase_messaging17.0.1,flutterfire configure;Info.plist:FirebaseMessagingInstallationIdEnabled= YES (default auto-init). Push Notifications capability on; APNs key uploaded in the Firebase console (key enabled for Sandbox & Production). - In Dart, after
Firebase.initializeApp()andrequestPermission(): subscribe toFirebaseMessaging.instance.onRegistered, callregister(), print the Installation ID. flutter run --release -d <physical iPhone>with automatic signing (Xcode uses the development profile;codesign -d --entitlements - build/ios/iphoneos/Runner.appshowsaps-environment = development).- Send to the printed id with the FCM HTTP v1 API:
POST https://fcm.googleapis.com/v1/projects/<project>/messages:sendbody{"message":{"fid":"<id>","notification":{"title":"t","body":"b"}}}. - Result on roughly half of cold launches: HTTP 400
"APNs device token is invalid."; on the other launches: 200 and the push arrives. Kill and relaunch the app and send again to see it flip. The debug build (flutter run) of the same app answers 200 every time.
To make it deterministic, break on -[FIRMessaging setAPNSToken:type:]: the first call on a failing launch comes from FLTFirebaseMessagingPlugin with type 2 (Prod); on a working launch from FIRMessagingRemoteNotificationsProxy with type 0 (Unknown).
Firebase Core version
5.1.0
Flutter Version
3.47.9 (stable), Dart 3.13.7
Relevant Log Output
# FCM HTTP v1, fid registered by a development-signed release build on a launch where the plugin's hook ran first
HTTP 400
{"error":{"code":400,"message":"APNs device token is invalid.","status":"INVALID_ARGUMENT"}}
# Admin SDK (firebase-admin 14.5.0) sendEachForMulticast({ fids: [...] }) on the same registration
messaging/invalid-argument
# entitlements of the installed build
codesign -d --entitlements - Runner.app | grep -A1 aps-environment
<key>aps-environment</key>
<string>development</string>
Flutter dependencies
pubspec.lock (relevant)
firebase_core: 5.1.0
firebase_core_platform_interface: 8.1.1
firebase_messaging: 17.0.1
firebase_messaging_platform_interface: 4.11.1
Firebase iOS SDK (SPM): 13.1.1
GoogleUtilities (SPM): 8.1.5
Xcode 27.2, macOS 27.2, physical iPhone 15 Pro Max
Additional context and comments
- The
#ifdef DEBUGsplit dates from the 2020 roadmap rework (#4012) and the same two sites were touched in July 2026 (6f22596) without changing the rule. - The documented alternative ("Prevent auto initialization",
FirebaseMessagingAutoInitEnabled = NO+register()) does avoid the mislabel, but with auto-init off the plugin no longer callsregisterForRemoteNotificationsat all, so an app must do that natively; that combination is probably not what most users expect from the docs. - Happy to open a PR if the
FIRMessagingAPNSTokenTypeUnknownapproach is acceptable.
- Ngôn ngữ chính
- Dart
- Star
- 9.3k
- Fork
- 4.1k
- Merge trung bình
- 1 ngày 9 giờ
- Pull request đã merge (30 ngày)
- 69
Chuẩn bị môi trường
- Không có Dockerfile hay tệp Docker Compose
- Có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của firebase/flutterfire
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 74/100
firebase/flutterfire#18908 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 3/5 1-2 ngày Mức phù hợp với người mới 67/100
firebase/flutterfire#18917 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
[📚] App Check Windows Support still N/A on ReadmeCó thể đã có người làm @Adrianogba đã nhận 1 ngày trước. Đang mởgood first issue type: documentation
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 35/100
firebase/flutterfire#18913 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
[📚] Data Connect Windows Support still N/A on ReadmeCó thể đã có người làm @Adrianogba đã nhận 1 ngày trước. Đang mởgood first issue type: documentation
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 35/100
firebase/flutterfire#18911 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
[📚] Realtime Database Windows Support still N/A on ReadmeCó thể đã có người làm @Adrianogba đã nhận 1 ngày trước. Đang mởgood first issue type: documentation
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 1/100
firebase/flutterfire#18909 ·
Maintainer thường phản hồi trong vòng 1 ngày
Tất cả issue của firebase/flutterfire
Issue tương tự
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 82/100
customerio/customerio-flutter#441 ·
Maintainer thường phản hồi trong vòng 2 ngày
-
JsonParseNode.getObjectValue returns non-null model on null JSON nodes and duplicates lifecycle hooksCó thể đã có người làm @hardikkaurani đã nhận hôm nay. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 76/100
microsoft/kiota-dart#170 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 77/100
fable-compiler/Fable#5280 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 74/100
immich-app/immich#33043 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
[FR] 希望能折叠搜索历史Đang mởenhancement
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 68/100
bggRGjQaUbCoE/PiliPlus#3503 ·
Maintainer thường phản hồi trong vòng 1 ngày