Reputation: 527
i'm developing a VoIP app and having problem with background handler. What i want is: sending push with type "call" then the app will show Call UI, later if receive push type "hangup" , the app will close that call UI.
In background handler i'm using a singleton global class to inform hang up event with a StreamController and CallScreen widget will listen to that stream to close itself.
Then i found out that flutterfire will start another isolate for background handler (turn screen off) , so it will create another singleton class -> i can't close my CallScreen UI with this new singleton class.
Is it possible to do something like this with flutterfire's background isolate ?
Example pseudo code:
class SingletonGlobal {
/// singleton class
final hangUpStreamController = StreamController<HangUpEvent>.broadcast();
void addHangupEvent(HangUpEvent event) {
hangUpStreamController.add(event);
}
}
class CallScreen extends StatefulWidget {
//// ...
@override
void initState() {
SingletonGlobal().hangUpStreamController.stream.listen((event) => closeCallUI(event));
}
}
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
await Firebase.initializeApp();
await appInit();
if (message.data.type = 'hangup') {
SingletonGlobal().addHangupEvent(hangUpEvent);
}
I tried Nitrodon's solution. but as I mentioned, _firebaseMessagingBackgroundHandler will create another instance of my SingleGlobal class. i don't know why.
"SingletonGlobal#internal" printed again after receive firebase background handler. that's mean it recreated SingletonGlobal.
class SingletonGlobal {
/// singleton class
static SingletonGlobal? _instance;
final _receivePort = ReceivePort();
factory SingletonGlobal() => _instance ?? SingletonGlobal._internal();
SingletonGlobal._internal() {
print('SingletonGlobal#internal');
IsolateNameServer.registerPortWithName(_receivePort.sendPort, 'global_singleton');
_receivePort.listen((message) => hangUpStreamController.add);
_instance = this;
}
}
Upvotes: 1
Views: 2939
Reputation: 3445
There are ways to communicate between isolates. In this case, since you only need to listen to events on the main isolate, you can register a port to receive hangup events from the background isolate:
class SingletonGlobal {
// Whatever private constructor you're using for this singleton
SingletonGlobal._() {
IsolateNameServer.registerPortWithName(_receivePort.sendPort, 'some port name');
_receivePort.listen(hangUpStreamController.add);
}
final hangUpStreamController = StreamController<HangUpEvent>.broadcast();
final _receivePort = ReceivePort();
void addHangupEvent(HangUpEvent event) {
hangUpStreamController.add(event);
}
}
void _firebaseMessagingBackgroundHandler(RemoteMessage message) {
// Do not try to access SingletonGlobal here.
if (message.data.type = 'hangup') {
// Since the background isolate is still in the same process, you
// can send objects (which are copied) instead of just basic messages.
IsolateNameServer.lookupPortByName('some port name')?.send(hangUpEvent);
}
}
Upvotes: 5
Reputation: 411
You have to use onMessageOpenedApp event. avoid using any other notifications plugins as it will ignore this event. By the way this event only works when the app is closed and it gets opened by the notification from FCM plugin. it will give you RemoteMessage object which from you can retrieve the message data.
Upvotes: 0