在AndroidXamarin中连接到wifi接入点的问题

问题描述

我目前正在一个项目中,我有一个Android应用程序,该应用程序需要连接到IoT设备并向其发送一些信息。物联网设备使用带有ATWINC1500 wifi模块的SAMD21微控制器。 ATWINC1500能够创建我应该能够从Android设备连接到的wifi接入点。它能够进行wifi直接(p2p)连接,并且不具有任何蓝牙功能。当前,在IoT设备上,我让它创建一个接入点,然后旋转服务器以侦听传入的连接。只是为了提供信息,目前wifi接入点是 open ,没有密码或密钥。

我的简化程序流程是这样:

  1. 在Android设备上,扫描可用的wifi网络,然后找到与IoT设备创建的接入点名称匹配的网络。
  2. 连接到IoT设备的访问点
  3. 创建一个TcpClient并连接到IoT设备上的服务器(IP地址为192.168.1.1)。
  4. 将一些信息发送到IoT设备。

在Android方面,我将C#与Xamarin一起使用。我有几个不同的测试设备:运行Android 10的10英寸平板电脑和运行Android 8.1的5英寸手机。我研究了Android文档以及其他一些Stack Overflow帖子,其中详细介绍了如何以编程方式使Android设备连接到wifi接入点。以下是我阅读过的其他一些Stack Overflow帖子:

  1. Connect To Wifi Android Q
  2. How to connect to WiFi programmatically
  3. How do I connect to a specific Wi-Fi network in Android programmatically?
  4. Android Q,programmatically connect to different WiFi AP for internet
  5. Android 10 / API 29 : how to connect the phone to a configured network?

不幸的是,即使查看所有这些来源,我也得出了一些不同的结果。它偶尔会起作用,但是只有很少的时间。 Android还具有单独的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_managerwifi_manager代码的其他地方定义,它们分别是类型ConnectivityManagerWifiManager。另外,network_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();
    }
}

最后,您会注意到,在调用“ OnAvailable”方法时,它将调用事件处理程序。事件处理程序调用方法是我实际上创建一个TcpClient并尝试连接到IoT设备上的服务器的地方。定义如下:

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),data.Length);

    //disconnect from the server
    writer.Close();
    client.Close();
}

现在,我发现该程序可以以几种不同的方式运行。 如果我正在Android 8.1设备上运行该应用程序,则在许多其他StackOverflow问题/答案中找到的典型3行代码也无法正常工作以连接到wifi美联社:

wifi_manager.disconnect();
wifi_manager.EnableNetwork(network_id,true);
wifi_manager.Reconnect();

必须包括RequestNetwork类中对ConnectivityManager调用,以使其甚至完全连接到wifi AP,这就是为什么存在以下代码行的原因:

connectivity_manager.RequestNetwork(network_request,network_callback);

但是,即使在Android 8.1和Android 10上都使用对RequestNetwork调用,它仍然无法完全正常工作。如果我只是停在那里并尝试创建TcpClient并连接到AP上的服务器,则会收到网络无法访问异常。

因此,经过大量研究和深入研究,我决定在调用OnAvailable之后在RequestNetwork方法添加以下代码

parent.connectivity_manager.BindProcesstoNetwork(network);

这似乎有时会有所帮助。它将TcpClient连接到AP的成功率从0%提高到了10%或20%,但是不幸的是,现在我经常遇到拒绝连接异常。

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

任何人都可以帮助阐明为什么我遇到这些例外情况吗?连接到AP是否缺少我的步骤?感谢您的帮助!

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)