Android(Xamarin)中连接wifi接入点的问题

Android(Xamarin)中连接wifi接入点的问题,android,xamarin,wifi,android-wifi,wifimanager,Android,Xamarin,Wifi,Android Wifi,Wifimanager,我目前正在进行一个项目,其中我有一个Android应用程序,需要连接到物联网设备并向其发送一些信息。物联网设备使用带有ATWINC1500 wifi模块的SAMD21微控制器。ATWINC1500能够创建一个wifi接入点,我应该能够从Android设备连接到该接入点。它不支持wifi直接(p2p)连接,也没有任何蓝牙功能。目前,在物联网设备上,我让它创建一个接入点,然后启动一个服务器来监听传入的连接。只是为了获取信息,wifi接入点目前处于开放状态,没有密码或钥匙 我的简化程序流程如下: 在A

我目前正在进行一个项目,其中我有一个Android应用程序,需要连接到物联网设备并向其发送一些信息。物联网设备使用带有ATWINC1500 wifi模块的SAMD21微控制器。ATWINC1500能够创建一个wifi接入点,我应该能够从Android设备连接到该接入点。它不支持wifi直接(p2p)连接,也没有任何蓝牙功能。目前,在物联网设备上,我让它创建一个接入点,然后启动一个服务器来监听传入的连接。只是为了获取信息,wifi接入点目前处于开放状态,没有密码或钥匙

我的简化程序流程如下:

  • 在Android设备上,扫描可用的wifi网络,并找到与物联网设备创建的接入点名称匹配的网络
  • 连接到物联网设备的接入点
  • 创建TCP客户端并连接到IoT设备上的服务器(IP地址为192.168.1.1)
  • 向物联网设备发送一些信息
  • 在安卓方面,我使用C#和Xamarin。我有两个不同的测试设备:一个运行安卓10的10英寸平板电脑和一个运行安卓8.1的5英寸手机。我研究了Android文档以及其他几个堆栈溢出帖子,详细介绍了如何通过编程将Android设备连接到wifi接入点。以下是我读过的其他几个堆栈溢出帖子:

  • 不幸的是,即使在查看了所有这些来源之后,我也得到了一些好坏参半的结果。它偶尔会起作用,但只在少数时间起作用。另一个复杂的事实是,根据设备上运行的安卓版本,安卓系统有单独的API用于连接wifi

    以下是我实际连接到wifi接入点的主要方法:

    public void ConnectToWifiNetwork(string ssid)
    {
        if (Android.OS.Build.VERSION.SdkInt >= BuildVersionCodes.Q)
        {
            var wifi_network_specifier = (new WifiNetworkSpecifier.Builder()).SetSsid(ssid).Build();
            var network_request = (new NetworkRequest.Builder()).AddTransportType(TransportType.Wifi)
                .SetNetworkSpecifier(wifi_network_specifier).Build();
            connectivity_manager.RequestNetwork(network_request, network_callback);
        }
        else if (Android.OS.Build.VERSION.SdkInt >= BuildVersionCodes.Lollipop)
        {
            //See if the desired network configuration already exists
            var configured_networks = wifi_manager.ConfiguredNetworks;
            var specified_network = configured_networks.Where(x => x.Ssid.Contains(ssid)).FirstOrDefault();
            int network_id = -1;
    
            //If no network configuration already exists....
            if (specified_network == null)
            {
                //Create a wifi configuration with the appropriate SSID
                specified_network = new WifiConfiguration();
                specified_network.Ssid = '"' + ssid + '"';
                specified_network.AllowedKeyManagement.Set((int)Android.Net.Wifi.KeyManagementType.None);
    
                //Add the configuration to the wifi manager's list of configured networks
                network_id = wifi_manager.AddNetwork(specified_network);
            }
            else
            {
                //Otherwise, if a network configuration does already exist, grab the network ID
                network_id = specified_network.NetworkId;
            }
    
            //If we have a valid network ID...
            if (network_id != -1)
            {
                //Let's attempt to connect to the network
                wifi_manager.Disconnect();
                wifi_manager.EnableNetwork(network_id, true);
                wifi_manager.Reconnect();
    
                //Now let's bind to the network we just connected to
                var network_request = (new NetworkRequest.Builder()).AddTransportType(TransportType.Wifi).Build();
                connectivity_manager.RequestNetwork(network_request, network_callback);
            }
        }
    }
    
    请注意,变量
    connectivity\u manager
    wifi\u manager
    在代码的其他地方定义,它们分别属于
    ConnectivityManager
    WifiManager
    类型。另外,
    network\u callback
    变量也在代码中的其他地方定义,它的类型为
    WifiConnectorNetworkCallback
    ,我将其定义为:

    class WifiConnectorNetworkCallback : ConnectivityManager.NetworkCallback
    {
        WifiConnector source;
    
        public WifiConnectorNetworkCallback(WifiConnector p)
        {
            source = p;
        }
    
        public override void OnAvailable(Network network)
        {
            source.connectivity_manager.BindProcessToNetwork(network);
            source.WifiNetworkConnected?.Invoke(source, new EventArgs());
        }
    
        public override void OnUnavailable()
        {
            base.OnUnavailable();
        }
    }
    
    private void WifiNetworkConnected(object sender, EventArgs e)
    {
        TcpClient client = new TcpClient();
        client.Connect(IPAddress.Parse("192.168.1.1"), 80);
        
        //Create a network stream to send data
        NetworkStream writer = client.GetStream();
    
        //Write some data
        string data = "test";
        writer.Write(Encoding.ASCII.GetBytes(data), 0, data.Length);
    
        //Disconnect from the server
        writer.Close();
        client.Close();
    }
    
    最后,您会注意到,当调用“OnAvailable”方法时,它会调用一个事件处理程序。事件处理程序调用的方法是我实际创建TcpClient并尝试连接到IoT设备上的服务器的方法。其定义如下:

    class WifiConnectorNetworkCallback : ConnectivityManager.NetworkCallback
    {
        WifiConnector source;
    
        public WifiConnectorNetworkCallback(WifiConnector p)
        {
            source = p;
        }
    
        public override void OnAvailable(Network network)
        {
            source.connectivity_manager.BindProcessToNetwork(network);
            source.WifiNetworkConnected?.Invoke(source, new EventArgs());
        }
    
        public override void OnUnavailable()
        {
            base.OnUnavailable();
        }
    }
    
    private void WifiNetworkConnected(object sender, EventArgs e)
    {
        TcpClient client = new TcpClient();
        client.Connect(IPAddress.Parse("192.168.1.1"), 80);
        
        //Create a network stream to send data
        NetworkStream writer = client.GetStream();
    
        //Write some data
        string data = "test";
        writer.Write(Encoding.ASCII.GetBytes(data), 0, data.Length);
    
        //Disconnect from the server
        writer.Close();
        client.Close();
    }
    
    现在,我发现程序可以以几种不同的方式运行。如果我在Android 8.1设备上运行该应用程序,则在许多其他问题/答案中发现的典型3行代码无法连接到wifi AP:

    wifi_manager.Disconnect();
    wifi_manager.EnableNetwork(network_id, true);
    wifi_manager.Reconnect();
    
    我必须包括从
    ConnectivityManager
    类调用
    RequestNetwork
    ,这样它才能连接到wifi AP,这就是为什么存在这行代码的原因:

    connectivity_manager.RequestNetwork(network_request, network_callback);
    
    但即使在安卓8.1和安卓10上使用对
    RequestNetwork
    的调用,它仍然不能完全工作。如果我只是停在那里,尝试创建一个TcpClient并连接到AP上的服务器,我会得到一个网络不可访问的异常

    因此,经过大量的研究和挖掘,我决定在调用
    RequestNetwork
    后,在
    OnAvailable
    方法中添加以下代码行:

    parent.connectivity_manager.BindProcessToNetwork(network);
    
    这有时似乎有帮助。它使我使用TcpClient连接AP的成功率从0%提高到10%或20%,但不幸的是,现在我经常遇到连接被拒绝的异常

    现在,我似乎有一种方法获得了100%的成功率:如果我使用Android设置应用程序手动连接到wifi AP,然后返回Android应用程序并创建TcpClient,它似乎每次都能成功运行。因此,我不认为物联网微控制器方面存在缺陷。Android中似乎发生了一些事情,如果我手动连接到AP,它可以正常工作,但是使用上面描述的代码连接到AP,我总是会遇到“网络不可访问”“连接被拒绝”异常


    有人能帮我澄清为什么我会遇到这些例外情况吗?在连接AP时,我是否缺少一个步骤?谢谢你的帮助

    Android Q上的这个新API非常感谢您链接到您优秀的博客文章。事实上,看起来我们的方法非常相似。如果我以前手动添加网络,我似乎会获得更好的成功,但这违背了我正在尝试的目的。我希望物联网设备上的wifi模块支持P2P连接,这样我就可以使用该API,但可惜它没有。我正在考虑切换到另一个支持BLE的模块,希望Android BLE API和该模块可以更好地相互配合。