I am making an application in Xamarin Forms that uses the Signalr service to implement a chat. The chat works perfectly in the UWP version and in the Android emulator, so it does when I am debugging on my phone (Android), but when I disconnect the phone from the PC the chaos begins. The problem is that I think that when the application goes to the background, it disconnects from the Signalr server.
I have tried automatic reconnection and even changing the times of ServerTimeout and KeepAliveInterval. But I have not been successful. It should be noted that where I live additionally there are major connectivity problems, but still my theory is when the application goes to Background.
This is my code where I initialize my service (Im using a Singleton services).
hubConnection = new HubConnectionBuilder()
.WithUrl(URL, options =>
{
options.AccessTokenProvider = () => Task.FromResult(_myAccessToken);
})
.WithAutomaticReconnect()
//.WithAutomaticReconnect(new[] { TimeSpan.Zero, TimeSpan.Zero, TimeSpan.FromSeconds(10) })
//.WithAutomaticReconnect(new RandomRetryPolicy())
.Build();
This is my code to connect when the connection is closed
hubConnection.Closed += async (error) =>
{
OnConnectionClosed?.Invoke(this, new MessageEventArgs("Connection closed...",
string.Empty));
IsConnected = false;
await Task.Delay(new Random().Next(0, 5) * 1000);
try { await ReConnectAsync(); } catch (Exception ex) { Debug.WriteLine(ex); }
};
This is my code to connect
public async Task ReConnectAsync()
{
await ConnectAsync();
}
public async Task ConnectAsync()
{
if (IsConnected)
{
return;
}
Debug.WriteLine(hubConnection.State);
if (hubConnection.State== HubConnectionState.Disconnected)
{
await hubConnection.StartAsync();
//CancellationToken cancellationToken = new CancellationToken();
//await ConnectWithRetryAsync(hubConnection, cancellationToken);
}
IsConnected = true;
}
What else could I try to prevent it from disconnecting on Android or what will I be doing wrong in my code?
You won't be able to keep the SignalR connection alive on Android unless you have a Foreground Service running, which essentially keeps the App alive. This is how music apps etc. can keep functioning in the background.
A foreground service will also need to show a notification to the user that it is running.
Xamarin provides a nice little sample showing how to create a foreground service here https://github.com/xamarin/monodroid-samples/tree/master/ApplicationFundamentals/ServiceSamples/ForegroundServiceDemo
Essentially you create a Service:
[Service]
public class MyForegroundService : Service
{
}
Then you start it from your Activity with an Intent:
var intent = new Intent(this, typeof(MyForegroundService));
StartForegroundService(intent);
In your Service you will need to call StartForeground
in a OnStartCommand
override, otherwise the service will just get killed.
Question is though. Do you really need a foreground service and keep running SignalR in the background?
Have you thought about polling the back-end once in a while to fetch latest messages?
Have you thought about sending push notifications when the user receives a new message?
You will encounter a bigger limitation if you decide to target iOS as well. There it will be impossible for you to keep your SignalR connection alive.