How to programmatically connect to Wifi with no internet Android (Xamarin)
Solution 1:
This is the solution that I came up with (for Api 28 ). It prioritizes WiFi over 4G/5G (Data) regardless of internet capability via a NetworkRequest, and then allows for both internet over 4G/5G (Data) and the app to use its local WiFi services:
public static WifiManager WifiManager { get; } = (WifiManager)Android.App.Application.Context.GetSystemService(Context.WifiService);
public static ConnectivityManager ConnectivityManager { get; set; } = (ConnectivityManager)Android.App.Application.Context.GetSystemService(Context.ConnectivityService);
public bool ConnectToWifi(string ssid, string password, bool previouslyConnected = true)
{
if (!WifiManager.IsWifiEnabled)
WifiManager.SetWifiEnabled(true); //turn on wifi if not on
var formattedSsid = $"\"{ssid}\"";
var formattedPassword = $"\"{password}\"";
var wifiConfig = new WifiConfiguration
{
Ssid = formattedSsid,
PreSharedKey = formattedPassword,
Priority = 0
};
_NetworkId = WifiManager.AddNetwork(wifiConfig);
WifiManager.Disconnect();
bool enableNetwork = WifiManager.EnableNetwork(_NetworkId, true);
NetworkRequest.Builder builder = new NetworkRequest.Builder(); //request that WiFi be prioritized over the 4G internet capable network.
builder.AddTransportType(TransportType.Wifi);
ConnectivityManager.RequestNetwork(builder.Build(), new BindNetworkCallBack ());
return enableNetwork;
}
This call back then binds the appropriate WIFI network to the app(process)! Allowing for the user to both simultaneously use the app with the local server over WIFI, and other apps that still require internet, as Android OS can allow other processes to access the internet via the 4G/5G data connection!
public class BindNetworkCallBack : ConnectivityManager.NetworkCallback
{
public override void OnAvailable(Network network)
{
if (WifiManager.ConnectionInfo.BSSID == NetworkBSSID) /*
The only way on Android (API 28+) to check if the acquired network is
the one you want is to use the BSSID (MAC address) of the network.
You can omit the if statement if you want to presume the acquired network is correct/
cannot know the MAC address...
*/
{
try
{
ConnectivityManager.BindProcessToNetwork(network);
}
catch (Exception ex)
{
Debug.WriteLine(@"\tERROR Unable to Bind process to network {0}", ex.Message);
}
}
}
}
"bindProcessToNetwork Binds the current process to network. All Sockets created in the future (and not explicitly bound via a bound SocketFactory from Network.getSocketFactory()) will be bound to network. All host name resolutions will be limited to network as well." - Android Docs