firebase_cloud_messaging_dart 3.1.0
firebase_cloud_messaging_dart: ^3.1.0 copied to clipboard
A pure Dart library for sending Firebase Cloud Messages and managing topics using the FCM HTTP v1 API. Perfect for server-side environments like Serverpod. Includes native Google Application Default [...]
Changelog #
3.1.0 (Correctness Fixes) #
Bug Fixes #
- Fix (Critical):
FcmErrornow reads the authoritative error code fromerror.details[](the entry typedgoogle.firebase.fcm.v1.FcmError) instead of relying solely on the top-levelerror.status. The two do not always agree — a quota failure arrives asRESOURCE_EXHAUSTEDand an invalid token asNOT_FOUND. Previously both fell through toFcmErrorCode.unknown, which meantQUOTA_EXCEEDEDwas never retried andUNREGISTEREDnever reachedonRegistrationChange, so stale tokens were never cleaned up.RESOURCE_EXHAUSTEDandNOT_FOUNDare now also mapped when no details block is present. - Fix (Critical): Input validation no longer relies on
assert. Asserts are stripped from release and AOT builds (dart compile exe) — exactly how a server package ships — so malformed requests were silently forwarded to FCM in production. The "exactly one of token/topic/condition" rule, empty token/message lists, the/topics/prefix rule, and a missingproject_idnow throwArgumentErrorin every build mode. - Fix (Critical):
ApnsConfigno longer serialises anotificationkey.ApnsConfighas no such field on the wire (it belongs underpayload.aps), and FCM rejects the whole request withInvalid JSON payload received. Unknown name "notification". This affected every message that setapnswithout a typednotification. - Fix:
toJson()now omits unset fields instead of emitting them as explicitnulls, matching what the FCM v1 API expects. - Fix:
TopicManagementResult.fromJsonno longer throws aTypeErrorwhen the Instance ID API returns agoogle.rpcerror envelope ({"error": {"code": 401, ...}}) rather than a per-token error string. Auth and quota failures onsubscribeTokensToTopic/unsubscribeTokensFromTopicnow surface as failed results. A non-JSON body (e.g. a proxy error page) is reported asHTTP_<status>. - Fix: A
401from FCM now triggers one forced token refresh and a replay, instead of being returned to the caller as a permanent failure. The cached token is additionally treated as expired 60 seconds before its stated expiry to absorb clock skew and in-flight time. - Fix: HTTP requests are now bounded by
requestTimeout(default 30 seconds). A hung connection previously blocked forever. - Fix: Transport failures (
SocketException, timeouts, connection resets) are retried underretryConfiginstead of being rethrown on the first occurrence. - Fix:
sendToMultipleandsendMessagesno longer open one socket per message. At mostmaxConcurrency(default 50) requests are in flight at a time; result ordering still matches the input. - Fix:
subscribeTokensToTopic/unsubscribeTokensFromTopicnow split lists longer than 1,000 tokens into sequential batches and return one combined result, rather than sending an over-sized request that the API rejects. - Fix:
FcmErrorandFirebaseMessageimplement value equality, soServerResult ==compares content rather than object identity. - Fix: Topic management now honours the disposed state and throws a clear
StateError, matchingsend().
New Features #
- Feat:
requestTimeoutandmaxConcurrencyparameters on every constructor. - Feat:
obtainCredentials()is exposed as a@protected@visibleForTestingseam, allowing the send path to be tested without contacting Google.
Improvements #
- Test: Added 43 tests covering the send path, retry and backoff behaviour, 401 recovery, concurrency limits, topic batching, payload serialisation, and argument validation — none of which had coverage before.
- Chore: Added a direct dependency on
meta.
3.0.2 (FCM v1 API Compliance & Bug Fixes) #
Bug Fixes #
- Fix (Critical):
onRegistrationChangecallback no longer fires on transient errors (QUOTA_EXCEEDED,UNAVAILABLE,INTERNAL). Previously it marked valid tokens as unregistered on any failure, causing premature token deletion. Now only fires onUNREGISTEREDandSENDER_ID_MISMATCH. - Fix (Critical):
AndroidNotificationProxy.ifPriorityDegradedrenamed toifPriorityLowered— the previous valueIF_PRIORITY_DEGRADEDdoes not exist in the FCM v1 API. Corrected toIF_PRIORITY_LOWEREDper the official spec. - Fix (Critical):
FCMColorfields changed fromint(0–255) todouble(0.0–1.0). The FCM v1 API defines color components as floats in the range[0, 1], not integers. - Fix:
INTERNAL(HTTP 500) errors are now correctly marked as retryable, matching the official FCM error documentation. - Fix: Removed phantom
imagefield fromFirebaseFcmOptions. The top-levelFcmOptionsin the FCM v1 API only containsanalyticsLabel— theimagefield never had any effect.
New Features #
- Feat: Added
AndroidFcmOptionsclass withanalyticsLabelfield andfcmOptionsonFirebaseAndroidConfig, enabling per-platform analytics labels for Android. - Feat: Added
bandwidthConstrainedOkandrestrictedSatelliteOkfields toFirebaseAndroidConfigper the FCM v1 API spec. - Feat:
sendMessages()now executes in parallel viaFuture.wait, matching the official Admin SDKsendEach()behavior. Previously sent sequentially. - Feat:
sendToTopic()andsendToCondition()now accept an optionalvalidateOnlyparameter for dry-run validation. - Feat: Added
liveActivityTokenfield toFirebaseApnsConfigfor Apple Live Activity updates (iOS 16.1+). - Feat:
_send()now asserts that exactly one oftoken,topic, orconditionis set on the message, catching misuse early.
Improvements #
- Feat:
Retry-Afterheader is now honored when present on 429/503 responses, falling back to exponential backoff otherwise. Per FCM best practices. - Refactor:
performAuth()deprecated — token management is now fully internal via_performAuth(). - Refactor:
fromServiceAccountFile()now throws a clearArgumentErrorinstead of aCastErrorwhen given an invalid type. - Refactor: Removed unused
collectiondependency. - Refactor: Cleaned up orphaned comments and stale doc references.
- Refactor: Calling any method after
dispose()now throws a clearStateErrorinstead of an opaque HTTP client error.
Breaking Changes #
AndroidNotificationProxy.ifPriorityDegraded→AndroidNotificationProxy.ifPriorityLoweredFCMColorfields changed fromint?todouble?FirebaseFcmOptions.imageremoved (was never part of the FCM v1 API)performAuth()deprecated in favor of automatic token management
3.0.1 (Deep Hardening & Optimization) #
- Records for Performance: Integrated Dart 3 Records in
sendToMultiplefor efficient intermediate data mapping, reducing object allocation overhead during large fan-outs. - Pattern Destructuring: Modernized HTTP response handling and JSON parsing using pattern matching for cleaner, type-safe logic.
- Architectural Hardening: Applied strict class modifiers (
final,base) project-wide and resolved all 89 analysis violations including unsafedynamiccalls. - Strict Quality: Enabled
avoid_dynamic_calls,prefer_final_locals, andstrict-inferenceanalysis flags for enterprise-grade safety. - Backward Compatibility: Optimized dependency constraints (
json_annotation: ^4.9.0) to maintain full support for Dart 3.0.0 and resolve build-time SDK warnings. - Memory Efficiency: Enforced
constconstructors across all data models to minimize runtime memory footprint. - Code Hygiene: Refactored internal result handling and improved error extraction logic.
3.0.0 (Dart 3 Modernization) #
Major Breaking Change: Renamed package from firebase_cloud_messaging_flutter to firebase_cloud_messaging_dart.
This update accurately reflects the library's status as a pure Dart package, suitable for both Flutter and server-side environments like Serverpod.
🚀 Key Improvements (Dart 3) #
- Sealed Results:
ServerResultis now asealedclass hierarchy (ServerSuccess,ServerFailure). This allows for type-safe exhaustive pattern matching when handling send outcomes. - Switch Expressions: Refactored internal error parsing logic to use concise Dart 3 switch expressions.
- Class Modifiers: Applied
finalclass modifiers to core data models (e.g.,FirebaseAndroidConfig,FirebaseApnsConfig,FcmError) to improve architectural integrity and compiler optimization. - SDK Alignment: Bumped minimum SDK constraint to
^3.0.0.
⚠️ Breaking Changes #
- Package Rename: All imports must now use
package:firebase_cloud_messaging_dart/. - Main Entry Point: Renamed from
firebase_cloud_messaging_server.darttofirebase_cloud_messaging_dart.dart. - Result Matching: Since
ServerResultis now sealed, users should switch to type-safe pattern matching or check forServerSuccess/ServerFailureconcrete types. Legacy properties (messageSent,fcmError,errorBody) are preserved on the base class for backward compatibility but using the subclasses is recommended.
2.1.0 #
This release elevates the package to a production-hardened server-side SDK by introducing native ambient credentials and dedicated topic management.
- Feat (Auth): Introduced
FirebaseCloudMessagingServer.applicationDefault({ required String projectId }). Supports Google Application Default Credentials (ADC) for seamless authentication in Cloud Run, App Engine, and Firebase Functions. - Feat (Topic Management): Added
subscribeTokensToTopic()andunsubscribeTokensFromTopic(). These utilize the Firebase Instance ID API for efficient batch management (up to 1,000 tokens per request). - Refactor (Architecture): Introduced
FcmTopicManagementinternal class to centralize topic lifecycle logic. - Refactor (Breaking): Migrated project-wide filename convention to standard Dart snake_case (e.g.,
android_config.dart). All internal imports and public exports have been updated. - Hardening: Consolidated network logic into a shared, reusable
http.Clientto prevent socket leaks. - Typing: Added missing priority and visibility fields to platform-specific configs.
2.0.0 #
Breaking Changes #
AndroidMessagePriority.normaland.highnow serialize to"NORMAL"and"HIGH"respectively.FirebaseWebpushConfig.notificationchanged to typedFirebaseWebpushNotification.FirebaseWebpushConfig.webPushFcmOptionsrenamed tofcmOptions.ServerResult.messageSentis now nullable.json_serializablemoved todev_dependencies.
New Features #
sendToMultiple()— sends to many tokens in parallel.sendToTopic()— targeted topic messages.sendToCondition()— targeted condition messages.validateMessage()— dry-run support.onRegistrationChange— registration status callback.FcmLogger— structured logging.FcmRetryConfig— exponential back-off retries.FirebaseCloudMessagingServer.fromServiceAccountJson()— load from JSON string.FirebaseCloudMessagingServer.fromServiceAccountFile()— load from File.dispose()— clean resource cleanup.FcmError+FcmErrorCode— typed FCM error extracted from failed requests. responses. UseisRetryableto decide whether to back off.BatchResult/TokenResult— aggregated result fromsendToMultiple.
API Completeness #
FirebaseApnsConfig— added typednotification(FirebaseApnsNotification) andfcmOptions(ApnsFcmOptions). Rawpayloadmap preserved for advanced APS dictionary use.- New
apns.notification.dart—FirebaseApnsNotification,ApnsAlert,ApnsFcmOptions. FirebaseWebpushConfig— replaced rawMapfields with typedFirebaseWebpushNotificationandWebpushFcmOptions.- New
webpush.notification.dart—FirebaseWebpushNotification,WebpushAction,WebpushFcmOptions. FirebaseFcmOptions— added missingimagefield.FirebaseAndroidConfig— addeddirectBootOk(direct_boot_ok) field.FirebaseAndroidNotification— addedproxyfield withAndroidNotificationProxyenum.
Bug Fixes #
- Fixed HTTP client leak: a single
http.Clientis now reused across all send calls and closed viadispose(). Previously a new client was created (and leaked) on everysend()invocation. - Fixed
projectIDbeing re-parsed from JSON on every request; now cached at construction time.
Quality #
- Added
copyWith()toFirebaseMessage,FirebaseSend, andServerResult. - Added
ServerResult.errorBody(raw response body on failure) andServerResult.fcmError(typed error). FirebaseSendnow asserts thatmessageis non-null at construction time.- Added full unit test suite in
test/. - Updated all dev dependencies to latest versions.
- Updated minimum SDK to
>=2.17.0.
1.0.6 #
- Updated dependencies
- Thanks to @dsyrstad
- Made fixes to .gitignore and removed pubspec.lock to make it conform to a standard Dart package project.
- Upgraded to support Dart 3.0+.
- Fixed commenting — replacing /// with // where appropriate.
- Support Webpush fcm_options and support proper notification object.
1.0.5 #
- Improved code structure and quality
1.0.4 #
- Updated dependencies
- Improved code structure and quality
1.0.3 #
- Improved code structure and quality
1.0.2 #
- Updated Dependencies
1.0.1 #
- Improved Example and Document File
1.0.0 #
- Initial version, minor things missing