当前位置 博文首页 > 淡了点:通过wifi与设备进行通信(Android)

    淡了点:通过wifi与设备进行通信(Android)

    作者:[db:作者] 时间:2021-08-05 19:05

    通过wifi与设备进行通信(Android)

    最近leader决定把app与设备之间的通信改为wifi,通过http协议实现设备之间的通信。
    相对与之前的蓝牙通信,的确简单不少,但实际编码当中也有坑。现在分享出来,希望能给需要的鞋童以帮助,有啥问题大家也可以讨论一下。

    切换手机wifi到指定wifi热点

    baidu或者google输入以上内容搜索,会出现很多相关资料,但是点开之后,才发现大多都是一样,那么实用性怎么样,于是我验证了一下。
    大致思路是,首先创建WifiConfiguration,按照wifi加密方式分为无密码,有密码(WEP,WPA)。

    // 创建 WifiConfiguration
    public WifiConfiguration CreateWifiInfo(String ssid, String password, int type) {     
          WifiConfiguration config = new WifiConfiguration();          
          config.SSID = "\"" + ssid + "\"";       
          WifiConfiguration tempConfig = this.IsExsits(ssid);               
          if(tempConfig != null) {      
              mWifiManager.removeNetwork(tempConfig.networkId);      
          }    
          if(Type == 1) //WIFICIPHER_NOPASS {     
                此处省略……
          }     
          if(Type == 2) //WIFICIPHER_WEP {  
                此处省略……      
          }     
          if(Type == 3) //WIFICIPHER_WPA {   
                此处省略……       
          }    
           return config;     
    } 
    

    从代码中看,之中还判断ssid是否存在,如果存在就用removeNetwork将此ssidwifi从已配置信息wifi列表中remove掉。这一步是必要的,因为ssid就是手机wifi列表中wifi的名称。具有相同ssidwifi可能并不是同一wifi,如果使用了上次保留的配置信息,就可能到导致自动连接wifi失败。但此代码因为是很早之前写的,所以在android6.0版本上并不适用。android6.0新特性加强了对手机权限控制,同时在wifi模块也不再允许对已保存的wifi配置列表进行更新和删除,这将会导致removeNetwork操作失败。

    下面看一下添加切换手机到指定wifi热点的代码

    // 更改前写法
    public boolean addNetwork(WifiConfiguration wcg) {     
         int wcgID = mWifiManager.addNetwork(wcg);     
         boolean b =  mWifiManager.enableNetwork(wcgID, true);     
         return b;  
    }
    

    此代码的确能使部分手机成功切换到指定wifi,但其实代码并不规范,这将会导致在部分手机中切换失败。下面介绍正确写法

    //更改后写法
    public boolean addNetwork(WifiConfiguration wifiConfiguration) {   
        mWifiManager.disconnect();
        int networkId = mWifiManager.addNetwork(wifiConfiguration);
        boolean res = mWifiManager.enableNetwork(networkId, true);
        mWifiManager.saveConfiguration();
        mWifiManager.reconnect();
        return res;
    }
    

    指定通过wifi进行http请求

    不要以为这样就完了,还有个大坑在等我们

    在测试过程中,突然发现,在手机wifi和数据流量同时存在时,部分手机会直接使用数据流量进行通信,这样就导致手机与设备之间无法通信,因为手机与设备只有处在同一局域网下才能正常通信。

    这可麻烦了,于是到处到解决办法,终于在WifiManager 这个类找到一个方法enableNetwork上面有一大段英文,我们一起看一下。

    /**
     * Allow a previously configured network to be associated with. If
     * <code>disableOthers</code> is true, then all other configured
     * networks are disabled, and an attempt to connect to the selected
     * network is initiated. This may result in the asynchronous delivery
     * of state change events.
     * <p>
     * <b>Note:</b> If an application's target SDK version is
     * {@link android.os.Build.VERSION_CODES#LOLLIPOP} or newer, network
     * communication may not use Wi-Fi even if Wi-Fi is connected; traffic may
     * instead be sent through another network, such as cellular data,
     * Bluetooth tethering, or Ethernet. For example, traffic will never use a
     * Wi-Fi network that does not provide Internet access (e.g. a wireless
     * printer), if another network that does offer Internet access (e.g.
     * cellular data) is available. Applications that need to ensure that their
     * network traffic uses Wi-Fi should use APIs such as
     * {@link Network#bindSocket(java.net.Socket)},
     * {@link Network#openConnection(java.net.URL)}, or
     * {@link ConnectivityManager#bindProcessToNetwork} to do so.
     *
     * @param netId the ID of the network in the list of configured networks
     * @param disableOthers if true, disable all other networks. The way to
     * select a particular network to connect to is specify {@code true}
     * for this parameter.
     * @return {@code true} if the operation succeeded
     */
    

    从第七行开始,大概意思就是,在应用目标版本大于或等于LOLLIPOP(5.0) 就算wifi是已连接的,网络通信也可能不用wifi,比喻说蜂窝数据。当 wifi 与蜂窝数据同时存在时,当wifi无法使用时,系统会自动切换到蜂窝数据。这不就是我们出现的问题吗,下面赶紧找解决办法。接着看,app确保使用wifi进行通信,应该使用下面三个方法 APIbindSocketopenConnectionbindProcessToNetwork。这个是不是说的有点抽象,就说三个方法,不告诉到底怎么样。额,我们只有迅速补脑了。

        ConnectivityManager mConnectivityManager = (ConnectivityManager)Context.getSystemService(Context.CONNECTIVITY_SERVICE);
        final NetworkRequest networkRequest = new NetworkRequest.Builder()
                .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
                .build();
        mConnectivityManager.requestNetwork(networkRequest, new ConnectivityManager.NetworkCallback(){
            @Override
            public void onAvailable(Network network) {
                String url = "";
                try {
                    HttpURLConnection conn = (HttpURLConnection) network.openConnection(new URL(url));
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });
    

    原来解决办法在 ConnectivityManager 这个类的方法 requestNetwork 可以指定使用 wifi 或者蜂窝数据等访问网络。如果要指定用蜂窝数据进行通信,将 addTransportType 设置为TRANSPORT_CELLULAR即可。在有可用指定传输类型连接上后,onAvailable方法就会调用,其实主要就是获取到 NetworkNetwork 通过 openConnection 得到 HttpURLConnection ,相信大家对HttpURLConnection十分熟悉,直接用它发起网络请求就可以了。

    联系我

    github 个人地址

    cs
    下一篇:没有了