Search code examples
c#androidxamarinnetworkingcellular-network

How to connect to local network first instead of internet in C# Xamarin Android app?


I have a Xamarin Android app. It connects to a “No Internet based Wifi router” for some IOT devices. But it also needs to use mobile’s cellular data for storing some information on Dropbox.

Now this is working as follows:

  1. I can turn on/off Wifi connection programmatically.
  2. I cannot turn on/off Cellular data (since Android L). Its not allowed on non rooted devices.
  3. When my phone is connected to this local Wifi router and Cellular Data is also ON, the way Android works in default, it uses the Internet from Cellular connection and all my calls to Dropbox works without any issue.
  4. But this preference to Cellular when local Wifi has “no internet” is causing my app to never connect to local devices. Say one of my device is listening on IP 192.168.2.3 on port 9000, when I try to connect to it, my code searches it via Cellular data and returns host not found.
  5. So is there a way to connect to local devices in this scenario?
  6. As a workaround, I have manually provided modal popups to instruct users to disable Cellular when “non” Dropbox calls like connection to IOT devices are required. But this is not a good user experience as users have to keep on changing networks manually. I would like the code to handle this in a more transparent manner.

Please advise.


Solution

  • After lot of tries and failures, I was able to implement the approach provided here: Stackoverflow Link

    I changed this code from Java to Xamarin C# and was able to force Cellular or Wifi as the preferred network programmatically.

    My implementation:

    using Android.Net;
    public SomeClass{
        public static Context _context = Android.App.Application.Context;
    
        ....
    
        /// <summary>
        /// Forces the wifi over cellular.
        /// </summary>
        public static void ForceWifiOverCellular()
        {
            ConnectivityManager connection_manager = (ConnectivityManager)_context.GetSystemService(Context.ConnectivityService);
    
            NetworkRequest.Builder request = new NetworkRequest.Builder();
            request.AddTransportType(TransportType.Wifi);
    
            var callback = new ConnectivityManager.NetworkCallback();
            connection_manager.RegisterNetworkCallback(request.Build(), new CustomNetworkAvailableCallBack());
    
        }
    
        /// <summary>
        /// Forces the cellular over wifi.
        /// </summary>
        public static void ForceCellularOverWifi()
        {
            ConnectivityManager connection_manager = (ConnectivityManager)_context.GetSystemService(Context.ConnectivityService);
    
            NetworkRequest.Builder request = new NetworkRequest.Builder();
            request.AddTransportType(TransportType.Cellular);
    
            connection_manager.RegisterNetworkCallback(request.Build(), new CustomNetworkAvailableCallBack());
        }
    }
    
    
    /// <summary>
    /// Custom network available call back.
    /// </summary>
    public class CustomNetworkAvailableCallBack : ConnectivityManager.NetworkCallback
    {
        public static Context _context = Android.App.Application.Context;
    
        ConnectivityManager connection_manager = (ConnectivityManager)_context.GetSystemService(Context.ConnectivityService);
    
        public override void OnAvailable(Network network)
        {
            //ConnectivityManager.SetProcessDefaultNetwork(network);    //deprecated (but works even in Android P)
            connection_manager.BindProcessToNetwork(network);           //this works in Android P
        }
    }
    

    Usage:

    1. Where I need to force Cellular, just call:

    SomeClass.ForceCellularOverWifi();

    1. Where I need to force Wifi, just call:

    SomeClass.ForceWifiOverCellular();

    Hope this helps others.