zoukankan      html  css  js  c++  java
  • Android WiFi开发教程(二)——WiFi的搜索和连接

    在上一篇中我们介绍了WiFi热点的创建和关闭,如果你还没阅读过,建议先阅读上一篇文章Android WiFi开发教程(一)——WiFi热点的创建与关闭。 本章节主要继续介绍WiFi的搜索和连接。

    WiFi的搜索

      /* 搜索wifi热点
         */
        private void search() {
            if (!wifiManager.isWifiEnabled()) {
                //开启wifi
                wifiManager.setWifiEnabled(true);
            }
            wifiManager.startScan();
        }

    我们在开始搜索WiFi之前确保当前WiFi功能是处于开启状态。如果未开启,通过调用WifiManager的setWifiEnabled(boolean enable)去开启。之后调用startScan()就开始扫描附近的WiFi了。而获取扫描的结果我们就需要创建一个广播接收者来处理。

    private BroadcastReceiver receiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                final String action = intent.getAction();
                if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
                    // wifi已成功扫描到可用wifi。
                    List<ScanResult> scanResults = wifiManager.getScanResults();
                    wifiListAdapter.clear();
                    wifiListAdapter.addAll(scanResults);
                } 
        };

    系统在扫描结束后,会发出WifiManager.SCAN_RESULTS_AVAILABLE_ACTION的广播,当我们的接收者接收到这个广播的时候,通过WifiManager的getScanResults()就能获取到扫描结果的集合了。ScanResult保存着每一个WiFi的信息。这里我将这个集合设置到Adapter中,并在列表中展示出来。下面是Apater中主要的代码:

     @Override
        public View getView(int position, View convertView, ViewGroup parent) {
    
            if (convertView == null) {
                convertView = mInflater.inflate(mResource, parent, false);
            }
    
            TextView name = (TextView) convertView.findViewById(R.id.wifi_name);
            TextView signl = (TextView) convertView.findViewById(R.id.wifi_signal);
    
            ScanResult scanResult = getItem(position);
            name.setText(scanResult.SSID);
    
            int level = scanResult.level;
            if (level <= 0 && level >= -50) {
                signl.setText("信号很好");
            } else if (level < -50 && level >= -70) {
                signl.setText("信号较好");
            } else if (level < -70 && level >= -80) {
                signl.setText("信号一般");
            } else if (level < -80 && level >= -100) {
                signl.setText("信号较差");
            } else {
                signl.setText("信号很差");
            }
    
            return convertView;
        }

    可以看出列表展示的数据也是比较简单,只有WiFi的名称和信号强度,这两个数据也是平时用得比较多的。获取到扫描结果后,我们就可以处理连接的逻辑了。

    WiFi的连接

    WiFi的连接相当于搜索就要复杂一些。首先给列表项设置点击事件,获取对应的ScanResult。

       listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                    wifiManager.disconnect();
                    final ScanResult scanResult = wifiListAdapter.getItem(position);
                     String capabilities = scanResult.capabilities;
                    int type = WIFICIPHER_WPA;
                    if (!TextUtils.isEmpty(capabilities)) {
                        if (capabilities.contains("WPA") || capabilities.contains("wpa")) {
                            type = WIFICIPHER_WPA;
                        } else if (capabilities.contains("WEP") || capabilities.contains("wep")) {
                            type = WIFICIPHER_WEP;
                        } else {
                            type = WIFICIPHER_NOPASS;
                        }
                    }
                    config = isExsits(scanResult.SSID);
            });

    获取到ScanResult后我们通过他的capabilities属性判断WiFi的加密方式。接着通过isExsits(String SSID)方法判断系统是否保存着当前WiFi的信息。

    private WifiConfiguration isExsits(String SSID) {
            List<WifiConfiguration> existingConfigs = wifiManager.getConfiguredNetworks();
            for (WifiConfiguration existingConfig : existingConfigs) {
                if (existingConfig.SSID.equals(""" + SSID + """)) {
                    return existingConfig;
                }
            }
            return null;
        }

    如果之前连接过,则返回WiFi的配置信息,否则返回空对象。然后接着处理连接的逻辑

    if (config == null) {
                        if (type != WIFICIPHER_NOPASS) {//需要密码
                            final EditText editText = new EditText(MainActivity.this);
                            final int finalType = type;
                            new AlertDialog.Builder(MainActivity.this).setTitle("请输入Wifi密码").setIcon(
                                    android.R.drawable.ic_dialog_info).setView(
                                    editText).setPositiveButton("确定", new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialog, int which) {
                                    Log.w("AAA", "editText.getText():" + editText.getText());
                                    config = createWifiInfo(scanResult.SSID, editText.getText().toString(), finalType);
                                    connect(config);
                                }
                            })
                                    .setNegativeButton("取消", null).show();
                            return;
                        } else {
                            config = createWifiInfo(scanResult.SSID, "", type);
                            connect(config);
                        }
                    } else {
                        connect(config);
                    }

    当没有获取到所要连接WiFi的配置信息时,我们就需要用到前面获取到的加密方式判断是否需要输入密码。如果加密方式为WAP或WEP时,则弹出提示框提示用户输入WiFi密码。用户输入密码后再调用connect(WifiConfiguration config)方法

    如果可以获取到所要连接WiFi的配置信息,则直接调用connect(WifiConfiguration config)。

    private void connect(WifiConfiguration config) {
            int wcgID = wifiManager.addNetwork(config);
            wifiManager.enableNetwork(wcgID, true);
        }

    直接调用WifiManger的addNetwork方法,将配置信息传进去后,会创建一个新的网络描述的身份并返回回来,如果返回来是-1,则表示创建失败。获取到身份后,调用enableNetwork方法就能开始连接WiFi了。到了这里,我们连接部分就完成了一半,接下来需要继续处理WiFi连接过程中返回来的状态。这里同样我们是需要用到广播接收者来处理。

    if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
      NetworkInfo info = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
    
                    if (info.getState().equals(NetworkInfo.State.DISCONNECTED)) {
                        text_state.setText("连接已断开");
                    } else if (info.getState().equals(NetworkInfo.State.CONNECTED)) {
                        WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
                        final WifiInfo wifiInfo = wifiManager.getConnectionInfo();
                        text_state.setText("已连接到网络:" + wifiInfo.getSSID());
    
                        }
                    } else {
                        NetworkInfo.DetailedState state = info.getDetailedState();
                        if (state == state.CONNECTING) {
                            text_state.setText("连接中...");
                        } else if (state == state.AUTHENTICATING) {
                            text_state.setText("正在验证身份信息...");
                        } else if (state == state.OBTAINING_IPADDR) {
                            text_state.setText("正在获取IP地址...");
                        } else if (state == state.FAILED) {
                            text_state.setText("连接失败");
                        }
                    }
    
                }

    上面是广播接收者中的关键代码。WiFi在连接的过程中系统会发出WifiManager.NETWORK_STATE_CHANGED_ACTION的广播,当接收者接收到这条广播时,获取NetworkInfo的state来判断当前的连接状态。状态值分别代表如下

    NetworkInfo.State.DISCONNECTED //连接已断开
    NetworkInfo.State.CONNECTED //已成功连接
    

    除了这两个状态之外,这里还判断了其他状态

    NetworkInfo.DetailedState state = info.getDetailedState();
                        if (state == state.CONNECTING) {
                            text_state.setText("连接中...");
                        } else if (state == state.AUTHENTICATING) {
                            text_state.setText("正在验证身份信息...");
                        } else if (state == state.OBTAINING_IPADDR) {
                            text_state.setText("正在获取IP地址...");
                        } else if (state == state.FAILED) {
                            text_state.setText("连接失败");
                        }

    DetailedState中包含了很多连接状态的信息,这里只对部分状态进行处理,其他状态值解析具体如下

    IDLE:空闲
    SCANNING:正在扫描
    CONNECTING:连接中
    AUTHENTICATING:正在进行身份验证
    OBTAINING_IPADDR:正在获取Ip地址
    CONNECTED:已连接
    SUSPENDED:已暂停
    DISCONNECTING:正在断开连接
    DISCONNECTED:已断开
    FAILED:失败
    BLOCKED:已阻止
    VERIFYING_POOR_LINK:暂时关闭(网络状况不佳)
    CAPTIVE_PORTAL_CHECK:判断是否需要浏览器二次登录

    到这里WiFi连接的逻辑就处理完成了,相对于WiFi热点的创建和关闭,搜索和连接确实要复杂一些。欢迎阅读下一篇Android WiFi开发教程(三)——WiFi热点数据传输

  • 相关阅读:
    Evanyou Blog 彩带
    Evanyou Blog 彩带
    Evanyou Blog 彩带
    Evanyou Blog 彩带
    Evanyou Blog 彩带
    Evanyou Blog 彩带
    Evanyou Blog 彩带
    Evanyou Blog 彩带
    数论12——浅谈指数与对数
    数论11——大组合数
  • 原文地址:https://www.cnblogs.com/Free-Thinker/p/7552233.html
Copyright © 2011-2022 走看看