Xamarin Android获取WiFi列表失败求助(Android 10+)
Xamarin Android 10+ 无法获取WiFi列表的问题排查与修复
针对你在树莓派Android 10+环境下无法获取WiFi列表的问题,核心原因是Android 10及以上版本对WiFi扫描和权限做了严格限制,你的代码未适配这些新规则,以下是具体问题和修复方案:
1. 权限不足与权限申请缺失
Android 10(API 29)及更高版本要求:
- 必须拥有
ACCESS_FINE_LOCATION前台权限(ACCESS_COARSE_LOCATION不再满足WiFi扫描要求) - Android 12(API 31)及以上还需添加
NEARBY_WIFI_DEVICES权限 - 权限必须主动向用户申请,仅在Manifest声明无效
修复:
第一步:更新AndroidManifest.xml
添加NEARBY_WIFI_DEVICES权限,并为位置权限补充前台属性:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" android:foregroundServiceType="location" /> <uses-permission android:name="android.permission.NEARBY_WIFI_DEVICES" android:usesPermissionFlags="neverForLocation" /> <!-- 保留原有必要权限 --> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
第二步:在调用扫描前主动申请权限
修改MainPage.xaml.cs的btn1_Clicked方法,先完成权限校验再执行扫描:
private async void btn1_Clicked(object sender, EventArgs e) { // 申请位置权限 var status = await Permissions.CheckStatusAsync<Permissions.LocationWhenInUse>(); if (status != PermissionStatus.Granted) { status = await Permissions.RequestAsync<Permissions.LocationWhenInUse>(); if (status != PermissionStatus.Granted) { txtlog.Text = "权限未授予,无法获取WiFi列表"; return; } } // 检查位置服务是否开启(Android 10+必须开启才能扫描WiFi) var locationEnabled = await Geolocation.IsLocationAvailableAsync(); if (!locationEnabled) { txtlog.Text = "请开启位置服务后重试"; await App.Current.MainPage.DisplayAlert("提示", "需要开启位置服务才能获取WiFi列表", "去设置"); // 可选:跳转到位置设置页 // Android.App.Application.Context.StartActivity(new Android.Content.Intent(Android.Provider.Settings.ActionLocationSourceSettings)); return; } // 执行WiFi扫描 try { IEnumerable<string> _wifiService = await DependencyService.Get<IWifi>().GetAvailableNetworksAsync(); // 过滤空SSID并去重 var uniqueWifis = _wifiService.Where(s => !string.IsNullOrEmpty(s)).Distinct().ToList(); txtlog.Text = $"找到{uniqueWifis.Count}个WiFi网络"; wifilist.ItemsSource = uniqueWifis; } catch (Exception ex) { txtlog.Text = $"扫描失败:{ex.Message}"; } }
2. 广播接收器未注销导致异常
你的代码注册了广播接收器,但未在扫描完成或超时后注销,会引发内存泄漏,甚至导致后续扫描失败。
修复:
修改Wifi类的GetAvailableNetworksAsync方法,确保接收器被注销:
public async Task<IEnumerable<string>> GetAvailableNetworksAsync() { var wifiMgr = (WifiManager)context.GetSystemService(Context.WifiService); var wifiReceiver = new WifiReceiver(wifiMgr); var intentFilter = new IntentFilter(WifiManager.ScanResultsAvailableAction); try { context.RegisterReceiver(wifiReceiver, intentFilter); return await Task.Run(() => wifiReceiver.Scan()); } finally { // 无论成功失败,强制注销接收器 try { context.UnregisterReceiver(wifiReceiver); } catch { } // 忽略注销失败的情况 } }
3. WiFi扫描的前台要求适配(Android 10+)
Android 10+规定WiFi扫描必须在应用前台执行,后台扫描频率被严格限制。同时需确保WiFi处于开启状态。
修复:
优化WifiReceiver的Scan方法,增加WiFi状态检查:
public IEnumerable<string> Scan() { tmr = new Timer(Timeout, null, TIMEOUT_MILLIS, System.Threading.Timeout.Infinite); // 检查并开启WiFi if (!wifi.IsWifiEnabled) { wifi.SetWifiEnabled(true); Thread.Sleep(1000); // 等待WiFi启动 } // 启动扫描并校验结果 bool scanStarted = wifi.StartScan(); if (!scanStarted) { receiverARE.Set(); return new List<string>(); } receiverARE.WaitOne(); return wifiNetworks; }
4. 扫描结果有效性校验
在OnReceive方法中,需确认扫描结果是否可用,避免空数据:
public override void OnReceive(Context context, Intent intent) { bool scanResultAvailable = intent.GetBooleanExtra(WifiManager.ExtraScanResultAvailable, false); if (!scanResultAvailable) { receiverARE.Set(); return; } IList<ScanResult> scanwifinetworks = wifi.ScanResults; foreach (ScanResult wifinetwork in scanwifinetworks) { // 过滤空SSID if (!string.IsNullOrEmpty(wifinetwork.Ssid)) { wifiNetworks.Add(wifinetwork.Ssid); } } receiverARE.Set(); }
额外注意事项
- 确认树莓派的WiFi硬件正常,可通过系统设置验证能搜索到WiFi网络
- Android 10+会限制扫描频率,避免短时间内多次触发扫描
- 若需后台扫描,需额外申请
ACCESS_BACKGROUND_LOCATION权限并启动前台服务
内容的提问来源于stack exchange,提问作者user19432624
相关产品推荐
相关产品推荐

