首页 > 解决方案 > 如何在没有互联网的情况下以编程方式连接到 Wifi Android (Xamarin)

问题描述

我的应用需要使用 wifi 网络(没有互联网,因此 android 默认避免使用它)。而且我希望它易于使用(就像奶奶不必手动更改设置一样)。这只是个人物联网设备,所以我想使用ConnectivityManager.BindProcessToNetwork(Android.Net.Network network). 如何获取与当前连接的 wifi 网络关联的 Android.Net.Network 以便我可以使用BindProcessToNetwork

//c#(Xamarin)
//my rudimentary attempt to get the connected wifi network:

var networks = ConnectivityManager.GetAllNetworks();
foreach (Network network in networks) {
                NetworkCapabilities networkCability =ConnectivityManager.GetNetworkCapabilities(network);

                if (networkCability.HasTransport(TransportType.Wifi))
                {
                    currentWifiNetwork = network;  // this is never reached
                }
}
ConnectivityManager.BindProcessToNetwork( currentWifiNetwork );

Network对于当前使用的所有手机 WiFi、蜂窝网络等...网络,难道没有一个不同的对象吗?

这个博客让我很接近:https ://android-developers.googleblog.com/2016/07/connecting-your-app-to-wi-fi-device.html 。

绑定套接字方法也可以工作(除非 wifi 网络在检查之前不是可用网络use network without internet box)。我只需要应用程序通过 wifi 使用端口 8080 上的 url。我想避免手动告诉Android“使用没有互联网的网络”。干杯

更新

当我运行它时,只有两个网络返回ConnectivityManager.GetAllNetworks(),并在调试器中查看它们,一个是具有 Internet 和 mms 的蜂窝网络,另一个是另一个没有 Internet 和 mms 的蜂窝网络。所以没有ConnectivityManager.GetAllNetworks()没有得到wifi网络,因为它看起来android甚至不会添加wifi网络,除非它有互联网!如果手机数据被禁用,Android 将切换并使用无互联网 wifi 进行所有流量(无需检查无论如何都使用网络框)。因此,它们必须是一种将 WiFi 网络绑定到应用程序的方法!或者...

如何以编程方式选中该use network anyways框!?

我还没有看到解决方案。只是整个网络上的一堆悬而未决的问题。按照这个速度,我可能只在 iot 设备上使用 dnsmasq 和一个欺骗性的网络服务器来让 android 认为它有互联网。我还看到 API 29 具有 NetworkBuilder,并且您可以指定对没有 Internet 功能的 WiFi 网络的请求……但我需要较低的 API 支持。

标签: androidxamarin.android

解决方案


这是我想出的解决方案(对于 Api 28 )。它通过 NetworkRequest 将 WiFi 优先于 4G/5G(数据)而不考虑互联网功能,然后允许 4G/5G(数据)和应用程序使用其本地 WiFi 服务:

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;

        }

这个回调然后将适当的 WIFI 网络绑定到应用程序(进程)!允许用户同时通过 WIFI 使用本地服务器的应用程序和其他仍然需要互联网的应用程序,因为 Android 操作系统可以允许其他进程通过 4G/5G 数据连接访问互联网!

 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 将当前进程绑定到网络。将来创建的所有套接字(并且未通过 Network.getSocketFactory() 中的绑定 SocketFactory 显式绑定)将绑定到网络。所有主机名解析也将限制为网络。” -安卓文档


推荐阅读