Reputation: 873
I have implemented the flutter onBackgroundMessage, that gets triggered when the device receives a Firebase Cloud Messaging data message; i should open a popup, but in this event handler I have no context
object. What's the correct way to achieve this ?
Upvotes: 1
Views: 4949
Reputation: 405
If you want to display a pop-up within the app, then you don't need onBackgroundMessage
- that is only for processing data when a message is received in the background. There is no way to launch the app at the moment the message is received.
However, if a user taps on the notification, the app will launch, and either the onResume or onLaunch callbacks will be called.
You can notify the relevant screen to show a pop up when this happens.
Here's a simple implementation:
In firebase_notification_receiver.dart
:
import 'dart:async';
import 'package:firebase_messaging/firebase_messaging.dart';
class NotificationEvent {
final Map<String, dynamic> content;
/// whether the notification was delivered while the app was in the foreground
final bool inApp;
NotificationEvent({this.content, this.inApp = false});
}
class FirebaseNotificationReceiver extends NotificationReceiver {
final FirebaseMessaging _firebaseMessaging = FirebaseMessaging();
StreamController<NotificationEvent> _controller = StreamController<NotificationEvent>.broadcast();
StreamSubscription _streamSubscription;
Function(NotificationEvent) _listener;
init{
// add the rest of the code to initialise firebase here
_firebaseMessaging.configure(
/// Fires when App was in foreground when receiving the notification
onMessage: (Map<String, dynamic> message) async {
print("onMessage: $message");
_controller.sink.add(NotificationEvent(content: message, inApp: true));
},
/// Fires when App was in background when receiving the notification and user has tapped on it
onResume: (Map<String, dynamic> message) async {
print("onResume: $message");
_controller.sink.add(NotificationEvent(content: message));
}
/// Fires when App was closed when receiving the notification and user has tapped on it
onLaunch: (Map<String, dynamic> message) async {
print("onLaunch: $message");
_controller.sink.add(NotificationEvent(content: message));
},
);
_streamSubscription =
_controller.stream.listen(_onStreamEvent, onError: (e) {
print("Notification Stream error $e");
});
}
setListener(Function(NotificationEvent) onData) {
this._listener = onData;
}
}
In main.dart
:
// imports go here
void main(){
final notificationReceiver = NotificationReceiver.firebase();
runApp(
MultiProvider(
providers: [
Provider<NotificationReceiver>(
builder: (_) => notificationReceiver),
// more providers go here
],
child: App(), // Your custom app class
),
);
}
In notification_listenable.dart
:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class NotificationListenable extends StatefulWidget {
final Widget child;
final Function(NotificationEvent) onData;
const NotificationListenable({@required this.child, this.onData});
@override
_NotificationListenableState createState() => _NotificationListenableState();
}
class _NotificationListenableState extends State<NotificationListenable> {
@override
Widget build(BuildContext context) {
Provider.of<NotificationReceiver>(context).setListener(widget.onData);
return widget.child;
}
}
In my_screen.dart:
/// add your imports here
class MyScreen extends StatefulWidget {
@override
HomePageState createState() => HomePageState();
}
class MyScreenState extends State<MyScreen> {
final _scaffoldKey = GlobalKey<ScaffoldState>();
void _onNotification(NotificationEvent n) {
(_scaffoldKey.currentState)?.showSnackBar(
SnackBar(
duration: Duration(seconds: 2),
content: Text("I am a pop up"),
),
),
}
@override
Widget build(BuildContext context) {
return NotificationListenable(
child: YourCustomScreenContent(),
onData: _onNotification,
);
}
Upvotes: 1
Reputation: 136
I created a class with static methods:
class FirebaseMessagingHandler {
final FirebaseMessaging firebaseMessaging = FirebaseMessaging();
final _bloc = AppModule.to.getBloc<FirebaseMessagingHandlerBloc>();
void setListeners() {
if (Platform.isIOS) _iOSPermission();
getToken();
refreshToken();
}
void getToken() {
firebaseMessaging.getToken().then((token) {
_bloc.saveToken(token);
print('DeviceToken = $token');
});
}
void _iOSPermission() {
firebaseMessaging.configure();
firebaseMessaging.requestNotificationPermissions(IosNotificationSettings(sound: true, badge: true, alert: true));
firebaseMessaging.onIosSettingsRegistered.listen((IosNotificationSettings settings) {
});
}
void refreshToken() {
firebaseMessaging.onTokenRefresh.listen((token) {
_bloc.refreshToken(token);
});
}
void showDialog(BuildContext context, Map<String, dynamic> message) {
// data
}
void showErrorDialog(BuildContext context, dynamic error) {
// data
}
void redirectToPage(BuildContext context, Map<String, dynamic> message) {
// data
}
}
And in my homePage (a page that will always be called when open my app) I call the configure:
class _HomePageState extends State<HomePage> {
final _fcm = FirebaseMessagingHandler();
@override
void initState() {
super.initState();
firebaseCloudMessagingListeners();
}
void firebaseCloudMessagingListeners() {
_fcm.firebaseMessaging.configure(
onMessage: (Map<String, dynamic> message) async {
try {
_fcm.showDialog(context, message);
} catch (e) {
_fcm.showErrorDialog(context, e);
}
},
onLaunch: (Map<String, dynamic> message) async {
try {
_fcm.redirectToPage(context, message);
} catch (e) {
_fcm.showErrorDialog(context, e);
}
},
onResume: (Map<String, dynamic> message) async {
try {
_fcm.redirectToPage(context, message);
} catch (e) {
_fcm.showErrorDialog(context, e);
}
},
);
}
}
Upvotes: 1