FlutterFire后台隔离通信
FlutterFire background isolate communication
我正在开发一个 VoIP 应用程序,但后台处理程序有问题。我想要的是:发送类型为“call”的推送,然后应用程序将显示 Call UI,稍后如果收到类型为“hangup”的推送,应用程序将关闭该调用 UI.
在后台处理程序中,我使用单例全局 class 通过 StreamController 通知挂断事件,CallScreen 小部件将监听该流以关闭自身。
然后我发现 flutterfire 将为后台处理程序启动另一个隔离(关闭屏幕),因此它将创建另一个 单例 class -> 我可以'不要用这个新的单身人士 class.
关闭我的 CallScreen UI
是否可以用 flutterfire 的背景隔离来做这样的事情?
示例伪代码:
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);
}
更新
我尝试了 Nitrodon 的解决方案。但正如我提到的,_firebaseMessagingBackgroundHandler 将创建我的 SingleGlobal class 的另一个实例。我不知道为什么。
收到 firebase 后台处理程序后再次打印“SingletonGlobal#internal”。这意味着它重新创建了 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;
}
}
您必须使用 onMessageOpenedApp 事件。避免使用任何其他通知插件,因为它会忽略此事件。
顺便说一句,此事件仅在应用程序关闭时有效,并且它会通过来自 FCM 插件的通知打开。它会给你 RemoteMessage 对象,你可以从中检索消息数据。
有多种方法可以在 isolate 之间进行通信。在这种情况下,由于你只需要监听主isolate上的事件,你可以注册一个端口来接收来自后台isolate的hangup事件:
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);
}
}
我正在开发一个 VoIP 应用程序,但后台处理程序有问题。我想要的是:发送类型为“call”的推送,然后应用程序将显示 Call UI,稍后如果收到类型为“hangup”的推送,应用程序将关闭该调用 UI.
在后台处理程序中,我使用单例全局 class 通过 StreamController 通知挂断事件,CallScreen 小部件将监听该流以关闭自身。
然后我发现 flutterfire 将为后台处理程序启动另一个隔离(关闭屏幕),因此它将创建另一个 单例 class -> 我可以'不要用这个新的单身人士 class.
关闭我的 CallScreen UI是否可以用 flutterfire 的背景隔离来做这样的事情?
示例伪代码:
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);
}
更新
我尝试了 Nitrodon 的解决方案。但正如我提到的,_firebaseMessagingBackgroundHandler 将创建我的 SingleGlobal class 的另一个实例。我不知道为什么。
收到 firebase 后台处理程序后再次打印“SingletonGlobal#internal”。这意味着它重新创建了 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;
}
}
您必须使用 onMessageOpenedApp 事件。避免使用任何其他通知插件,因为它会忽略此事件。 顺便说一句,此事件仅在应用程序关闭时有效,并且它会通过来自 FCM 插件的通知打开。它会给你 RemoteMessage 对象,你可以从中检索消息数据。
有多种方法可以在 isolate 之间进行通信。在这种情况下,由于你只需要监听主isolate上的事件,你可以注册一个端口来接收来自后台isolate的hangup事件:
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);
}
}