Android 6及以上系统获取可用WiFi列表失败的问题求助
解决Android 6+无法获取WiFi扫描列表的问题
首先,你的代码在Android 6以下设备正常,但高版本失效,核心原因是Android 6.0(API 23)开始的运行时权限模型,加上后续版本对WiFi扫描新增的位置服务强制要求和扫描限制。我来帮你一步步排查和修复:
1. 必须开启位置服务(关键!)
从Android 6.0开始,系统要求获取WiFi扫描结果时,不仅要有位置权限,还必须开启设备的位置服务(GPS或网络定位)。哪怕你申请了ACCESS_FINE_LOCATION/ACCESS_COARSE_LOCATION,如果用户关闭了位置服务,getScanResults()会返回空列表。
代码中添加位置服务检查
在权限授予后,先检查位置服务是否开启,如果没开启,引导用户去设置打开:
// 在onPermissionGranted方法中添加 LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); boolean isLocationEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) || locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER); if (!isLocationEnabled) { // 引导用户开启位置服务 Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS); startActivityForResult(intent, 1001); } else { // 继续WiFi扫描流程 startWifiScan(); }
然后在onActivityResult中处理用户返回后的逻辑:
@Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == 1001) { // 用户返回后,重新检查位置服务并启动扫描 LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); boolean isLocationEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) || locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER); if (isLocationEnabled) { startWifiScan(); } else { Toast.makeText(this, "位置服务未开启,无法获取WiFi列表", Toast.LENGTH_SHORT).show(); } } } // 把原来的WiFi扫描逻辑抽成方法 private void startWifiScan() { mainWifi = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE); if (!mainWifi.isWifiEnabled()) { Toast.makeText(getApplicationContext(), "wifi已关闭,正在开启...", Toast.LENGTH_LONG).show(); mainWifi.setWifiEnabled(true); } receiverWifi = new WifiReceiver(); registerReceiver(receiverWifi, new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)); // 主动触发扫描,并可以同步尝试获取结果(避免广播延迟) boolean scanStarted = mainWifi.startScan(); if (scanStarted) { // 可以先尝试获取一次结果,可能之前的扫描缓存存在 List<ScanResult> tempList = mainWifi.getScanResults(); if (tempList != null && !tempList.isEmpty()) { updateWifiList(tempList); } } else { Toast.makeText(this, "扫描启动失败,请检查权限和WiFi状态", Toast.LENGTH_SHORT).show(); } } // 抽离更新列表的方法,复用 private void updateWifiList(List<ScanResult> wifiList) { sb = new StringBuilder(); sb.append("\n 可用WiFi数量:"+wifiList.size()+"\n\n"); for(int i = 0; i < wifiList.size(); i++){ sb.append((i+1) + ". "); sb.append(wifiList.get(i).toString()); sb.append("\n\n"); Log.i("LOGO_WIFI", sb.toString()); } // 这里可以把sb的内容显示到UI上 }
2. 权限适配不同Android版本
- Android 6-9:需要
ACCESS_FINE_LOCATION或ACCESS_COARSE_LOCATION,同时要在运行时申请。 - Android 10+(API 29):必须申请
ACCESS_FINE_LOCATION,ACCESS_COARSE_LOCATION无法获取WiFi扫描结果。 - Android 12+(API 31):新增
ACCESS_WIFI_SCAN权限,需要在清单文件中声明,并且运行时申请(如果是targetSdkVersion 31+)。
清单文件补充权限
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /> <!-- Android 12+ 新增 --> <uses-permission android:name="android.permission.ACCESS_WIFI_SCAN" android:minSdkVersion="31" /> <!-- 可选:如果需要网络定位 --> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
3. 处理广播接收的可靠性问题
- Android 8.0(API 26)开始,静态注册的广播接收器会受到限制,但你用的是动态注册,没问题,但要注意在
onDestroy中注销接收器,避免内存泄漏:
@Override protected void onDestroy() { super.onDestroy(); if (receiverWifi != null) { unregisterReceiver(receiverWifi); } }
- 有时候
SCAN_RESULTS_AVAILABLE_ACTION广播可能不会触发(比如系统限制扫描频率),可以考虑使用WifiManager.startScan()的返回值判断扫描是否启动,同时主动调用getScanResults()获取结果,不要完全依赖广播。
4. 后台扫描限制(Android 8+)
如果你的App在后台,Android 8+会限制WiFi扫描的频率(每分钟最多4次),如果是前台App则不受此限制。所以确保测试时App处于前台状态。
修改后的WifiReceiver可以简化,直接调用更新方法:
class WifiReceiver extends BroadcastReceiver { @Override public void onReceive(Context c, Intent intent) { if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(intent.getAction())) { List<ScanResult> wifiList = mainWifi.getScanResults(); if (wifiList != null) { updateWifiList(wifiList); } } } }
最后,测试时记得:
- 确认位置服务已开启
- 确认App已授予位置权限
- 确保App处于前台状态
内容的提问来源于stack exchange,提问作者Ehsan
相关产品推荐
相关产品推荐

