Reputation: 440
I'm using SignalR for push notifications on my Flutter app and that works ok. I get the message from the backend and show notification using flutter_local_notifications. The problem is that the SignalR service would shut down after some time. How can I make my app stay on in the background? and even start on reboot?
Here's my code:
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:isolate_test/Model/UserMessageModel.dart';
import 'package:signalr_core/signalr_core.dart';
import 'EndPointService.dart';
import 'NotificationService.dart';
class SignalRProvider {
static String appName = "NOTIFICATION";
static String? userName = "";
static String deviceName = "android_app";
static List<UserMessageModel> messages = <UserMessageModel>[];
HubConnection connection = HubConnectionBuilder()
.withUrl(
'my_url',
HttpConnectionOptions(
logging: (level, message) => print(message),
))
.withAutomaticReconnect()
.withHubProtocol(JsonHubProtocol())
.build();
Function(bool update)? onMessagesUpdateCallback;
SignalRProvider({
this.onMessagesUpdateCallback,
});
setUsername(String username) {
userName = username;
}
Future initSignalR(BuildContext context) async {
WidgetsFlutterBinding.ensureInitialized();
await NotificationService().init();
connection.on('SignalRUserReceiveMessage', (message) async {
var data = message!.first;
if (data != null) {
UserMessageModel msg = UserMessageModel.fromJson(data);
messages.add(msg);
msg.showNotification();
}
if (onMessagesUpdateCallback != null) {
onMessagesUpdateCallback!(true);
}
});
connection.on('SignalRMonitoringMessage', (message) async {
var data = message!.first;
if (data != null) {
UserMessageModel msg = UserMessageModel.fromJson(data);
messages.add(msg);
msg.showNotification();
}
if (onMessagesUpdateCallback != null) {
onMessagesUpdateCallback!(true);
}
});
connection.on("SignalRReceiveConnectedMessage", (message) async {
await connection.send(methodName: 'SignalRInit', args: [
userName,
appName,
connection.connectionId,
]);
});
connection.on("SignalRReceiveDisconnectedMessage", (message) async {
if (connection.state == HubConnectionState.disconnected) {
connection.start();
}
});
await connection.start();
}
List<UserMessageModel> getMessages() {
return messages;
}
Future deleteMessage(UserMessageModel _msg) async {
if (_msg == null) return;
var response =
await EndPointService().SetupApi("Message", "", []).httpDelete(
HeaderEnum.BasicHeaderEnum,
ResponseEnum.ResponseModelEnum,
jsonEncode(_msg),
);
}
addOrUpdateMessage(UserMessageModel _msg) {
if (_msg == null) return;
if (messages != null) {
var found =
messages.firstWhere((e) => e.user == _msg.user && e.id == _msg.id);
var index =
messages.indexWhere((e) => e.user == _msg.user && e.id == _msg.id);
if (found != null) {
messages[index] = _msg;
} else {
messages.add(_msg);
}
if (onMessagesUpdateCallback != null) {
onMessagesUpdateCallback!(true);
}
}
}
setMessagesUpdateCallback(Function(bool update) func) {
onMessagesUpdateCallback = func;
}
}
Upvotes: 4
Views: 3726
Reputation: 28948
SignalR for Flutter uses web sockets and SSE to receive messages from the SignalR service. If the app was terminated because the user restarted their phone or the OS shut down the app to save battery, these push notifications would not be received by the app.
To overcome this, app developers (and SignalR) have to use FCM on Android, and APNs on iOS (or FCM which will also use APNs on iOS). All other approaches will be more limited because the operating systems do not allow users to keep background processes running the entire time. This was actually allowed years ago, but the operating systems have made these changes to save the user battery - they enforce that all apps go through the same push notification medium - FCM on Android, APNs on iOS.
SignalR for Flutter uses neither FCM nor APNs. At it's current state, SignalR is not well suited for Android or iOS - take a look at the comments with people struggling with similar problems to you on How to use signalr in Android.
The simplest / easiest way to get started is to use Firebase Cloud Messaging.
Caveat: On Android, there is a more complicated alternative called unifiedpush, but the limitations include showing a notification to the user at all times to handle background notifications.
My analysis: This is all done based on my quick investigation by reading the pubspec.yaml
, the GitHub issues on the original repo, the SignalR documentation, and some experience implementing Push Notifications for Flutter.
Disclosure: I just released a push notification library 2 days ago called push
which would be well suited to these types of Push Notification packages making the transformation to using FCM on Android and APNs on iOS. However, as an app developer, in most cases, you should use firebase_messaging
, not push
.
Upvotes: 10
Reputation: 322
I worked with SignalR but on native Platform(IOS & Android), I made stock app and get realtime price. When app go to background, I will disconnect with SignalR server after 5 second, and when app go to foreground again, I check if app's current state not connect to server SignalR, I'll connect again. I think it not good if your app still connect and receiver data from signalR server in background state.
Upvotes: 1