本文沒有涉及到連接配接WIFI之後進行通訊,若有這方面的想法(例如兩個用戶端連接配接至同一WIFI後進行通訊),請關注後續文章一起讨論。
其實關于WIFI的開發的文章也非常的多,但是大部分隻是簡單的例子,不夠全面,我這裡是想寫一個比較完整的WIFI應用,主要功能:
1.能夠打開/關閉WIFI
2.能夠掃面wifi并擷取掃描結果
3.能夠連接配接wifi,無論是什麼加密方式
4.能夠監聽連接配接狀态,如正在連接配接、正在擷取ip、密碼錯誤等
5.能夠鎖定wifi
6.能擷取wifi的加密方式
7.開啟熱點
8.等等,大部分wifi操作常用的功能...
至于開發中用的幾個相關類我就不做過多介紹了,網上比比皆是,還不了解的可以先看一下其他部落格的介紹或者官方文檔。
我盡量在代碼中增加了一些注釋,還是那句話:我還是個安卓小白,錯誤在所難免,如果有錯誤,希望大家多多指點。
一般使用WIFI流程:
1.打開wifi
1.1 狀态監聽
2.掃描wifi
3.連接配接wifi
4.關閉wifi
其中連接配接需要分幾種情況:
1.如果是之前已經儲存,直接連接配接
2.如果沒有儲存,必須先進行配置,再連接配接
2.1配置需要區分三種加密方式:無密碼、WEP、WPA
3.WPS連接配接
那麼就來打造一個簡單demo,按照以上的步驟來。
開發流程
我們為了以後使用友善,直接編寫一個wifi管理類,然後在activity直接調用對應方法就行了。下面着手進行這個類的編寫:
0.在開始開發之前我們需要先配置相應的權限,如果是Android N以上級的動态申請位置權限哦
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<!-- 在android N 以上 需要添加位置權限 -->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
然後先看看我們需要準備什麼全局變量
private WifiManager mWifiManager;//wifi管理器
private List<ScanResult> mScanResults;//掃描結果
private Context mContext;
private WifiStateReceiver mReceiver;//廣播接收器
private WifiStateChangeListener mWifiStateChangeListener;//
private WifiManager.WifiLock mWifiLock;//WIFI鎖
private static WiFiAdmin mWifiAdmin;//單利模式,
1.第一步,初始化wifi管理器并打開wifi
初始化
/***
* 構造方法 - - 由于使用單例,是以設為私有
* @param context
*/
private WiFiAdmin(Context context) {
mContext = context;
//如果使用activity的context則不能通路存儲空間,在版本大于Android N時,是以使用全局的Context
mWifiManager = (WifiManager) mContext.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
mWifiLock = mWifiManager.createWifiLock("mlock");
}
打開wifi
public void openWifi() {
if (!mWifiManager.isWifiEnabled()) {
mWifiManager.setWifiEnabled(true);
}
}
2.注冊廣播,接收wifi的一些狀态,例如正在連接配接、正在擷取ip位址、斷開連接配接等
private void registerWifiRecv() {
//注冊廣播
mReceiver = new WifiStateReceiver();
IntentFilter mFilter = new IntentFilter();
mFilter.addAction(WifiManager.RSSI_CHANGED_ACTION); //信号強度變化
mFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); //網絡狀态變化
mFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); //wifi狀态,是否連上,密碼
mFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION); //是不是正在獲得IP位址
mFilter.addAction(WifiManager.NETWORK_IDS_CHANGED_ACTION);
mFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
mContext.registerReceiver(mReceiver, mFilter);
isRegisterRecv = true;
}
3.既然注冊了廣播,那麼我們肯定要處理對應結果
class WifiStateReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (!isRegisterRecv) return;//沒注冊監聽就沒必要執行之後的邏輯
String action = intent.getAction();
switch (action) {
case WifiManager.RSSI_CHANGED_ACTION:
//信号強度變化
mWifiStateChangeListener.onSignalStrengthChanged(getStrength(context));
break;
case WifiManager.NETWORK_STATE_CHANGED_ACTION:
NetworkInfo info = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
if (info.getDetailedState().equals(NetworkInfo.DetailedState.DISCONNECTED)) {
//wifi已斷開
mWifiStateChangeListener.onWifiDisconnect();
} else if (info.getDetailedState().equals(NetworkInfo.DetailedState.CONNECTING)) {
//正在連接配接...
mWifiStateChangeListener.onWifiConnecting();
} else if (info.getDetailedState().equals(NetworkInfo.DetailedState.CONNECTED)) {
//連接配接到網絡
mWifiStateChangeListener.onWifiConnected();
}else if(info.getDetailedState().equals(NetworkInfo.DetailedState.OBTAINING_IPADDR)){
//正在擷取IP位址
mWifiStateChangeListener.onWifiGettingIP();
}else if(info.getDetailedState().equals(NetworkInfo.DetailedState.FAILED)){
//連接配接失敗
}
break;
case WifiManager.WIFI_STATE_CHANGED_ACTION:
int wifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, 0);
switch (wifiState) {
case WifiManager.WIFI_STATE_ENABLING:
//wifi正在啟用
mWifiStateChangeListener.onWifiEnabling();
break;
case WifiManager.WIFI_STATE_ENABLED:
//Wifi已啟用
mWifiStateChangeListener.onWifiEnable();
break;
}
break;
case WifiManager.SUPPLICANT_STATE_CHANGED_ACTION:
int error = intent.getIntExtra(WifiManager.EXTRA_SUPPLICANT_ERROR, -100);
LogUtil.log("密碼認證錯誤:"+error+"\n");
if (error==WifiManager.ERROR_AUTHENTICATING){
//wifi密碼認證錯誤!
mWifiStateChangeListener.onPasswordError();
}
break;
case WifiManager.NETWORK_IDS_CHANGED_ACTION:
//已經配置的網絡的ID可能發生變化時
mWifiStateChangeListener.onWifiIDChange();
break;
case ConnectivityManager.CONNECTIVITY_ACTION:
//連接配接狀态發生變化,暫時沒用到
int type = intent.getIntExtra(ConnectivityManager.EXTRA_NETWORK_TYPE,0);
break;
default:
break;
}
}
}
/**
* 計算信号強度
*
* @param context 含有WIFI資訊的資源對象
* @return 信号強度
*/
private int getStrength(Context context) {
WifiInfo info = getConnectInfo();
if (info.getBSSID() != null) {
int strength = WifiManager.calculateSignalLevel(info.getRssi(), 5);
// 連結速度
// int speed = info.getLinkSpeed();
// // 連結速度機關
// String units = WifiInfo.LINK_SPEED_UNITS;
// // Wifi源名稱
// String ssid = info.getSSID();
return strength;
}
return 0;
}
4.然後發起掃描并擷取掃描結果
/**
* 啟動掃描,掃描前應使用 {@link #getWifiState()}判斷WIFI是否可用
* 或者在回調函數 mWifiStateChangeListener.onWifiEnable() 調用
*/
public void startWifiScan() {
mWifiManager.startScan();
mScanResults = mWifiManager.getScanResults();
}
5.擷取到掃描結果之後,我們就可以發起連接配接了。對于之前已經連接配接過的wifi,可以直接這樣:
public boolean connectWifi(int netId) {
return mWifiManager.enableNetwork(netId, true);
}
那麼netid怎麼來的?這就需要以下這些操作,首先要擷取已經配置過(就是之前連接配接過的)的wifi
public WifiInfo getConnectInfo() {
return mWifiManager.getConnectionInfo();
}
使用以下方法擷取netid,如果傳回-1,證明沒有配置,需要配置才能發起連接配接請求。
public int isWifiConfig(String ssid) {
List<WifiConfiguration> lists = getConfigWifiList();
for (WifiConfiguration c : lists) {
if (c.SSID.equals("\"" + ssid + "\"")) {
return c.networkId;
}
}
return -1;
}
而如果是連接配接新的wifi(上面的方法傳回-1)需要先配置對應的參數,例如密碼之類的才能發起連接配接
public int configWifi(String ssid, String pwd,int security) {
int result = -1;
for (ScanResult s : mScanResults) {
if (s.SSID.equals(ssid)) {
WifiConfiguration config = new WifiConfiguration();
config.SSID = "\"" + ssid + "\"";
config.hiddenSSID = false;
config.status = WifiConfiguration.Status.ENABLED;
switch (security){
case SECURITY_NONE:
config.wepKeys[0] ="\""+pwd+"\"";
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
config.wepTxKeyIndex = 0;
break;
case SECURITY_WEP:
config.wepKeys[0]= "\""+pwd+"\"";
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
config.wepTxKeyIndex = 0;
break;
case SECURITY_WPA:
case SECURITY_WPA_PSK:
config.preSharedKey = "\"" + pwd + "\"";
break;
default:
break;
}
result = mWifiManager.addNetwork(config);
break;
}
}
return result;
}
配置完成再次調用擷取netid的方法就可以擷取netid了
6.經過步驟5,我們已經能連接配接上wifi,接下來就可以退出程式,愉快的上網了。當然,如果不需要wifi了,别忘了關閉哦~
public void closeWifi() {
if (mWifiManager.isWifiEnabled()) {
mWifiManager.setWifiEnabled(false);
}
}
上面是簡化後的步驟,像在配置時,還需要判斷有沒有加密,加密方式是什麼,怎麼擷取加密方式等都省略了。全部了解請看下方全部代碼哦~
下面有關于wifi的更多操作,也有要共享wifi的法等。
總體就是這種流程,按照這個流程來調用對應的方法就差不多了。記得根據步驟來閱讀,才不會覺得混亂。下面是wifi管理類的全部代碼,我整合大部分需要用到的功能:
package cn.small_qi.wificonn;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
/**
* Created by small_qi on 2017/7/21.
*/
public class WiFiAdmin {
private WifiManager mWifiManager;
private List<ScanResult> mScanResults;
private Context mContext;
private WifiStateReceiver mReceiver;
private WifiStateChangeListener mWifiStateChangeListener;
private WifiManager.WifiLock mWifiLock;
private static WiFiAdmin mWifiAdmin;
private boolean isRegisterRecv;
private boolean isWifiLock;
public static final int SECURITY_WEP = 3;//WEP
public static final int SECURITY_WPA = 2;//WPA/WPA2
public static final int SECURITY_WPA_PSK = 1;//WPA-PSK/WPA2-PSK
public static final int SECURITY_NONE = 0;//沒有密碼
public static final int ORDER_SMART_SORT = 0;//智能排序,
public static final int ORDER_SIGNAL_LEVEL_SORT = 1;//信号強度排序
/***
* 構造方法 - - 由于使用單例,是以設為私有
* @param context
*/
private WiFiAdmin(Context context) {
mContext = context;
//如果使用activity的context則不能通路存儲空間,在版本大于Android N時,是以使用全局的Context
mWifiManager = (WifiManager) mContext.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
mWifiLock = mWifiManager.createWifiLock("mlock");
}
/**
* 對外面公開的擷取執行個體的方法
*
* @param context
* @return 建立的
*/
public static WiFiAdmin getInstance(Context context) {
if (mWifiAdmin == null) {
mWifiAdmin = new WiFiAdmin(context);
}
return mWifiAdmin;
}
/**
* 設定網絡狀态監聽
* 如果設定了監聽,一定要在調用的Activity/Fragment
* 的生命周期結束時調用{@link #removeWifiStateChangeListener()}
* 避免記憶體洩漏
*/
public void addWifiStateChangeListener(WifiStateChangeListener wscListener) {
if (isRegisterRecv) return;
registerWifiRecv();
this.mWifiStateChangeListener = wscListener;
}
private void registerWifiRecv() {
//注冊廣播
mReceiver = new WifiStateReceiver();
IntentFilter mFilter = new IntentFilter();
mFilter.addAction(WifiManager.RSSI_CHANGED_ACTION); //信号強度變化
mFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); //網絡狀态變化
mFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); //wifi狀态,是否連上,密碼
mFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION); //是不是正在獲得IP位址
mFilter.addAction(WifiManager.NETWORK_IDS_CHANGED_ACTION);
mFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
mContext.registerReceiver(mReceiver, mFilter);
isRegisterRecv = true;
}
public void removeWifiStateChangeListener() {
if (!isRegisterRecv) return;
isRegisterRecv = false;
mContext.unregisterReceiver(mReceiver);
}
public void openWifi() {
if (!mWifiManager.isWifiEnabled()) {
mWifiManager.setWifiEnabled(true);
}
}
public void closeWifi() {
if (mWifiManager.isWifiEnabled()) {
mWifiManager.setWifiEnabled(false);
}
}
public boolean lockWifi() {
if (mWifiLock == null) {
return false;
}
mWifiLock.acquire();
isWifiLock = true;
return true;
}
public boolean unLockWifi() {
if (mWifiLock == null) {
return false;
}
mWifiLock.release();
isWifiLock = false;
return true;
}
public boolean isWifiLock() {
return isWifiLock;
}
/**
* 擷取網卡狀态
*
* @return
*/
public int getWifiState() {
/**
* WIFI網卡的狀态是由一系列的整形常量來表示的。
1.WIFI_STATE_DISABLED : WIFI網卡不可用(1)
2.WIFI_STATE_DISABLING : WIFI網卡正在關閉(0)
3.WIFI_STATE_ENABLED : WIFI網卡可用(3)
4.WIFI_STATE_ENABLING : WIFI網正在打開(2) (WIFI啟動需要一段時間)
5.WIFI_STATE_UNKNOWN : 未知網卡狀态
*/
if (mWifiManager.isWifiEnabled()) {
return mWifiManager.getWifiState();
}
return -1;
}
/**
* 啟動掃描,掃描前應使用 {@link #getWifiState()}判斷WIFI是否可用
* 或者在回調函數 mWifiStateChangeListener.onWifiEnable() 調用
*/
public void startWifiScan() {
mWifiManager.startScan();
mScanResults = mWifiManager.getScanResults();
}
/**
* 擷取排序後的掃描結果
*
* @param order 排序方式
* 1.隻按信号強度排序
* 2.已經儲存的在前面,其他按強度排序
*/
public List<ScanResult> getOrderScanResults(int order) {
List<ScanResult> sortResult = mScanResults;
if (order == ORDER_SIGNAL_LEVEL_SORT) {
levelSort(sortResult);
} else if (order == ORDER_SMART_SORT) {
smartSort(sortResult);
}
return null;
}
private void levelSort(List<ScanResult> sortResult) {
Collections.sort(sortResult, new Comparator<ScanResult>() {
@Override
public int compare(ScanResult o1, ScanResult o2) {
return o1.level - o2.level;
}
});
}
private void smartSort(List<ScanResult> sortResult) {
Collections.sort(sortResult, new Comparator<ScanResult>() {
@Override
public int compare(ScanResult o1, ScanResult o2) {
if (isWifiConfig(o1.SSID) > 0 && isWifiConfig(o2.SSID) > 0) {
return o1.level - o2.level;
} else if (isWifiConfig(o1.SSID) > 0 || isWifiConfig(o2.SSID) > 0) {
return isWifiConfig(o1.SSID) - isWifiConfig(o2.SSID);
} else {
return o1.level - o2.level;
}
}
});
}
/**
* 擷取掃描結果
*/
public List<ScanResult> getScanResults() {
return mScanResults;
}
/**
* 擷取已經儲存的wifi清單
*/
public List<WifiConfiguration> getConfigWifiList() {
List<WifiConfiguration> configurations = mWifiManager.getConfiguredNetworks();
return configurations;
}
/**
* 判斷該wifi是否已經儲存
*
* @return 傳回-1表示沒儲存,已經儲存傳回網絡id
*/
public int isWifiConfig(String ssid) {
List<WifiConfiguration> lists = getConfigWifiList();
for (WifiConfiguration c : lists) {
if (c.SSID.equals("\"" + ssid + "\"")) {
return c.networkId;
}
}
return -1;
}
/**
* 配置沒有儲存的wifi
* 一般隻要配置一下幾個屬性就可以了,其他使用其,預設值
* @param scanResult
* @param pwd
* @return 儲存成功則傳回該Wifi的網絡id,否則-1
*/
public int configWifi(ScanResult scanResult, String pwd,int security) {
return configWifi(scanResult.SSID,pwd,security);
}
/**
* 配置方法重載
*/
public int configWifi(String ssid, String pwd,int security) {
int result = -1;
for (ScanResult s : mScanResults) {
if (s.SSID.equals(ssid)) {
WifiConfiguration config = new WifiConfiguration();
config.SSID = "\"" + ssid + "\"";
config.hiddenSSID = false;
config.status = WifiConfiguration.Status.ENABLED;
switch (security){
case SECURITY_NONE:
config.wepKeys[0] ="\""+pwd+"\"";
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
config.wepTxKeyIndex = 0;
break;
case SECURITY_WEP:
config.wepKeys[0]= "\""+pwd+"\"";
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
config.wepTxKeyIndex = 0;
break;
case SECURITY_WPA:
case SECURITY_WPA_PSK:
config.preSharedKey = "\"" + pwd + "\"";
break;
default:
break;
}
result = mWifiManager.addNetwork(config);
break;
}
}
return result;
}
/**
* 配置方法重載,用于更複雜的配置
*/
public int configWifi(WifiConfiguration config) {
return mWifiManager.addNetwork(config);
}
/**
* 擷取加秘方式
*/
public int getSecurity(ScanResult scanResult) {
return getSecurity(scanResult.capabilities);
}
/**
* 擷取加秘方式
*
* @param capabilities
* @return 加密類型, 具體類型請檢視: {@link #SECURITY_NONE}{@link #SECURITY_WEP}{@link #SECURITY_WPA}{@link #SECURITY_WPA_PSK}
*/
public int getSecurity(String capabilities) {
if (capabilities.contains("WEP")) {
return SECURITY_WEP;
} else if (capabilities.contains("WPA")) {
if (capabilities.contains("PSK"))
return SECURITY_WPA_PSK;
return SECURITY_WPA;
} else {
return SECURITY_NONE;
}
}
/**
* 删除/忘記一個wifi(也就是通常的不儲存)
*
* @param ssid 要忘記網絡名成
* @return 執行結果
*/
public boolean forgetWifi(String ssid) {
for (WifiConfiguration c : getConfigWifiList()) {
if (c.SSID.equals("\"" + ssid + "\"")) {
return mWifiManager.removeNetwork(c.networkId);
}
}
return false;
}
/**
* 斷開連接配接
* @return
*/
public boolean disconnectWifi(){
return mWifiManager.disableNetwork(getConnectInfo().getNetworkId());
// mWifiManager.disconnect();//斷流
}
/**
* 連接配接wifi
*
* @param netId wifi網絡id
* @return 連接配接結果
*/
public boolean connectWifi(int netId) {
return mWifiManager.enableNetwork(netId, true);
}
/**
* 擷取已經連接配接的WIFI資訊
*/
public WifiInfo getConnectInfo() {
return mWifiManager.getConnectionInfo();
}
/**
* IP 位址轉換
*
* @param ip 轉換前的IP
* @return 轉換後的IP
*/
public static String parseIPAddressToString(int ip) {
return ((ip & 0xff) + "." + (ip >> 8 & 0xff) + "." + (ip >> 16 & 0xff) + "." + (ip >> 24 & 0xff));
}
/**
* 廣播監聽内部類
*/
class WifiStateReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (!isRegisterRecv) return;//沒注冊監聽就沒必要執行之後的邏輯
String action = intent.getAction();
switch (action) {
case WifiManager.RSSI_CHANGED_ACTION:
//信号強度變化
mWifiStateChangeListener.onSignalStrengthChanged(getStrength(context));
break;
case WifiManager.NETWORK_STATE_CHANGED_ACTION:
NetworkInfo info = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
if (info.getState().equals(NetworkInfo.State.DISCONNECTED)) {
//wifi已斷開
mWifiStateChangeListener.onWifiDisconnect();
} else if (info.getState().equals(NetworkInfo.State.CONNECTING)) {
//正在連接配接...
mWifiStateChangeListener.onWifiConnecting();
} else if (info.getState().equals(NetworkInfo.State.CONNECTED)) {
//連接配接到網絡
mWifiStateChangeListener.onWifiConnected();
}else if(info.getDetailedState().equals(NetworkInfo.DetailedState.OBTAINING_IPADDR)){
//正在擷取IP位址
mWifiStateChangeListener.onWifiGettingIP();
}
break;
case WifiManager.WIFI_STATE_CHANGED_ACTION:
int wifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, 0);
switch (wifiState) {
case WifiManager.WIFI_STATE_ENABLING:
//wifi正在啟用
mWifiStateChangeListener.onWifiEnabling();
break;
case WifiManager.WIFI_STATE_ENABLED:
//Wifi已啟用
mWifiStateChangeListener.onWifiEnable();
break;
}
break;
case WifiManager.SUPPLICANT_STATE_CHANGED_ACTION:
int error = intent.getIntExtra(WifiManager.EXTRA_SUPPLICANT_ERROR, 0);
switch (error) {
case WifiManager.ERROR_AUTHENTICATING:
//wifi密碼認證錯誤!
mWifiStateChangeListener.onPasswordError();
break;
default:
break;
}
break;
case WifiManager.NETWORK_IDS_CHANGED_ACTION:
//已經配置的網絡的ID可能發生變化時
mWifiStateChangeListener.onWifiIDChange();
break;
case ConnectivityManager.CONNECTIVITY_ACTION:
//連接配接狀态發生變化,暫時沒用到
break;
default:
break;
}
}
}
/**
* 計算信号強度
*
* @param context 含有WIFI資訊的資源對象
* @return 信号強度
*/
private int getStrength(Context context) {
WifiInfo info = getConnectInfo();
if (info.getBSSID() != null) {
int strength = WifiManager.calculateSignalLevel(info.getRssi(), 5);
// 連結速度
// int speed = info.getLinkSpeed();
// // 連結速度機關
// String units = WifiInfo.LINK_SPEED_UNITS;
// // Wifi源名稱
// String ssid = info.getSSID();
return strength;
}
return 0;
}
/**
* WIFI狀态變化回調接口
*/
public interface WifiStateChangeListener {
//void onRssiChanged();
//void onNetWorkStateChanged();
//void onWifiStateChanged();
//void onSupplicantStateChanged();
// void NetWorkIDSChange();
void onSignalStrengthChanged(int level);
void onWifiConnecting();
void onWifiGettingIP();
void onWifiConnected();
void onWifiDisconnect();
void onWifiEnabling();
void onWifiEnable();
void onPasswordError();
void onWifiIDChange();
//void onWifiLock(int isLock);
}
//-------------------------------以下部分為開啟熱點-------------------------------------
/**
* 建立熱點
*
* @param mSSID 熱點名稱
* @param mPasswd 熱點密碼
* @param isOpen 是否是開放熱點
*/
public void startWifiAp(String mSSID, String mPasswd, boolean isOpen) {
Method method1 = null;
try {
method1 = mWifiManager.getClass().getMethod("setWifiApEnabled",
WifiConfiguration.class, boolean.class);
WifiConfiguration netConfig = new WifiConfiguration();
netConfig.SSID = mSSID;
netConfig.preSharedKey = mPasswd;
netConfig.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
netConfig.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
netConfig.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
if (isOpen) {
netConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
} else {
netConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
}
netConfig.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
netConfig.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);
netConfig.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
netConfig.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
method1.invoke(mWifiManager, netConfig, true);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
/**
* 擷取熱點名
**/
public String getApSSID() {
try {
Method localMethod = this.mWifiManager.getClass().getDeclaredMethod("getWifiApConfiguration", new Class[0]);
if (localMethod == null) return null;
Object localObject1 = localMethod.invoke(this.mWifiManager, new Object[0]);
if (localObject1 == null) return null;
WifiConfiguration localWifiConfiguration = (WifiConfiguration) localObject1;
if (localWifiConfiguration.SSID != null) return localWifiConfiguration.SSID;
Field localField1 = WifiConfiguration.class.getDeclaredField("mWifiApProfile");
if (localField1 == null) return null;
localField1.setAccessible(true);
Object localObject2 = localField1.get(localWifiConfiguration);
localField1.setAccessible(false);
if (localObject2 == null) return null;
Field localField2 = localObject2.getClass().getDeclaredField("SSID");
localField2.setAccessible(true);
Object localObject3 = localField2.get(localObject2);
if (localObject3 == null) return null;
localField2.setAccessible(false);
String str = (String) localObject3;
return str;
} catch (Exception localException) {
}
return null;
}
/**
* 檢查是否開啟Wifi熱點
*
* @return
*/
public boolean isWifiApEnabled() {
try {
Method method = mWifiManager.getClass().getMethod("isWifiApEnabled");
method.setAccessible(true);
return (boolean) method.invoke(mWifiManager);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return false;
}
/**
* 關閉熱點
*/
public void closeWifiAp() {
WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
if (isWifiApEnabled()) {
try {
Method method = wifiManager.getClass().getMethod("getWifiApConfiguration");
method.setAccessible(true);
WifiConfiguration config = (WifiConfiguration) method.invoke(wifiManager);
Method method2 = wifiManager.getClass().getMethod("setWifiApEnabled", WifiConfiguration.class, boolean.class);
method2.invoke(wifiManager, config, false);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
/**
* 開熱點手機獲得其他連接配接手機IP的方法
*
* @return 其他手機IP 數組清單
*/
public ArrayList<String> getConnectedIP() {
ArrayList<String> connectedIp = new ArrayList<String>();
try {
BufferedReader br = new BufferedReader(new FileReader(
"/proc/net/arp"));
String line;
while ((line = br.readLine()) != null) {
String[] splitted = line.split(" +");
if (splitted != null && splitted.length >= 4) {
String ip = splitted[0];
if (!ip.equalsIgnoreCase("ip")) {
connectedIp.add(ip);
}
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return connectedIp;
}
}
裡面還少了一種WPS連接配接,這個如果需要,大家在自己添加上去了。
整個流程下來代碼還是挺多的,至于哪些地方需要注意的一時半會也說不完,也忘記了我開發過程遇到哪些問題了~~~間歇性失憶,啊哈哈哈
但是我還是要說一下:
1.可能會有人注意到,為什麼我使用ssid時,有時是直接使用,有時又需要加上雙引号"\""+ ssid + "\""這樣子,
這是因為如果你是從 WifiConfiguration 中擷取到的ssid的話,他預設會有雙引号,但是從ScanResult等擷取到ssid是沒有雙引号的,
是以為了比對隻好加上了。是以,在配置 WifiConfiguration時ssid和密碼都需要我們手動加上雙引号,他預設格式是這樣,不按照這個來會出現錯誤。
2.關于AP方面,目前開放的方法能直接開啟,是以這部分的内容全是通過反射機制進行的,我也是參考了一些部落格寫的,具體我自己沒試過。
3.其他有疑問的話,就在評論中提問吧~這樣友善大神們給你回複。
後面我寫了一個測試小程式,除了AP沒有測試外,其他功能正常使用,和系統的wifi功能差不多哦~
下面是幾張截圖:
掃描-擷取掃描結果
點選連接配接(已經儲存好的)wifi - -分别會顯示正在連接配接...- - 正在擷取ip... - - 已連接配接
連接配接沒有儲存的wifi --彈出輸入密碼框(如果是沒加密不會彈出,而是直接連接配接),确認之後就連接配接
如果點選已經連接配接的wifi,就可以選擇斷開還是忘記(不儲存)
大概就這樣了。接下去可能會寫連接配接上wifi之後進行區域網通訊相關的。
完整demo github位址:https://github.com/nongchengqi/WifiConn2
附上activity的代碼:
package cn.small_qi.wificonn;
import android.Manifest;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiInfo;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private ListView list;
private WifiAdapter adapter;
private WiFiAdmin admin;
private static final int PERMISSION_WIFI_CODE = 1001;
private static final int PERMISSION_FILE_CODE = 1002;
private int curPosition=-1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
int code = ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (code != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSION_FILE_CODE);
}
}
initList();
setListener();
setStateListener();
}
private void initList() {
admin = WiFiAdmin.getInstance(this);
list = (ListView) findViewById(R.id.list);
adapter = new WifiAdapter(this);
list.setAdapter(adapter);
list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
curPosition = position;
final ScanResult result = adapter.getItem(position);
if (admin.getConnectInfo().getSSID().equals("\""+result.SSID+"\"")){
new AlertDialog.Builder(MainActivity.this)
.setTitle("是否斷開連接配接?")
.setPositiveButton("斷開", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
admin.disconnectWifi();
}
})
.setNegativeButton("不儲存", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
admin.forgetWifi(result.SSID);
}
})
.create().show();
return;
}
final int security =admin.getSecurity(result) ;
int netid = admin.isWifiConfig(result.SSID);
if ( netid == -1) {
if (security != WiFiAdmin.SECURITY_NONE) {
final EditText pwdEt = new EditText(MainActivity.this);
//彈出輸入密碼對話框
new AlertDialog.Builder(MainActivity.this)
.setView(pwdEt)
.setTitle("請輸入密碼")
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
admin.configWifi(result, pwdEt.getText().toString(),security);
admin.connectWifi(admin.isWifiConfig(result.SSID));
}
})
.setNegativeButton("取消", null)
.create().show();
} else {
admin.configWifi(result, "",security);
admin.connectWifi(admin.isWifiConfig(result.SSID)) ;
}
} else {
admin.connectWifi(netid);
}
}
});
}
private void setListener() {
findViewById(R.id.close).setOnClickListener(this);
findViewById(R.id.open).setOnClickListener(this);
findViewById(R.id.scan).setOnClickListener(this);
findViewById(R.id.info).setOnClickListener(this);
findViewById(R.id.conn).setOnClickListener(this);
}
private void setStateListener() {
admin.addWifiStateChangeListener(new WiFiAdmin.WifiStateChangeListener() {
@Override
public void onSignalStrengthChanged(int level) {
}
@Override
public void onWifiConnecting() {
adapter.updateState(0,curPosition);
}
@Override
public void onWifiGettingIP() {
adapter.updateState(1,curPosition);
}
@Override
public void onWifiConnected() {
adapter.updateState(2,curPosition);
}
@Override
public void onWifiDisconnect() {
adapter.updateState(4,curPosition);
}
@Override
public void onWifiEnabling() {
}
@Override
public void onWifiEnable() {
}
@Override
public void onPasswordError() {
adapter.updateState(3,curPosition);
}
@Override
public void onWifiIDChange() {
}
});
}
private void checkPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
int code = ContextCompat.checkSelfPermission(this, Manifest.permission_group.LOCATION);
if (code != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION}, PERMISSION_WIFI_CODE);
} else {
admin.startWifiScan();
adapter.addAllWifis(admin.getScanResults());
}
} else {
admin.startWifiScan();
adapter.addAllWifis(admin.getScanResults());
}
}
@Override
protected void onDestroy() {
super.onDestroy();
admin.removeWifiStateChangeListener();
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode) {
case PERMISSION_WIFI_CODE:
if (grantResults[1] == PackageManager.PERMISSION_GRANTED) {
admin.startWifiScan();
adapter.addAllWifis(admin.getScanResults());
}
break;
default:
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
break;
}
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.close:
admin.closeWifi();
break;
case R.id.open:
admin.openWifi();
break;
case R.id.scan:
//6.0權限
checkPermission();
break;
case R.id.info:
showInfo();
break;
case R.id.conn:
if (admin!=null&&admin.getConnectInfo().getIpAddress()!=0){
startActivity(new Intent(MainActivity.this,ConnActivity.class));
}else{
Toast.makeText(this, "請先連接配接Wifi或者等待Wifi連接配接成功", Toast.LENGTH_SHORT).show();
}
break;
}
}
private void showInfo() {
WifiInfo info = admin.getConnectInfo();
if (info == null) {
Toast.makeText(MainActivity.this, "目前未連接配接到WIFI", Toast.LENGTH_SHORT).show();
return;
}
new AlertDialog.Builder(MainActivity.this)
.setTitle("目前連接配接WIFI資訊:")
.setMessage(info.getSSID() + "\n" + info.getMacAddress() + "\n" + WiFiAdmin.parseIPAddressToString(info.getIpAddress()) + "\n" +
info.getLinkSpeed() + "\n" + info.getBSSID() + "\n" + info.getRssi())
.create()
.show();
}
}
xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/open"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="打開" />
<Button
android:id="@+id/close"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="關閉" />
<Button
android:id="@+id/scan"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="掃描" />
<Button
android:id="@+id/info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="資訊" />
<Button
android:id="@+id/conn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="通訊" />
</LinearLayout>
</HorizontalScrollView>
<ListView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"></ListView>
</LinearLayout>
--- 轉載請注明本文位址---