Android中wifi开发总结

一、开发中所需要的权限






二、Wifi基础知识

1、开发中常用类和常量

类名 功能
WifiManager wifi统一管理类,进行各种wifi操作
WifiInfo 描述当前连接的wifi热点信息
WifiConfiguration wifi网络配置信息

除此之外还有一个类:

类名 功能
ScanResult 描述扫描出的wifi热点的信息,每个wifi对应一个ScanResult

 常用wifi名词解释:

名称 功能
SSID 描述wifi热点的名称,就是大家搜索到的直接名称,如ChinaNet
BSSID 姑且理解成热点的mac地址,但实际有所不同
networkID 数字型的id
RSSI 描述wifi信号强弱的值,官方叫做level

 手机输入wifi密码连上后,下一次可以不用输入密码甚至是自动连接,就是因为手机中其实已经存储了wifi的信息,每个wifi有对应的networkid

打开和关闭wifi的总开关:

WifiManager mWifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
// 打开wifi开关
mWifiManager.setWifiEnabled(true);
// 关闭wifi开关
mWifiManager.setWifiEnabled(false);

wifi打开和关闭的状态常量,都封装在WifiManager中:

Android中wifi开发总结_第1张图片

可以在任何时候通过mWifiManager.getWifiState()来获取当前wifi的状态:

mWifiManager.setWifiEnabled(true);
if (mWifiManager.getWifiState() == WifiManager.WIFI_STATE_DISABLING) {
      // wifi正在关闭
} else if (mWifiManager.getWifiState() == WifiManager.WIFI_STATE_DISABLED) {
      // wifi已关闭
} else if (mWifiManager.getWifiState() == WifiManager.WIFI_STATE_ENABLING) {
      // wifi正在开启
} else if (mWifiManager.getWifiState() == WifiManager.WIFI_STATE_ENABLED) {
      // wifi已开启
} else if (mWifiManager.getWifiState() == WifiManager.WIFI_STATE_UNKNOWN) {
      // 未知状态
}

wifi状态的变化会发出下列的广播事件:
WifiManager.WIFI_STATE_CHANGED_ACTION                  wifi开关变化通知
WifiManager.SCAN_RESULTS_AVAILABLE_ACTION         wifi扫描结果通知
WifiManager.SUPPLICANT_STATE_CHANGED_ACTION   wifi连接结果通知
WifiManager.NETWORK_STATE_CHANGED_ACTION       网络状态变化通知
 

2、Wifi搜索和连接

(1)、搜索周围wifi信号:

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

(2)、获取扫描到的wifi

调用上述方法以后就开始搜索wifi了,当搜到wifi以后系统会发广播出来,监听广播来获取搜索到的wifi:因为wifiManager.getScanResults()每次获取的都是左右的扫到的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 scanResults = wifiManager.getScanResults();
                wifiListAdapter.clear();
                wifiListAdapter.addAll(scanResults);
            } 
    };

(3)、wifi连接

private static final int WIFICIPHER_NOPASS = 1;
private static final int WIFICIPHER_WEP = 2;
private static final int WIFICIPHER_WPA = 3;

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);
                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是否有保存
     *
     * @param SSID
     * @return
     *   当没有获取到所要连接WiFi的配置信息时,我们就需要用到前面获取到的加密方式判断是否需
     *   要输入密码。如果加密方式为WAP或WEP时,则弹出提示框提示用户输入WiFi密码。用户输入密
     *   码后再调用connect(WifiConfiguration config)方法
     */
    private WifiConfiguration isExsits(String SSID) {
        List existingConfigs = wifiManager.getConfiguredNetworks();
        for (WifiConfiguration existingConfig : existingConfigs) {
            if (existingConfig.SSID.equals("\"" + SSID + "\"")) {
                return existingConfig;
            }
        }
        // 返回空表示没保存过
        return null;
    }

    private void connect(WifiConfiguration config) {
        text_state.setText("连接中...");
        // 获取的networkId 如果为-1表示失败
        int networkID = wifiManager.addNetwork(config);
        wifiManager.enableNetwork(networkID, true);
    }

(4)、注册广播,监听连接的状态

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("连接失败");
                    }
                }
 
            }

以上代码只是监听了部分详细状态,还有很多其他的状态:

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

三、Wifi Direct Connection介绍

1、简介

蓝牙有Ble轻量连接,Wifi当然也一样,WiFi Direct Connection点对点传输不用连接网络和热点,可进行近距离通信,比蓝牙传输要远,速度更快。

Wifi Direct API主要包括以下几个部分:

(1)WifiP2pManager,该类允许用户发现、请求和连接其他支持Wifi Direct的设备

(2)监听Wifi Direct请求的广播接收器

(3)被Wifi Direct框架检测到的时间通知,例如终止连接、发现新的Wifi Direct设备等

2、Wifi Direct广播接收器, 基本都是异步的,通过发广播来通知界面

WIFI_P2P_STATE_CHANGED_ACTION     检测Wifi Direct Connection是否可用,并且将检测结果通过此广播通知界面
WIFI_P2P_PEERS_CHANGED_ACTION    搜索可用的Wifi列表完成,收到此广播可以通过mWifiP2pManager.requestPeers方法获取所有的可用的wifi列表
WIFI_P2P_CONNECTION_CHANGED_ACTION    表示Wi-Fi连接状态发生了改变  
WIFI_P2P_THIS_DEVICE_CHANGED_ACTION     响应设备的wifi状态变化

 public class WiFiDirectBroadcastReceiver extends BroadcastReceiver {
        private WifiP2pManager.Channel channel;
        private WifiP2pManager manager;
        private MainActivity activity;
        public WiFiDirectBroadcastReceiver(WifiP2pManager.Channel channel, WifiP2pManager manager) {
            super();
            this.channel = channel;
            this.manager = manager;
        }
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (action.equals(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION)) {
                // 确定Wi-Fi Direct模式是否可用
                int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);
                if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) {
                    // 可用
                } else {
                    // 不可用
                }
            } else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {
                // 发现设备后会发此通知来获取数据
                if (manager != null) {
                    // 获取扫到的设备列表也是异步,因此需要回调
                    manager.requestPeers(channel, new WifiP2pManager.PeerListListener() {
                        @Override
                        public void onPeersAvailable(WifiP2pDeviceList peers) {
                            // 参数就是扫到的wifi设备列表
                            Collection deviceList = peers.getDeviceList();
                        }
                    });
                }
            } else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {
                // 当用户点击扫描到的列表上某个设备去连接的时候,连接状态会发此广播来通知,连接成功以后就可以获取WifiP2pInfo获取连接设备的具体信息了
                if (manager != null) {
                    NetworkInfo networkInfo = (NetworkInfo) intent.getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO);
                    if (networkInfo.isConnected()) {
                        // 请求连接设备的信息,拿到WifiP2pInfo后就可以跟别的设备通信了
                        manager.requestConnectionInfo(channel, new WifiP2pManager.ConnectionInfoListener() {
                            @Override
                            public void onConnectionInfoAvailable(WifiP2pInfo info) {

                            }
                        });
                    } else {
                        // ...
                    }
                }
            } else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION
                    .equals(action)) {
                //连接设备信息改变
                // ...
            }
        }
    }

 

3、初始化

WifiP2pManager mManager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE); 
WifiP2pManager.Channel mChannel = mManager.initialize(this, getMainLooper(), null); 
WiFiDirectBroadcastReceiver mReceiver = new WiFiDirectBroadcastReceiver(mManager, mChannel);

4、查找设备

mManager.discoverPeers(channel, new WifiP2pManager.ActionListener() {
    @Override
    public void onSuccess() {
        ...
    }

    @Override
    public void onFailure(int reasonCode) {
        ...
    }
});

Wifi扫到设备后会统一回调,这里只是提示用户已经查找成功,具体获取扫到的列表数据要去广播(WIFI_P2P_PEERS_CHANGED_ACTION)中通过mManager.requestPeers()获取

5、连接设备

WifiP2pDevice device;
WifiP2pConfig config = new WifiP2pConfig();
config.deviceAddress = device.deviceAddress;
config.wps.setup = WpsInfo.PBC;
mManager.connect(mChannel, config, new ActionListener() {

    @Override
    public void onSuccess() {
        // 连接成功的通知
    }

    @Override
    public void onFailure(int reason) {
        // 连接失败的通知
    }
});

第4部的时候已经获取到了所有wifi列表,是一个Collection集合,上述方法就是连接点击的设备,上面代码中的device就是要连接的设备,连接状态会通过广播(WIFI_P2P_CONNECTION_CHANGED_ACTION)告诉用户,用户可以在收到这个广播的时候获取连接的设备信息,从而进行通信。

6、获取连接设备的信息

NetworkInfo networkInfo = (NetworkInfo) intent.getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO);
if (networkInfo.isConnected()) {
     manager.requestConnectionInfo(channel, new WifiP2pManager.ConnectionInfoListener() {
                            @Override
                            public void onConnectionInfoAvailable(WifiP2pInfo info) {

                            }
     });
}

7、通信

得到WifiP2pInfo以后,我们就可以获取到连接设备的地址,这样就可以通过Socket和它通信了,我们手机端一般是连接端,所以是客户端,其他wifi设备一般是被连接端,所以是服务端,获取到流以后就可以传文件/文本等数据了

if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {
     // 当用户点击扫描到的列表上某个设备去连接的时候,连接状态会发此广播来通知,连接成功以后就可以获取WifiP2pInfo获取连接设备的具体信息了
     NetworkInfo networkInfo = (NetworkInfo)intent.getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO);
     if (networkInfo.isConnected()) {
          mManager.requestConnectionInfo(channel, new WifiP2pManager.ConnectionInfoListener() {
              @Override
              public void onConnectionInfoAvailable(WifiP2pInfo info) {
                    try {
                         Socket socket = new Socket();
                         InetSocketAddress inetSocketAddress = new InetSocketAddress(info.groupOwnerAddress.getHostAddress(), 5330);
                         socket.connect(inetSocketAddress);
                         OutputStream outputStream = socket.getOutputStream();
                         InputStream inputStream = socket.getInputStream();
                    }
                    catch (Exception e) {

                    }

               }
           });
     }
}

 

你可能感兴趣的:(Android中wifi开发总结)