前言

今天来看看Aroid中与Wifi有关的编程,虽然项目中用的不多,但是多学点东西总是没有坏处嘛,万一哪天用上了呢。

API介绍

与wifi有关的API都在android.net.wifi包下面,我们先介绍几个比较重要的类。
(1)ScanResult
主要是通过wifi 硬件的扫描来获取一些周边的wifi 热点的信息。 在我们进行wifi 搜索的时候,一般会搜到这些信息,首先是接入点名字、接入点信息的强弱、还有接入点使用的安全模式,是WPA、WPE;打开这个类,我们可以看到以下几个信息 BSSID 接入点的地址,这里主要是指小范围几个无线设备相连接所获取的地址,比如说两台笔记本通过无线网卡进行连接,双方的无线网卡分配的地址。
SSID 网络的名字,当我们搜索一个网络时,就是靠这个来区分每个不同的网络接入点。
Capabilities 网络接入的性能,这里主要是来判断网络的加密方式等。
Frequency 频率,每一个频道交互的MHz 数。
Level 等级,主要来判断网络连接的优先数。
这里只提供了一个方法,就是将获得信息编程字符串toString()。

(2)wifiConfiguration
在我们连通一个wifi 接入点的时候,需要获取到的一些信息。大家可以跟我们有线的设备进行对比一下。
这里的数据相对来说比较复杂一下。
六个子类
WifiConfiguration.AuthAlgorthm 用来判断加密方法。
WifiConfiguration.GroupCipher 获取使用GroupCipher 的方法来进行加密。
WifiConfiguration.KeyMgmt 获取使用KeyMgmt 进行。
WifiConfiguration.PairwiseCipher 获取使用WPA 方式的加密。
WifiConfiguration.Protocol 获取使用哪一种协议进行加密。
wifiConfiguration.Status 获取当前网络的状态。
对于上述加密感兴趣的朋友,可以在网上搜索相关的内容。
设置WifiConfiguration的属性:
WifiConfiguration.AuthAlgorthm 设置加密方法。
可选参数:LEAP只用于leap,
OPEN 被wpa/wpa2需要,
SHARED需要一个静态的wep key
WifiConfiguration.GroupCipher 使用GroupCipher 的方法来进行加密。
可选参数:CCMP,TKIP,WEP104,WEP40
WifiConfiguration.KeyMgmt 键管理机制(keymanagerment),使用KeyMgmt 进行。
可选参数IEEE8021X,NONE,WPA_EAP,WPA_PSK
WifiConfiguration.PairwiseCipher 设置加密方式。
可选参数 CCMP,NONE,TKIP
WifiConfiguration.Protocol 设置一种协议进行加密。
可选参数 RSN,WPA,
wifiConfiguration.Status 设置当前网络的状态。
可选参数CURRENT,DISABLED,ENABLED

(3))WifiInfo
在我们的wifi 已经连通了以后,可以通过这个类获得一些已经连通的wifi 连接的信息获取当前链接的信息,
这里信息就比较简单了,这里简单介绍一下这里的方法:
getBSSID() 获取BSSID
getDetailedStateOf() 获取客户端的连通性
getHiddenSSID() 获得SSID 是否被隐藏
getIpAddress() 获取IP 地址
getLinkSpeed() 获得连接的速度
getMacAddress() 获得Mac 地址
getRssi() 获得802.11n 网络的信号
getSSID() 获得SSID
getSupplicanState() 返回具体客户端状态的信息

(4)wifiManager
这个不用说,就是用来管理我们的wifi 连接,这里已经定义好了一些类,可以供我们使用。
这里来说相对复杂,里面的内容比较多,但是通过字面意思,我们还是可以获得很多相关的信息。这个类里面预先定义了许多常量,我们可以直接使用,不用再次创建。
这里还是简单介绍一下这里的方法:
addNetwork(WifiConfiguration config) 通过获取到的网络的链接状态信息,来添加网络
calculateSignalLevel(int rssi , int numLevels) 计算信号的等级
compareSignalLevel(int rssiA, int rssiB) 对比连接A 和连接B
createWifiLock(int lockType, String tag) 创建一个wifi 锁,锁定当前的wifi 连接
disableNetwork(int netId) 让一个网络连接失效
disconnect() 断开连接
enableNetwork(int netId, Boolean disableOthers) 连接一个连接
getConfiguredNetworks() 获取网络连接的状态
getConnectionInfo() 获取当前连接的信息
getDhcpInfo() 获取DHCP 的信息
getScanResulats() 获取扫描测试的结果
getWifiState() 获取一个wifi 接入点是否有效
isWifiEnabled() 判断一个wifi 连接是否有效
pingSupplicant() ping 一个连接,判断是否能连通
ressociate() 即便连接没有准备好,也要连通
reconnect() 如果连接准备好了,连通
removeNetwork() 移除某一个网络
saveConfiguration() 保留一个配置信息
setWifiEnabled() 让一个连接有效
startScan() 开始扫描
updateNetwork(WifiConfiguration config) 更新一个网络连接的信息
此外wifiManaer 还提供了一个内部的子类,也就是wifiManagerLock,WifiManagerLock 的作用是这样的,
在普通的状态下,如果我们的wifi 的状态处于闲置,那么网络的连通,将会暂时中断。
但是如果我们把当前的网络状态锁上,那么wifi 连通将会保持在一定状态,当然接触锁定之后,就会恢复常态

Wifi状态

官方文档定义了如下几种状态:
WIFI_STATE_DISABLING WIFI网卡正在关闭 0
WIFI_STATE_DISABLED WIFI网卡不可用 1
WIFI_STATE_ENABLING WIFI网卡正在打开 2
WIFI_STATE_ENABLED WIFI网卡可用 3
WIFI_STATE_UNKNOWN WIFI网卡状态不可知 4

要操作WIFI设备,就需要使用Context.getSystemService(Context.WIFI_SERVICE)来获取WifiManager对象,并通过这个对象来管理我们的WIFI设备。
如果要想得到周围的WIFI热点列表,可以使用WifiManager.getScanResults()返回一个ScanResult列表

代码演示

首先我们需要在项目中添加如下权限:

1.开启Wifi

/**
* 打开wifi
*/
public void openWifi(){
if(!wifiManager.isWifiEnabled()){
wifiManager.setWifiEnabled(true);
}
}

2.扫描Wifi信号

/**
* 开始扫描wifi
*/
public void startScanWifi(){
wifiManager.startScan();
}

3.得到Wifi扫描结果

/**
* 获得扫描的结果
* @return
*/
public List<ScanResult> getScanResults(){
return wifiManager.getScanResults();
}

4.得到配置好的Wifi信息

/**
* 得到配置好的wifi信息
*/
public void getConfiguration(){
configuredNetworks = wifiManager.getConfiguredNetworks();
for (int i = 0; i < configuredNetworks.size(); i++) {
System.out.println("=====SSID"+configuredNetworks.get(i).SSID);
System.out.println("=====networkId"+configuredNetworks.get(i).networkId);
}
}

5.根据Wifi的名称SSID判定指定WIFI是否已经配置好,配置好则返回其networkId,用于连接

/**
* 根据SSID判断指定Wifi是否配置好
* @param SSID
* @return 配置好则返回networkId,否则返回-1
*/
public int isConfiguration(String SSID){
for(int i = 0;i<configuredNetworks.size();i++){
if(configuredNetworks.get(i).SSID.equals(SSID)){
return configuredNetworks.get(i).networkId;
}
}
return -1;
}

6.如果需要连接的Wifi没有配置好,即没有保存密码。则为指定名称ssid的WIFI添加密码信息password,添加成功后返回给其分配的networId,同于连接

public int addWifiConfig(List<ScanResult> wifiList,String ssid,String password){
int wifiId = -1;
for (int i = 0; i < wifiList.size() ; i++) {
ScanResult wifi = wifiList.get(i);
if(wifi.SSID.equals(ssid)){
WifiConfiguration wifiConfig = new WifiConfiguration();
wifiConfig.SSID = "\""+wifi.SSID+"\"";
wifiConfig.preSharedKey = "\""+password+"\"";//WPA-PSK密码
wifiConfig.hiddenSSID = false;
wifiConfig.status = WifiConfiguration.Status.ENABLED;
//将配置好的特定WIFI密码信息添加,添加完成后默认是不激活状态,成功返回ID,否则为-1
wifiId = wifiManager.addNetwork(wifiConfig);
if(wifiId!=-1){
return wifiId;
}
}
}
return wifiId;
}

7.根据步骤6配置好需要连接的WIFI密码信息后,下面通过networkId连接指定WIFI。在连接经过步骤6刚添加配置信息的WIFI信号之前需要重新执行下步骤4,得到新的配置好信息的列表。

public boolean ConnectWifi(int wifiId){
for(int i = 0; i < configuredNetworks.size(); i++){
WifiConfiguration wifi = configuredNetworks.get(i);
if(wifi.networkId == wifiId){
while(!(wifiManager.enableNetwork(wifiId, true))){//激活该Id,建立连接
//status:0--已经连接,1--不可连接,2--可以连接
Log.i("ConnectWifi",String.valueOf(configuredNetworks.get(wifiId).status));
}
return true;
}
}
return false;
}

下面是完整代码

public class WifiUtil {
//提供Wifi管理的各种主要API,主要包含wifi的扫描、建立连接、配置信息等
private WifiManager wifiManager;
//ScanResult用来描述已经检测出的接入点,包括接入的地址、名称、身份认证、频率、信号强度等
private List<WifiConfiguration> configuredNetworks;
//手机锁屏后,阻止WIFI也进入睡眠状态及WIFI的关闭
private WifiManager.WifiLock wifiLock;
//已经建立好网络链接的信息
private WifiInfo info;

public WifiUtil(Context context){
wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
}
/**
* 检查Wifi状态
* @return WIFI_STATE_DISABLING WIFI网卡正在关闭 0
WIFI_STATE_DISABLED WIFI网卡不可用 1
WIFI_STATE_ENABLING WIFI网卡正在打开 2
WIFI_STATE_ENABLED WIFI网卡可用 3
WIFI_STATE_UNKNOWN WIFI网卡状态不可知 4
*/
public int checkWifiState(){
return wifiManager.getWifiState();
}
/**
* 打开wifi
*/
public void openWifi(){
if(!wifiManager.isWifiEnabled()){
wifiManager.setWifiEnabled(true);
}
}

/**
* 关闭wifi
*/
public void closeWifi(){
if(wifiManager.isWifiEnabled()){
wifiManager.setWifiEnabled(false);
}
}
/**
* 开始扫描wifi
*/
public void startScanWifi(){
wifiManager.startScan();
}

/**
* 获得扫描的结果
* @return
*/
public List<ScanResult> getScanResults(){
return wifiManager.getScanResults();
}
/**
* 得到配置好的wifi信息
*/
public void getConfiguration(){
configuredNetworks = wifiManager.getConfiguredNetworks();
for (int i = 0; i < configuredNetworks.size(); i++) {
//网络的名字
// System.out.println("=====SSID"+configuredNetworks.get(i).SSID);
//网络id,从0开始
// System.out.println("=====networkId"+configuredNetworks.get(i).networkId);
}
}
/**
* 根据SSID判断指定Wifi是否连接过好
* @param SSID
* @return 连接过则返回networkId,否则返回-1
*/
public int isConfiguration(String SSID){
for(int i = 0;i<configuredNetworks.size();i++){
if(configuredNetworks.get(i).SSID.equals(SSID)){
return configuredNetworks.get(i).networkId;
}
}
return -1;
}
/**
* 将Wifi的ssid和密码添加到配置中
* @param wifiList
* @param ssid
* @param password
* @return
*/
public int addWifiConfig(List<ScanResult> wifiList,String ssid,String password){
int wifiId = -1;
for (int i = 0; i < wifiList.size() ; i++) {
ScanResult wifi = wifiList.get(i);
if(wifi.SSID.equals(ssid)){
WifiConfiguration wifiConfig = new WifiConfiguration();
wifiConfig.SSID = "\""+wifi.SSID+"\"";//网络名称
wifiConfig.preSharedKey = "\""+password+"\"";//WPA-PSK使用的密码
wifiConfig.hiddenSSID = false;//设置不隐藏,可以被外界搜到
wifiConfig.status = WifiConfiguration.Status.ENABLED;
//将配置好的特定WIFI密码信息添加,添加完成后默认是不激活状态,成功返回ID,否则为-1
wifiId = wifiManager.addNetwork(wifiConfig);
if(wifiId!=-1){
return wifiId;
}
}
}
return wifiId;
}
/**
* 根据wifiId进行连接
* @param wifiId
* @return
*/
public boolean ConnectWifi(int wifiId){
for(int i = 0; i < configuredNetworks.size(); i++){
WifiConfiguration wifi = configuredNetworks.get(i);
if(wifi.networkId == wifiId){
if((wifiManager.enableNetwork(wifiId, true))){//激活该Id,建立连接,发明true表示激活成功
//status:0--已经连接,1--不可连接,2--可以连接
Log.i("ConnectWifi",String.valueOf(configuredNetworks.get(wifiId).status));
}
return true;
}
}
return false;
}
public void createWifiLock(String wifiLockName){
wifiLock = wifiManager.createWifiLock(wifiLockName);
}
public void accquireWifiLock(){
wifiLock.acquire();
}
public void releaseWifiLock(){
if(wifiLock.isHeld()){
wifiLock.release();
}
}
public void getConnctedWifiInfo(){
info = wifiManager.getConnectionInfo();
}
//得到连接的MAC地址
public String getConnectedMacAddr(){
return (info == null)? "NULL":info.getMacAddress();
}

//得到连接的名称SSID
public String getConnectedSSID(){
return (info == null)? "NULL":info.getSSID();
}

//得到连接的IP地址
public int getConnectedIPAddr(){
return (info == null)? 0:info.getIpAddress();
}

//得到连接的ID
public int getConnectedID(){
return (info == null)? 0:info.getNetworkId();
}
}
public class MainActivity extends AppCompatActivity {

private ListView listView;
private List<String> wifiListString = new ArrayList<>();
private WifiUtil wifiUtil;
private List<ScanResult> scanResults;
private ArrayAdapter<String> adapter;
private String wifiPassword = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = (ListView) findViewById(R.id.wifilistview);
adapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1, wifiListString);
listView.setAdapter(adapter);
listView.setOnItemClickListener(onItemClickListener);
wifiUtil = new WifiUtil(this);
}
public void detectWifi(View view){
wifiListString.clear();
//打开wifi
wifiUtil.openWifi();
//开始扫描
wifiUtil.startScanWifi();
//检查wifi状态
while(wifiUtil.checkWifiState()!= WifiManager.WIFI_STATE_ENABLED) {
//0正在关闭,1WIFi不可用,2正在打开,3可用,4状态未知
System.out.println("==========wifi state: " + wifiUtil.checkWifiState());
}
try {
Thread.sleep(3000);//休眠3秒,不然会使getScanResults返回空
} catch (InterruptedException e) {
e.printStackTrace();
}
scanResults = wifiUtil.getScanResults();//获取扫描结果
wifiUtil.getConfiguration();//获取配置信息
if(wifiListString!=null){
scanResultToString(scanResults,wifiListString);
}
}
/**
* 把扫描结果展示到页面上
* @param scanResults
* @param wifiListString
*/
private void scanResultToString(List<ScanResult> scanResults, List<String> wifiListString) {
for (int i = 0; i < scanResults.size(); i++) {
ScanResult scanResult = scanResults.get(i);
//接入点名称和地址
String str = scanResult.SSID + "---" + scanResult.BSSID;
wifiListString.add(str);//将数据添加到集合中
adapter.notifyDataSetChanged();
System.out.println("===========scanResult " + wifiListString.get(i));
}
//每次扫描到的数据量
System.out.println("========size: "+wifiListString.size());
}
AdapterView.OnItemClickListener onItemClickListener = new AdapterView.OnItemClickListener() {
String wifiSSID = null;
private View selectdItem;//点击的条目
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
selectdItem = view;
view.setBackgroundResource(android.R.color.darker_gray);
String wifiItem = adapter.getItem(position);//点击位置条目的内容
String[] itemValue = wifiItem.split("---");
wifiSSID = itemValue[0];//得到wifi名称
int networkId = wifiUtil.isConfiguration("\""+wifiSSID+"\"");//获得networkId
if(networkId!=-1){//已经连接过,直接连接
if(wifiUtil.ConnectWifi(networkId)){
view.setBackgroundResource(android.R.color.holo_red_light);
}
}else{
WifiPasswordDialog dialog = new WifiPasswordDialog(MainActivity.this, new WifiPasswordDialog.OnCustomDialogListener() {
@Override
public void back(String str) {
wifiPassword = str;
if(wifiPassword!=null){
//根据密码和ssid配置,
int netId = wifiUtil.addWifiConfig(scanResults,wifiSSID,wifiPassword);
if(netId!=-1){//配置成功
wifiUtil.getConfiguration();
if(wifiUtil.ConnectWifi(netId)){//根据netId进行连接
selectdItem.setBackgroundResource(android.R.color.holo_red_light);
}
}else{
Toast.makeText(MainActivity.this, "网络链接错误", Toast.LENGTH_SHORT).show();
selectdItem.setBackgroundResource(android.R.color.holo_red_light);
}
}else{
selectdItem.setBackgroundResource(android.R.color.transparent);
}
}
});
dialog.show();
}
}
};
public void close(View view){
wifiUtil.closeWifi();
}
}

最后我们实现一个功能,点击按钮搜索Wifi信号,如果首次连接弹出输入密码框,否则直接连接,项目源码在下面:
​点此下载项目源码​​