WiFi扫描通常需要原生代码。
在Android上,我们需要使用原生WifiManager来扫描WiFi。注意:需要相应的权限(如ACCESS_FINE_LOCATION)和运行时权限请求。
由于实现完整功能代码量较大,这里只给出框架代码。实际开发中,还需要考虑Android版本差异、权限请求等。
在Maui项目中,我们可以通过依赖注入获取该服务,然后调用扫描方法。
但是,请注意,从Android 10(API级别29)开始,对WiFi扫描的限制更加严格,应用需要具有精确位置权限,并且设备需要启用位置服务。
一. 创建共享wifi扫描接口
首先创建一个共享接口类:
cs
namespace MauiWifi
{
public interface IWifiScanner
{
Task<List<WifiNetwork>> ScanNetworksAsync();//扫描wifi
Task<bool> RequestPermissionsAsync();//请求权限
}
}
类中定义了一个扫描方法和一个请求权限方法,方法需要用异步 task之类
二.新建一个wifi 网络模型类WifiNetwork.cs
每一个附近的wifi网络都会被封装成一个模型类对象
cs
public class WifiNetwork
{
public string Ssid { get; set; }//wifi网络名
public string Bssid { get; set; }
public int SignalStrength { get; set; } // dBm
public int Frequency { get; set; } // MHz
public bool IsSecured { get; set; } //是否设置了密码
}
三.Android 实现
添加权限(Android/AndroidManifest.xml):
cs
<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" />
这是必须是权限,对于安卓10.0以上的版本还需要动态申请权限以及定位权限
四。实现接口类
// Platforms/Android/WifiScanner.cs 需建立在Android路径下
cs
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks; // 需要添加这个用于Task
using System.Linq; // 需要添加这个用于LINQ操作
using Android.Content;
using Android.Net.Wifi;
using Android.OS;
using Application = Android.App.Application;
namespace MauiWifi.Platforms.Android
{
// WiFi扫描器实现类,实现IWifiScanner接口
public class WifiScanner : IWifiScanner
{
private readonly WifiManager _wifiManager; //原生wifi管理类WifiManager对象
// 构造函数,初始化WifiManager
public WifiScanner()
{
// 从Android应用上下文中获取WifiService系统服务
_wifiManager = (WifiManager)Application.Context
.GetSystemService(Context.WifiService);
}
// 请求必要的权限(特别是位置权限,因为Android 6.0+需要位置权限来扫描WiFi)
public async Task<bool> RequestPermissionsAsync()
{
// 检查Android版本是否为6.0(API 23)或更高
if (Build.VERSION.SdkInt >= BuildVersionCodes.M)
{
// 请求运行时位置权限
var status = await Permissions.RequestAsync<Permissions.LocationWhenInUse>();
// 返回权限是否被授予
return status == PermissionStatus.Granted;
}
// Android 6.0以下版本不需要运行时权限
return true;
}
// 扫描附近的WiFi网络
public async Task<List<WifiNetwork>> ScanNetworksAsync()
{
// 创建存储WiFi网络结果的列表
var networks = new List<WifiNetwork>();
// 请求权限,如果权限被拒绝则返回空列表
if (!await RequestPermissionsAsync())
return networks;
// 检查WiFi是否启用,如果未启用则启用它
if (!_wifiManager.IsWifiEnabled)
_wifiManager.SetWifiEnabled(true);
// 开始扫描附近的WiFi网络
_wifiManager.StartScan();
// 等待扫描完成(2秒延迟,给扫描操作足够的时间)
await Task.Delay(2000);
// 获取扫描结果
var scanResults = _wifiManager.ScanResults;
// 遍历所有扫描到的WiFi网络
foreach (var result in scanResults)
{
// 将每个WiFi网络信息添加到列表中
networks.Add(new WifiNetwork
{
Ssid = result.Ssid, // 网络名称
Bssid = result.Bssid, // MAC地址
SignalStrength = result.Level, // 信号强度(dBm)
Frequency = result.Frequency, // 频率(MHz)
// 检查网络是否加密(通过检查能力字段是否包含安全协议)
IsSecured = !string.IsNullOrEmpty(result.Capabilities)
&& result.Capabilities.Contains("WEP")
|| result.Capabilities.Contains("PSK")
|| result.Capabilities.Contains("EAP")
});
}
// 对结果进行分组、去重和排序:
// 1. 按SSID分组(处理多个AP有相同SSID的情况)
// 2. 从每组中选择信号最强的网络
// 3. 转换为列表返回
return networks
.GroupBy(n => n.Ssid)
.Select(g => g.OrderByDescending(n => n.SignalStrength).First())
.ToList();
}
}
}
五.在 MauiProgram.cs 中注册服务
cs
//依赖注入wifi接口IWifiScanner,实现这个接口依赖Platforms.Android.WifiScanner
#if ANDROID
builder.Services.AddSingleton<IWifiScanner, Platforms.Android.WifiScanner>();
#endif
完整代码如下
cs
using Microsoft.Extensions.Logging;
namespace MauiWifi
{
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.ConfigureFonts(fonts =>
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
});
#if ANDROID
builder.Services.AddSingleton<IWifiScanner, Platforms.Android.WifiScanner>();
#endif
#if DEBUG
builder.Logging.AddDebug();
#endif
return builder.Build();
}
}
}
六.在页面中使用
cs
using System.Collections.ObjectModel;
namespace MauiWifi
{
public partial class MainPage : ContentPage
{
private readonly IWifiScanner _wifiScanner;//wifi扫描接口对象
//自动刷新的list<wifi模型>字段 _networks
private ObservableCollection<WifiNetwork> _networks = new();
public MainPage(IWifiScanner wifiScanner)
{
InitializeComponent();
_wifiScanner = wifiScanner;//依赖注入
wifiListView.ItemsSource = _networks;//绑定到界面的 Items
}
//扫描按键
private async void OnScanClicked(object sender, EventArgs e)
{
try
{
var networks = await _wifiScanner.ScanNetworksAsync();
_networks.Clear();//清空
foreach (var network in networks.OrderByDescending(n => n.SignalStrength))
{
_networks.Add(network);//逐个添加扫描到的附近WiFi
}
}
catch (Exception ex)
{
await DisplayAlert("错误", ex.Message, "确定");
}
}
}
}
七.XLML 页面
XML
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MauiWifi.MainPage">
<VerticalStackLayout>
<Button Text="扫描WiFi"
Clicked="OnScanClicked"
Margin="20"/>
<ListView x:Name="wifiListView">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<VerticalStackLayout Padding="10">
<Label Text="{Binding Ssid}"
FontSize="16"
FontAttributes="Bold"/>
<Label Text="{Binding SignalStrength, StringFormat='信号强度: {0} dBm'}"
FontSize="12"/>
<Label Text="{Binding Bssid}"
FontSize="10"
TextColor="Gray"/>
</VerticalStackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</VerticalStackLayout>
</ContentPage>
运行测试:原生api,需在真机上运行
