A summary
This paper introduces the development interface and usage of WiFi module in the application layer of Android, including some suggestions for dealing with common problems, and finally provides a github project as a reference Demo.
II. Introduction to relevant concepts
1 class involved
- Wifi Manager -- entry class, through which all operations related to Wifi pass
- WifiConfiguration - when connecting hotspots, create a configuration for the hotspots through this class, and generate a networkId based on this configuration by WiFi manager, and then start connecting; in addition, it is also used to represent the local record of a connected hotspot
- wifi info -- indicates the current wifi network connection information
- ScanResult -- scanned hotspot information class, each object represents a scanned hotspot, including several hotspot information
AccessPoint: This article defines the object for easy description and explanation. The structure is as follows:
public class AccessPoint {
private String ssid;
private String bssid;
private String password;
private float signalStrength; // 0~100
private String encryptionType;
private int networkId;
/**
* aps are relative AccessPoints who share the same ssid while different bssid
* we will treat them as one hotspot
*/
private ArrayList<AccessPoint> relativeAPs;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
2 broadcasting involved
- WifiManager.WIFI_STATE_CHANGED_ACTION - wifi switch change broadcast
- WifiManager.SCAN_RESULTS_AVAILABLE_ACTION - Notification broadcast of hot spot scanning results
- WifiManager.SUPPLICANT_STATE_CHANGED_ACTION - Notification broadcast of hotspot connection results
- WifiManager.NETWORK_STATE_CHANGED_ACTION - network status change broadcast (cooperate with the previous broadcast to complete the connection process notification)
3 relevant properties and concepts
- networkId -- when connecting to a wifi hotspot, the system will generate a networkId for the hotspot. On the same device, the networkids of different hotspots are unique. Generally, they are integers greater than 0. On some devices, the first hotspot networkId connected after factory restoration is 0
- ssid -- wifi hotspot name, repeatable
- bssid -- similar to the mac address, but not the router's mac address. Together with ssid, bssid can be used as the unique identification of hotspots, and each hotspot of this attribute is unique and not repeated
- Kinship hotspot - (the concept set in this paper) ssid is the same, but all hotspots of bssid are different, which are kinship hotspots for each other. android devices will treat all kinship hotspots with the same ssid as a hotspot
4 hotspot encryption type
At present, common and hot spots to be dealt with include the following three categories:
- Open - open network, i.e. no encryption, direct connection
- wep -- hot spot of wep encryption type, outdated, insecure, easy to be cracked, and the current utilization rate is less than 10%
- wpa/wpa2 -- the most widely used, relatively safest and most difficult encryption type
wps (wifi protected setup): it is a technology to further enhance the hotspot of wpa and simplify the connection process. It does not belong to encryption type.
III. Development details
1 get WiFi manager entry class instance:
wifiManager = (WifiManager) context
.getSystemService(Context.WIFI_SERVICE);
- 1
- 2
2 turn wifi on and off
wifiManager.setWifiEnabled(true)
- 1
true means to turn on the wifi switch, false means to turn off. The return value of this method only represents whether the operation is successful, not the change of wifi status;
By listening to the broadcast WifiManager.WIFI_STATE_CHANGED_ACTION to determine the real wifi switch change. The broadcast has an int value to represent the wifi state:
int wifistate = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
WifiManager.WIFI_STATE_DISABLED);
switch (wifistate) {
case WifiManager.WIFI_STATE_DISABLED:
//wifi is off
break;
case WifiManager.WIFI_STATE_ENABLED:
//wifi is on
break;
case WifiManager.WIFI_STATE_ENABLING:
//wifi is turning on
break;
default:
break;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
As you can see, this operation is actually an asynchronous operation, and generally takes 1-3 seconds.
3 hot spot scanning around
wifiManager.startScan()
- 1
The above method is the interface to start scanning. Its return value represents whether the operation is successful. The scanning result is obtained through another interface:
List<ScanResult> results = wifiManager.getScanResults();
- 1
Generally, after calling startScan initiatively, it will receive about 2 seconds WifiManager.SCAN_RESULTS_AVAILABLE_ACTION), which includes an additional parameter of boolean type:
boolean isScanned = intent.getBooleanExtra(WifiManager.EXTRA_RESULTS_UPDATED, true);
- 1
The above value indicates whether the scan result is available. If available, getScanResults can be used to get the result. Before the result is not ready, null will be returned.
Generally, the system itself will call the startScan interface, but this operation is relatively power consuming, so it needs to be used as appropriate in the application, and does not need to be called frequently.
4 get connected hotspots
All connected hotspots will exist in a local file. The general path is / data / misc / WiFi / WPA_ supplicant.conf (root is required in the view), and it is obtained in the program through the following interface:
List<WifiConfiguration> configurations = wifiManager.getConfiguredNetworks();
- 1
Only ssid and networkId can be used to directly connect to the hotspot. Other information such as bssid and key are basically empty. (how to connect hotspots directly, described below)
5 get current wifi connection information
WifiInfo info = wifiManager.getConnectionInfo();
- 1
This object represents the currently connected hotspot. If there is no connection, null will be returned;
This object can obtain information including ssid, bssid, networkId, etc., while ssid includes double quotes, such as "CCMC". In the previous scan result, ssid does not have double quotes.
6 connect the specified hotspot
To connect an unconnected hotspot, three steps are required:
1) Create a configuration: WiFi configuration
public WifiConfiguration createConfiguration(AccessPoint ap) {
String SSID = ap.getSsid();
WifiConfiguration config = new WifiConfiguration();
config.SSID = "\"" + SSID + "\"";
String encryptionType = ap.getEncryptionType();
String password = ap.getPassword();
if (encryptionType.contains("wep")) {
/**
* special handling according to password length is a must for wep
*/
int i = password.length();
if (((i == 10 || (i == 26) || (i == 58))) && (password.matches("[0-9A-Fa-f]*"))) {
config.wepKeys[0] = password;
} else {
config.wepKeys[0] = "\"" + password + "\"";
}
config.allowedAuthAlgorithms
.set(WifiConfiguration.AuthAlgorithm.SHARED);
config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
config.wepTxKeyIndex = 0;
} else if (encryptionType.contains("wpa")) {
config.preSharedKey = "\"" + password + "\"";
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
} else {
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
}
return config;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
*There are many codes for creating configuration on the Internet, but most of them have not been verified. The above codes have passed the online version test and are accurate and available.
The way to determine the encryption type can be optimized. This is only an example. *
2) Generate a networkId
WifiConfiguration config = createConfiguration(ap);
/**
* networkId is bigger than 0 in most time, 0 in few time and smaller than 0 in no time
*/
int networkId = networkId = wifiManager.addNetwork(config);
- 1
- 2
- 3
- 4
- 5
- 6
In general, when performing the above operations on a connected hotspot (with a local connection record), a networkId less than 0 will be returned at api21 or above. At this time, it is meaningless to perform the next connection step. Obtaining a networkId less than 0 indicates that the connection failed.
3) Start connection
wifiManager.enableNetwork(networkId, true)
- 1
For the connected hotspots, after obtaining the networkId of the hotspot through the method in Item 4, you can directly connect in the third step without 1) 2);
If it is necessary to carry out 12 steps (such as trying a new password, because even if the wrong password connection is used, the system will generate a local record for this connection), you must remove the local record at the beginning, and the remove operation will be described below.
The connection results are fed back through two broadcasts: WifiManager.NETWORK_STATE_CHANGED_ACTION and WifiManager.SUPPLICANT_STATE_CHANGED_ACTION
Among them, the result notification of password error needs to be judged through the second broadcast:
int error = intent.getIntExtra(WifiManager.EXTRA_SUPPLICANT_ERROR, 0);
if (WifiManager.ERROR_AUTHENTICATING == error) {
//Password error, authentication failed
}
- 1
- 2
- 3
- 4
Other results are received through the first broadcast:
if (intent.getAction().equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
NetworkInfo info = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
if (null != info) {
NetworkInfo.DetailedState state = info.getDetailedState();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
public enum DetailedState {
/** Ready to start data connection setup. */
IDLE,
/** Searching for an available access point. */
SCANNING,
/** Currently setting up data connection. */
CONNECTING,
/** Network link established, performing authentication. */
AUTHENTICATING,
/** Awaiting response from DHCP server in order to assign IP address information. */
OBTAINING_IPADDR,
/** IP traffic should be available. */
CONNECTED,
/** IP traffic is suspended */
SUSPENDED,
/** Currently tearing down data connection. */
DISCONNECTING,
/** IP traffic not available. */
DISCONNECTED,
/** Attempt to connect failed. */
FAILED,
/** Access to this network is blocked. */
BLOCKED,
/** Link has poor connectivity. */
VERIFYING_POOR_LINK,
/** Checking if network is a captive portal */
CAPTIVE_PORTAL_CHECK
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
7 disconnect the current wifi connection
wifiManager.disconnect()
- 1
The above interface return value indicates whether the current operation is successful. The final result of the operation will be fed back in two broadcasts:
WifiManager.SUPPLICANT_STATE_CHANGED_ACTION
WifiManager.NETWORK_STATE_CHANGED_ACTION
And the successful broadcast will be sent several times.
8 forget a connected hotspot
boolean isRemoved = wifiManager.removeNetwork(networkId)
- 1
The return value indicates whether the operation is successful or not. In systems above api21, the success rate is below 10%, and in systems below api21, the operation is basically successful;
This operation can be repeated to improve the success rate, but it has little effect.