Closed Vinayak006 closed 3 months ago
@Vinayak006
The document is incorrect.
It is correct that calling the receivePort getter function creates a new ReceivePort.
Currently, when the app starts, a ReceivePort must be created and managed as a global instance.
I plan to improve this issue. Thank you for reporting.
@Dev-hwang, Thank you for your clarification.
Is there any workaround that we can use in the meantime to handle this more efficiently?
Nope, Didn't helped. Tried but same problem. receivePort
not receiving new messages sent by sentPort
once app is killed and re-opened. @Dev-hwang
Can you share the project?
I can't share the project.
Let me summarize what I have done so far.
main.dart
ReceivePort? receivePort;
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
if (GetPlatform.isAndroid) {
receivePort = FlutterForegroundTask.receivePort;
Get.put<ForegroundService>(ForegroundService());
}
runApp(const SipPhone());
}
As you can see, I made receivePort as globally accessible.
ForegroundService.dart
@pragma("vm:entry-point")
Future<void> startCallback() async {
FlutterForegroundTask.setTaskHandler(MyTaskHandler());
}
class ForegroundService extends GetxController {
StreamSubscription? receivePortStreamSubscription;
Rxn<RegisterState> registerState = Rxn<RegisterState>();
Rxn<ConnectionState> connectionState = Rxn<ConnectionState>();
Future<void> start(final ConnectParam param) async {
await FlutterForegroundTask.startService(
notificationTitle: "My service",
notificationText: "This is required to receive call in background",
callback: startCallback,
);
FlutterForegroundTask.sendData({
"connect": param.toJson(),
});
}
Future<void> stop() async {
FlutterForegroundTask.sendData("disconnect");
await receivePortStreamSubscription?.cancel();
await FlutterForegroundTask.stopService();
}
@override
Future<void> onInit() async {
super.onInit();
FlutterForegroundTask.init(
androidNotificationOptions: AndroidNotificationOptions(
channelId: "sip",
channelName: "SIP",
),
iosNotificationOptions: const IOSNotificationOptions(),
foregroundTaskOptions: const ForegroundTaskOptions(
isOnceEvent: true,
),
);
}
@override
Future<void> onClose() async {
super.onClose();
await receivePortStreamSubscription?.cancel();
}
}
My task handler
class MyTaskHandler extends TaskHandler implements SipUaHelperListener {
final SIPUAHelper sipuaHelper = SIPUAHelper();
SendPort? _sendPort;
@override
void onDestroy(final DateTime timestamp, final SendPort? sendPort) {
_sendPort = sendPort;
}
@override
Future<void> onReceiveData(final Object data) async {
super.onReceiveData(data);
if (data is Map) {
if (data["connect"] != null) {
// Handle connect logic
}
}
if (data is String) {
if (data == "disconnect") {
//handle disconnect logic
}
}
}
@override
void onRepeatEvent(final DateTime timestamp, final SendPort? sendPort) {}
@override
void onStart(final DateTime timestamp, final SendPort? sendPort) {
logger.i("onStart called");
sipuaHelper.addSipUaHelperListener(this);
_sendPort = sendPort;
}
@override
void callStateChanged(final Call call, final CallState state) {
_sendPort?.send("CALL ${state.state}");
}
@override
void onNewMessage(final SIPMessageRequest msg) {}
@override
void onNewNotify(final Notify ntf) {}
@override
void registrationStateChanged(final RegistrationState state) {
logger.i("registrationStateChanged called");
_sendPort?.send("RegistrationState Changed");
}
@override
void transportStateChanged(final TransportState state) {
_sendPort?.send("RegistrationState Changed");
}
}
And in home controller,
class HomeController extends GetxController {
@override
void onInit() {
super.onInit();
if (GetPlatform.isAndroid) {
// ignore: always_specify_types
receivePort?.listen((final message) {
logger.i("MESSAGE: $message");
Get.snackbar("Message", "$message");
});
}
}
}
when starting the service, i can get the log and snackbar message. But once app opened from terminated state, receivePort isn't receive message.
@Vinayak006
When you call the FlutterForegroundTask.receivePort
getter function, SendPort
is also new created.
ReceivePort and SendPort are pairs.
You can temporarily use the IsolateNameServer.lookupPortByName
function.
import 'dart:isolate';
import 'dart:ui';
class MyTaskHandler extends TaskHandler implements SipUaHelperListener {
final SIPUAHelper sipuaHelper = SIPUAHelper();
// SendPort? _sendPort;
@override
void onDestroy(final DateTime timestamp, final SendPort? sendPort) {
// _sendPort = sendPort;
}
@override
Future<void> onReceiveData(final Object data) async {
super.onReceiveData(data);
if (data is Map) {
if (data["connect"] != null) {
// Handle connect logic
}
}
if (data is String) {
if (data == "disconnect") {
//handle disconnect logic
}
}
}
@override
void onRepeatEvent(final DateTime timestamp, final SendPort? sendPort) {}
@override
void onStart(final DateTime timestamp, final SendPort? sendPort) {
logger.i("onStart called");
sipuaHelper.addSipUaHelperListener(this);
// _sendPort = sendPort;
}
@override
void callStateChanged(final Call call, final CallState state) {
final SendPort? sendPort =
IsolateNameServer.lookupPortByName('flutter_foreground_task/isolateComPort');
sendPort?.send("CALL ${state.state}");
}
@override
void onNewMessage(final SIPMessageRequest msg) {}
@override
void onNewNotify(final Notify ntf) {}
@override
void registrationStateChanged(final RegistrationState state) {
final SendPort? sendPort =
IsolateNameServer.lookupPortByName('flutter_foreground_task/isolateComPort');
logger.i("registrationStateChanged called");
sendPort?.send("RegistrationState Changed");
}
@override
void transportStateChanged(final TransportState state) {
final SendPort? sendPort =
IsolateNameServer.lookupPortByName('flutter_foreground_task/isolateComPort');
sendPort?.send("RegistrationState Changed");
}
}
Yeah, it is working now.
Thanks for the assistance :-) @Dev-hwang
@Vinayak006
I discovered a big problem through this discussion. thank you
The new version makes it easier to troubleshoot.
dependencies:
flutter_foreground_task: ^8.0.0
Migration Guide https://github.com/Dev-hwang/flutter_foreground_task#migration-ver-800
@Dev-hwang
That's a quick fix, and I appreciate it. I'll update to the new version using the migration guide.
In documentation, it is stated that,
Register the receivePort before starting the service
.Below is my startService code:
I have registered receivePort before starting the service as said, and it works fine.
But when the app is closed/terminated, and opened again, receivePort is not receiving any message. As stated in documentation,
You can get the previous ReceivePort without restarting the service
, I did tried gettingFlutterForegroundTask.receivePort
, but port isn't getting any message from sendPort.Below is my initState code:
Now, my question is that wheather receive port created new everytime?