Android WiFi
WiFi相关的知识点,我是第一次接触,所以比较零碎
Wifi基础知识
WiFi Scan
官方文档对WiFi扫描的说明:
比较完整的例子,可参考:
按照官方文档,大致的步骤:
1.为 SCAN_RESULTS_AVAILABLE_ACTION
注册一个广播监听器,系统会在完成扫描请求时调用此监听器,提供其成功/失败状态
2.使用 WifiManager.startScan()
请求扫描
3.使用 WifiManager.getScanResults()
获取扫描结果
在使用之前,需要下面的相关权限:
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
ACCESS_WIFI_STATE
- Allows applications to access information about Wi-Fi networks.CHANGE_WIFI_STATE
- Allows applications to change Wi-Fi connectivity state.
ACCESS_FINE_LOCATION
和 ACCESS_COARSE_LOCATION
属于危险权限,需要运行时权限
android.permission.ACCESS_NETWORK_STATE
与android.permission.ACCESS_WIFI_STATE
的区别
参考:
android.permission.ACCESS_NETWORK_STATE
is needed for accessing ConnectivityManager (mainly for monitoring network connections in general), whileandroid.permission.ACCESS_WIFI_STATE
grants access to WifiManager (for managing all aspects of Wi-Fi connectivity in particular).
例子如下:
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity-TAG";
//需要先申请的权限
String[] permissions = new String[] {
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION
};
private WifiManager mWifiManager;
private ListView mListView;
private Button mScanBtn;
private List<ScanResult> mResults;
private ArrayList<String> mArrayList = new ArrayList<>();
private ArrayAdapter mAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
requestPermissions();
mScanBtn = findViewById(R.id.scanBtn);
mListView = findViewById(R.id.wifiList);
mScanBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
scanWiFi();
}
});
mWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
if (!mWifiManager.isWifiEnabled()) {
Toast.makeText(MainActivity.this, "WiFi is disabled... we need enable it", Toast.LENGTH_SHORT).show();
//Enable or disable Wi-Fi.
//Applications must have the android.Manifest.permission.CHANGE_WIFI_STATE permission to toggle wifi.
mWifiManager.setWifiEnabled(true);
}
mAdapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, mArrayList);
mListView.setAdapter(mAdapter);
scanWiFi();
}
//扫描WiFi
private void scanWiFi() {
mArrayList.clear();
registerReceiver(wifiReceiver, new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
mWifiManager.startScan();
Toast.makeText(this, "Scanning WiFi...", Toast.LENGTH_SHORT).show();
}
// 请求权限
private void requestPermissions() {
for (String permission : permissions) {
if (checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(MainActivity.this, permissions, 100);
}
}
}
BroadcastReceiver wifiReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent != null) {
String action = intent.getAction();
Log.d(TAG, "onReceive:" + action);
if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
unregisterReceiver(this);
boolean success = intent.getBooleanExtra(WifiManager.EXTRA_RESULTS_UPDATED, false);
if (success) {
Toast.makeText(MainActivity.this, "Scan success", Toast.LENGTH_SHORT).show();
mResults = mWifiManager.getScanResults();
for (ScanResult scanResult : mResults) {
mArrayList.add(scanResult.SSID + " - " + scanResult.capabilities);
mAdapter.notifyDataSetChanged();
}
} else {
Toast.makeText(MainActivity.this, "Scan fail", Toast.LENGTH_SHORT).show();
}
}
}
}
};
}
1.开启手机WLAN
,扫描结果如下:
2.如果未开启WLAN
,调用mWifiManager.setWifiEnabled(true)
后,在本人的oppo手机上有如下的弹窗出现
如果选择了允许,WiFi扫描也会成功,列表中也会有扫描结果
我原本以为mWifiManager.setWifiEnabled(true)
会把手机的WLAN
开关打开,但是却并非如此,WLAN
还是关闭状态
还需要注意的是setWifiEnabled (boolean enabled)
方法已废弃
Starting with Build.VERSION_CODES#Q, applications are not allowed to enable/disable Wi-Fi. Compatibility Note: For applications targeting
Build.VERSION_CODES.Q
or above, this API will always fail and returnfalse
. If apps are targeting an older SDK (Build.VERSION_CODES.P
or below), they can continue to use this API.Deprecation Exemptions:(废弃豁免)
- Device Owner (DO), Profile Owner (PO) and system apps.
Enable or disable Wi-Fi.
Applications must have the
Manifest.permission.CHANGE_WIFI_STATE
permission to toggle wifi.
如何解决这个废弃的问题,可参考:
Intent panelIntent = new Intent(Settings.Panel.ACTION_INTERNET_CONNECTIVITY);
startActivityForResult(panelIntent, 100);
此时如果WLAN
被关闭,将会打开如下的界面
连接WiFi
原来连接WiFi大概要使用如下的方法和类
- WifiConfiguration
- WifiManager#addNetwork
- WifiManager#enableNetwork
- WifiManager#disableNetwork
按如下的方式来连接WiFi
private void connectWiFi(String networkCapabilities, String networkSSID) {
Toast.makeText(this, "Connecting to network: "+ networkSSID, Toast.LENGTH_SHORT).show();
String networkPass = "password";
WifiConfiguration wifiConfig = new WifiConfiguration();
wifiConfig.SSID = "\"" + networkSSID + "\"";
if(networkCapabilities.toUpperCase().contains("WEP")) { // WEP Network.
Toast.makeText(this, "WEP Network", Toast.LENGTH_SHORT).show();
wifiConfig.wepKeys[0] = "\"" + networkPass + "\"";
wifiConfig.wepTxKeyIndex = 0;
wifiConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
wifiConfig.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP40);
} else if(networkCapabilities.toUpperCase().contains("WPA")) { // WPA Network
Toast.makeText(this, "WPA Network", Toast.LENGTH_SHORT).show();
wifiConfig.preSharedKey = "\""+ networkPass +"\"";
} else { // OPEN Network.
Toast.makeText(this, "OPEN Network", Toast.LENGTH_SHORT).show();
wifiConfig.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
}
int result = mWifiManager.addNetwork(wifiConfig);
List<WifiConfiguration> list = this.mWifiManager.getConfiguredNetworks();
for( WifiConfiguration config : list ) {
if(config.SSID != null && config.SSID.equals("\"" + networkSSID + "\"")) {
this.mWifiManager.disconnect();
this.mWifiManager.enableNetwork(config.networkId, true);
this.mWifiManager.reconnect();
break;
}
}
}
但由于mWifiManager.addNetwork(wifiConfig)
该方法一直返回的是-1
,所以一直没有成功
addNetwork方法有如下的介绍:
在Android 10 及以上中,一直返回-1
而我手机的版本为Android 11
,我估计是这个问题造成的,该怎么处理了?
在网上找到了如下的方法
//连接WiFi
private void connectWiFi(String networkCapabilities, String networkSSID) {
Toast.makeText(this, "Connecting to network: "+ networkSSID, Toast.LENGTH_SHORT).show();
String networkPass = "xingxing_password";
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) {
NetworkSpecifier specifier =
new WifiNetworkSpecifier.Builder()
.setSsidPattern(new PatternMatcher(networkSSID, PatternMatcher.PATTERN_PREFIX))
.setWpa2Passphrase(networkPass)
.build();
NetworkRequest request =
new NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.setNetworkSpecifier(specifier)
.build();
ConnectivityManager connectivityManager = (ConnectivityManager) this.getSystemService(Context.CONNECTIVITY_SERVICE);
ConnectivityManager.NetworkCallback networkCallback = new ConnectivityManager.NetworkCallback() {
@Override
public void onAvailable(Network network) {
// do success processing here..
Log.d(TAG, "onAvailable " + network.toString());
}
@Override
public void onUnavailable() {
// do failure processing here..
Log.d(TAG, "onUnavailable ");
}
};
connectivityManager.requestNetwork(request, networkCallback);
// Release the request when done.
// connectivityManager.unregisterNetworkCallback(networkCallback);
}
}
在我oppo Android11手机上,当通过上面的方法连接某个WiFi时,会跳转到如下的页面:
点击要连接的WiFi后,会自动连接上对应的WiFi,不需要输入密码
注意
1.需要申请如下的权限
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" /> <uses-permission android:name="android.permission.WRITE_SETTINGS" />
否则可能会有如下的提示:
java.lang.SecurityException: com.example.wifidemo was not granted either of these permissions: android.permission.CHANGE_NETWORK_STATE, android.permission.WRITE_SETTINGS.
2.测试的时候,
WLAN
要开启
可参考:
其它方法
1.getWifiState()
public int getWifiState ()
Gets the Wi-Fi enabled state.
检查当前wifi状态.
WIFI_STATE_DISABLING
- Wi-Fi is currently being disabled. The state will change toWIFI_STATE_DISABLED
if it finishes successfully. 值为0WIFI_STATE_DISABLED
- Wi-Fi is disabled. 值为1WIFI_STATE_ENABLING
- Wi-Fi is currently being enabled. The state will change toWIFI_STATE_ENABLED
if it finishes successfully. 值为2WIFI_STATE_ENABLED
- Wi-Fi is enabled. 值为3WIFI_STATE_UNKNOWN
- Wi-Fi is in an unknown state. This state will occur when an error happens while enabling or disabling. 值为4
// 获取WiFi状态
private void getWiFiState() {
int wifiState = mWifiManager.getWifiState();
switch (wifiState) {
case WifiManager.WIFI_STATE_ENABLED:
Log.d(TAG, "wifiState = " + wifiState + " WIFI_STATE_ENABLED");
break;
case WifiManager.WIFI_STATE_DISABLED:
Log.d(TAG, "wifiState = " + wifiState + " WIFI_STATE_DISABLED");
break;
default:
break;
}
}
如果打开WLAN
开关,WiFi状态为WIFI_STATE_ENABLED
2021-08-17 15:08:10.602 10282-10282/com.example.wifidemo D/MainActivity-TAG: wifiState = 3 WIFI_STATE_ENABLED
如果关闭WLAN
,WiFi状态为WIFI_STATE_DISABLED
2021-08-17 15:10:36.497 13093-13093/com.example.wifidemo D/MainActivity-TAG: wifiState = 1 WIFI_STATE_DISABLED
2.getConnectionInfo
public WifiInfo getConnectionInfo ()
Return dynamic information about the current Wi-Fi connection, if any is active.
当前wifi连接信息
注意这个方法在最新的版本中也是废弃了
This method was deprecated in API level 31.
Starting withBuild.VERSION_CODES#S
, WifiInfo retrieval is moved toConnectivityManager
API surface. WifiInfo is attached inNetworkCapabilities#getTransportInfo()
which is available via callback inNetworkCallback#onCapabilitiesChanged(Network, NetworkCapabilities)
or on-demand fromConnectivityManager#getNetworkCapabilities(Network)
.
如下的例子:
WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
int ip = wifiInfo.getIpAddress();
String macAddress = wifiInfo.getMacAddress();
String bssid = wifiInfo.getBSSID();
int rssi = wifiInfo.getRssi();
int linkspeed = wifiInfo.getLinkSpeed();
String ssid = wifiInfo.getSSID();
int networkId = wifiInfo.getNetworkId();
String ipAddress = Formatter.formatIpAddress(ip);
Log.d(TAG, "macAddress = " + macAddress);
Log.d(TAG, "bssid = " + bssid);
Log.d(TAG, "rssi = " + rssi);
Log.d(TAG, "linkspeed = " + linkspeed);
Log.d(TAG, "ssid = " + ssid);
Log.d(TAG, "networkId = " + networkId);
Log.d(TAG, "ipAddress = " + ipAddress);
当前本人手机连接信息
2021-08-17 14:23:41.086 30534-30534/com.example.wifidemo D/MainActivity-TAG: macAddress = 02:00:00:00:00:00
2021-08-17 14:23:41.086 30534-30534/com.example.wifidemo D/MainActivity-TAG: bssid = ec:26:ca:c9:7d:3e
2021-08-17 14:23:41.086 30534-30534/com.example.wifidemo D/MainActivity-TAG: rssi = -33
2021-08-17 14:23:41.086 30534-30534/com.example.wifidemo D/MainActivity-TAG: linkspeed = 72
2021-08-17 14:23:41.086 30534-30534/com.example.wifidemo D/MainActivity-TAG: ssid = "xingxing"
2021-08-17 14:23:41.086 30534-30534/com.example.wifidemo D/MainActivity-TAG: networkId = 6
2021-08-17 14:23:41.086 30534-30534/com.example.wifidemo D/MainActivity-TAG: ipAddress = 192.168.2.102
3.另一种监测WiFi是否开启的方法
在网络上看到了另一种监测WiFi状态的方codinginflow/AndroidManifest.xml
通过注册广播WifiManager.WIFI_STATE_CHANGED_ACTION
IntentFilter intentFilter = new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION);
registerReceiver(wifiStateReceiver, intentFilter);
private BroadcastReceiver wifiStateReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
int wifiStateExtra = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
WifiManager.WIFI_STATE_UNKNOWN);
switch (wifiStateExtra) {
case WifiManager.WIFI_STATE_ENABLED:
wifiSwitch.setChecked(true);
wifiSwitch.setText("WiFi is ON");
break;
case WifiManager.WIFI_STATE_DISABLED:
wifiSwitch.setChecked(false);
wifiSwitch.setText("WiFi is OFF");
break;
}
}
};
4.WifiManager.NETWORK_STATE_CHANGED_ACTION
Broadcast intent action indicating that the state of Wi-Fi connectivity has changed. An extra provides the new state in the form of a
NetworkInfo
object. No network-related permissions are required to subscribe to this broadcast.This broadcast is not delivered to manifest receivers in applications that target API version 26 or later.
表示的是 Wi-Fi连接状态改变
可参考:
// 监听wifi的连接状态即是否连上了一个有效无线路由
if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(intent.getAction())) {
Parcelable parcelableExtra = intent
.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
if (null != parcelableExtra) {
// 获取联网状态的NetWorkInfo对象
NetworkInfo networkInfo = (NetworkInfo) parcelableExtra;
//获取的State对象则代表着连接成功与否等状态
NetworkInfo.State state = networkInfo.getState();
//判断网络是否已经连接
boolean isConnected = state == NetworkInfo.State.CONNECTED;
Log.e("TAG", "isConnected:" + isConnected);
if (isConnected) {
} else {
}
}
}
参考资料
其它可参考的资料:
- Android WiFi开发 (一)扫描、连接、信息
- Android-wifi
- Android WiFi 开发
- Android Wifi Scanning Tutorial
- Android设备wifi开发
- Android Wifi 开发相关
Github上有封装的类,可以参考下: