Search code examples
androidxamarinxamarin.formssignalrsignalr-hub

Xamarin background disconnected signalr


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?


Solution

  • 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.