firebase_fcm_client 0.1.1
firebase_fcm_client: ^0.1.1 copied to clipboard
Server-side Firebase Cloud Messaging (FCM) HTTP v1 client for Dart with keyless runtime credentials and optional service account impersonation.
Firebase FCM Client #
Server-side Firebase Cloud Messaging HTTP v1 client for Dart.
This package is for backend workloads that send push notifications to FCM. It is not a browser/mobile Firebase Messaging SDK and it does not register device tokens for your app.
What This Package Is For #
- Sending FCM messages from a backend service
- Using keyless runtime credentials by default
- Optionally impersonating a target Google service account
- Sending to device tokens, topics, and conditions
What This Package Is Not For #
- Obtaining push tokens in the browser or mobile app
- Receiving notifications on client devices
- Storing device tokens in your application database
Use the Firebase client SDKs in your frontend apps for token registration and message reception. Use this package on the backend to deliver notifications to the saved tokens.
Installation #
dependencies:
firebase_fcm_client: ^0.1.0
Recommended Credential Model #
Prefer keyless server credentials:
- Direct runtime identity Use this when the workload already runs as the correct Google service account.
- Service account impersonation Use this when the workload should act as a different target service account.
- Local ADC
Use
gcloud auth application-default loginfor local development.
Avoid shipping service-account JSON keys as the normal production path.
Quick Start #
Direct Runtime Identity #
import 'package:firebase_fcm_client/firebase_fcm_client.dart';
Future<void> main() async {
final fcm = await FCMClient.fromServerCredentials(
projectId: 'my-firebase-project',
);
final result = await fcm.sendToToken(
'device-token',
title: 'Hello',
body: 'Sent with direct runtime credentials',
);
print(result);
await fcm.auth.close();
}
Target Service Account Impersonation #
import 'package:firebase_fcm_client/firebase_fcm_client.dart';
Future<void> main() async {
final fcm = await FCMClient.fromServerCredentials(
projectId: 'my-firebase-project',
targetServiceAccountEmail:
'fcm-sender@my-project.iam.gserviceaccount.com',
);
final result = await fcm.sendToTopic(
'tenant_123',
title: 'Deployment finished',
body: 'The latest rollout completed successfully.',
);
print(result);
await fcm.auth.close();
}
Explicit Auth Object #
import 'package:firebase_fcm_client/firebase_fcm_client.dart';
Future<void> main() async {
final auth = await ServiceAccountAuth.fromServerCredentials(
projectId: 'my-firebase-project',
targetServiceAccountEmail:
'fcm-sender@my-project.iam.gserviceaccount.com',
);
final fcm = FCMClient(
auth: auth,
projectId: 'my-firebase-project',
);
await fcm.sendToCondition(
"'ops' in topics && 'critical' in topics",
title: 'Alert',
body: 'A critical event was detected.',
);
await auth.close();
}
API Surface #
Preferred #
ServiceAccountAuth.fromServerCredentials({
required String projectId,
String? targetServiceAccountEmail,
})
FCMClient.fromServerCredentials({
required String projectId,
String? targetServiceAccountEmail,
})
Deprecated #
ServiceAccountAuth.fromImpersonation(...)
FCMClient.fromImpersonation(...)
These old names still exist for migration, but the package now models server credentials more accurately:
- no target service account means direct runtime identity
- target service account means impersonation
Sending Messages #
await fcm.send(message);
await fcm.sendToToken(token, title: 'Title', body: 'Body');
await fcm.sendToTopic(topic, title: 'Title', body: 'Body');
await fcm.sendToCondition(condition, title: 'Title', body: 'Body');
Local Development #
gcloud auth application-default login
Then run your Dart server normally. The package will use application-default credentials and optionally impersonate the configured target service account.
Operational Guidance #
- Keep device-token registration and persistence in your application backend.
- Keep FCM delivery in this package.
- Treat service account impersonation as a server concern, not a frontend concern.
- Prefer one obvious initializer path across apps so each backend integrates the package the same way.