Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use Firebase Cloud Messaging in a Flutter Windows app

I have checked both firebase_dart and flutterfire packages but none of them provide a firebase FirebaseMessaging class to use. Is there any way I can use Cloud Messaging in my Flutter Windows app? I want to listen to events from the console in the app and send a Windows notification using the event data.

like image 845
Vonarian Avatar asked May 02 '26 18:05

Vonarian


1 Answers

I have sort of found a workaround that is usable, at least for now. The answer by Allysson is about sending events as a Dart admin client, but I want to receive messages on my Flutter Windows application.

Workaround Steps:

  1. First, we have to add Firebase "Real-Time Database" to our project ==> firebase_dart, firebase_core, and or firebase_dart_flutter packages are required for this matter. We don't need the flutter package in case we are not developing a Flutter Windows app.
  2. Prepare our data class for handling incoming events from the RTDB:
class Message {
  final String title;
  final String subtitle;
  final int id;
  final String? url;
  final String? operation;
  final String? device;

  @override
  const Message(
      {required this.title,
      required this.subtitle,
      required this.id,
      this.url,
      this.operation,
      this.device});

  @override
  String toString() {
    return 'Message{title: $title, subtitle: $subtitle, id: $id, url: $url, operation: $operation, device: $device}';
  }

  Map<String, dynamic> toMap() {
    return {
      'title': title,
      'subtitle': subtitle,
      'id': id,
      'url': url,
      'operation': operation,
      'device': device,
    };
  }

  factory Message.fromMap(Map<String, dynamic> map) {
    return Message(
      title: map['title'] as String,
      subtitle: map['subtitle'] as String,
      id: map['id'] as int,
      url: map['url'] as String?,
      operation: map['operation'] as String?,
      device: map['device'] as String?,
    );
  }
}

In this Message class, we have non-nullable id, title, and subtitle fields, which are our static data structure from the RTDB. Other nullable fields are optional which I will explain.

  1. Define our fields in RTDB:

The fields in the Real-Time Database

As already pointed out, the id, title, and subtitle fields are mandatory and not nullable. id is a unique integer which is checked each time by our Windows client, optionally you can save the last id value on disk to prevent repetitive notifications on app restarts. Each time id is changed in our database, the event is sent to clients listening to this RTDB, then clients check if id's value is new or not, then send a notification, there are multiple notification packages on pub.dev. title and subtitle are passed to our notification package's functions to actually send the notification.

  1. Listen to the RTDB:

  StreamSubscription? startListening() {
    FirebaseDatabase db = FirebaseDatabase(
        app: app,
        databaseURL:
            '<Our RTDB URl>');
    db.goOnline();
    return db.reference().onValue.listen((event) async {
      final data = event.snapshot.value;
      if (data != null &&
          data['title'] != null &&
          data['subtitle'] != null &&
          data['id'] != null &&
          data['title'] != '' &&
          data['subtitle'] != '') {
        Message message = Message.fromMap(data);
        if (widget.prefs.getInt('id') != message.id) {
          if (message.device == (await deviceInfo.windowsInfo).computerName ||
              message.device == null) {
            var toast =
                LocalNotification(title: message.title, body: message.subtitle)
                  ..show();
            toast.onClick = () {
              if (message.url != null) {
                launchUrl(Uri.parse(message.url!));
              }
            };
            await widget.prefs.setInt('id', message.id);
          }
        }
      }
    });
  }

In the code sample above, we are making an object for our database, listening to it and returning the StreamSubscription to handle listening states.

At last, we will actually start listening to our database:

 StreamSubsricption? dbSub;
 @override
 void initState() {
    super.initState();
    dbSub = startListening(); //Start listening to our RTDB
  }
 @override
 void dispose() {
   dbSub?.cancel(); //Stop listening - Must be called to prevent a memory-leak
   super.dispose();
 }

This way, we are sending notifications to our Windows clients each time after changing id's value on the Firebase console, we can optionally define url field to open the URL in the browser when client clicks on the notification.

like image 146
Vonarian Avatar answered May 05 '26 09:05

Vonarian



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!