Search code examples
androidxamarin.formswifiiot

Xamarin Forms / Maui connecting and disconnecting to IoT Device WiFi access point from Android


I am maintaining an App written in Xamarin forms (Android) that controls an IoT device.

The issue I am facing is related to the user connecting to the IoT device to provide it with WiFi connection credentials so the IoT device can communicate across the internet. Whilst I can establish the connection to the IoT device access point and push the connection credentials in, when the IoT device closes the access point, the App seems to loose all ability to connect to the internet (our API Endpoints can not be reached) despite the smart phone device having full connectivity (I have checked that it has reconnected to its original network, and that I can open a web page). If I close and restart the app all works again - so pretty certain the act of connecting to the Access Point and returning to the connection is at fault.

I am either doing something wrong in the way I am connecting to or terminating the connection, but I am at a loss!

For reference the IoT device will automatically shut down the access point as soon as it receives WiFi connection credentials.

In the main activity file of the project I have this code:

public class WifiConnector : IWifiConnector
{
private Context context = null;

public WifiConnector()
{
this.context = Android.App.Application.Context;
}


NetworkCallback _callback;
public void connect(string ssid, string password)
{
var specifier = new WifiNetworkSpecifier.Builder()
.SetSsid(ssid)
.SetWpa2Passphrase(password)
.Build();

var request = new NetworkRequest.Builder()
.AddTransportType(TransportType.Wifi) 
.RemoveCapability(NetCapability.Internet) 
.SetNetworkSpecifier(specifier) 
.Build();

_callback = new NetworkCallback();

var connectivityManager = Android.App.Application.Context.GetSystemService(
  Android.App.Application.ConnectivityService) as Android.Net.ConnectivityManager;

connectivityManager.RequestNetwork(request, _callback);
   
}

public void disconnect()
{
var connectivityManager = Android.App.Application.Context.GetSystemService(
   Android.App.Application.ConnectivityService) as Android.Net.ConnectivityManager;
connectivityManager.UnregisterNetworkCallback(_callback);
}

private class NetworkCallback : ConnectivityManager.NetworkCallback
{
public static Android.Content.Context context = Android.App.Application.Context;

Android.Net.ConnectivityManager connectivityManager = (Android.Net.ConnectivityManager)context.GetSystemService(Android.App.Application.ConnectivityService);

public Action NetworkAvailable { get; set; }

public override void OnAvailable(Network network)
{
base.OnAvailable(network);
connectivityManager.BindProcessToNetwork(network);
Xamarin.Forms.MessagingCenter.Send("OK", "network");
}

public override void OnUnavailable()
{
base.OnUnavailable();
Xamarin.Forms.MessagingCenter.Send("Fail", "network");
}
}


   
}

I call connect to connect - which works

Then once I have pushed in WiFi credentials I call disconnect. I have experimented by not calling disconnect which makes no difference. As my IoT device has no internet capabilities I have experimented by removing this RemoveCapability(NetCapability.Internet) but again no difference.

What I am looking for is for the Android device to return to its previously WiFi state and for my App to realise this.

Thanks for any assistance.


Solution

  • Microkid.

    I had the same problem as you and found a way to fix the code for hours. I hope my code will help you.

    To give you a brief explanation.... The public void disconnect() method of your code is not wrong.

    However, I just need to add one more process to disconnect and reconnect the Wi-Fi. It took me a long time to find this answer, but I hope it helps you!

    public void DisConnect()
        {
            var connectivityManager = Android.App.Application.Context.GetSystemService(Android.App.Application.ConnectivityService) as Android.Net.ConnectivityManager;
    
            connectivityManager.UnregisterNetworkCallback(_callback);
    
            bool whileTrigger = false;
            IEnumerable<ConnectionProfile> profiles = Connectivity.Current.ConnectionProfiles;
            while (!whileTrigger)
            {
                if (profiles.Contains(ConnectionProfile.WiFi))
                {
                    var request = new NetworkRequest.Builder()
                        .AddTransportType(TransportType.Wifi)
                        .RemoveCapability(NetCapability.Internet)
                        .AddCapability(NetCapability.Trusted)
                        .AddCapability(NetCapability.NotRestricted)
                        .RemoveCapability(NetCapability.NotMetered)
                        .RemoveCapability(NetCapability.NotVpn)
                        .RemoveCapability(NetCapability.Foreground)
                        .RemoveCapability(NetCapability.NotCongested)
                        .RemoveCapability(NetCapability.NotSuspended)
                        .RemoveCapability(NetCapability.NotRoaming)
                        .Build();
    
                    connectivityManager.RequestNetwork(request, _callback);
    
                    whileTrigger = true;
                }
    
                if (whileTrigger)
                {
                    MainThread.BeginInvokeOnMainThread(() =>
                    {
                        var toast = Toast.Make($"Escape", ToastDuration.Short, 15);
                        toast.Show();
                    });
                    break;
                }
                Thread.Sleep(500);
                MainThread.BeginInvokeOnMainThread(() =>
                {
                    var toast = Toast.Make($"Search Loading", ToastDuration.Short, 15);
                    toast.Show();
                });
            }
    
        }
    

    Once again, add connectivityManager.RequestNetwork(request, _callback); to the Disconnect() method and connect it back to the Wi-Fi that your phone is holding as Default.

    This is the solution for me I hope it helps, buddy!