You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET MAUI前台服务WiFi扫描异常问题求助

解决方案:.NET MAUI前台服务WiFi扫描后台失效问题

针对你遇到的「应用关闭后前台服务存活但WiFi扫描停止」的问题,核心原因是安卓平台的后台权限限制与MAUI服务实现的细节问题,以下是针对性的解决步骤:


1. 补全安卓平台必要权限

安卓对后台WiFi扫描有严格的权限要求,需在安卓项目的AndroidManifest.xml中添加以下权限:

<!-- WiFi基础权限 -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<!-- 定位权限(WiFi扫描依赖定位,后台需申请后台定位) -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<!-- 前台服务与通知权限 -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<!-- 安卓13+专属WiFi扫描前台服务权限 -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_WIFI_SCAN" />

2. 调整前台服务的扫描触发逻辑

避免使用普通Timer(后台易被系统暂停),改用安卓Handler实现周期性扫描;同时动态注册WiFi扫描结果接收器(静态接收器在安卓8+后台失效):

[Service(ForegroundServiceType = ForegroundService.TypeWifiScan)]
public class WifiScanForegroundService : Service
{
    private WifiManager _wifiManager;
    private BroadcastReceiver _scanResultReceiver;
    private Handler _scanHandler;
    private Action _periodicScanAction;

    public override IBinder OnBind(Intent intent) => null;

    public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
    {
        // 启动前台通知,绑定服务
        StartForeground(1001, CreateForegroundNotification());

        _wifiManager = (WifiManager)GetSystemService(WifiService);
        // 动态注册扫描结果接收器
        _scanResultReceiver = new WifiScanResultReceiver();
        RegisterReceiver(_scanResultReceiver, new IntentFilter(WifiManager.ScanResultsAvailableAction));

        // 用Handler实现10秒一次的周期性扫描
        _scanHandler = new Handler(Looper.MainLooper);
        _periodicScanAction = () =>
        {
            _wifiManager.StartScan();
            _scanHandler.PostDelayed(_periodicScanAction, 10000);
        };
        _scanHandler.Post(_periodicScanAction);

        return StartCommandResult.Sticky;
    }

    private Notification CreateForegroundNotification()
    {
        var channelId = "WifiScanServiceChannel";
        if (Build.VERSION.SdkInt >= BuildVersionCodes.O)
        {
            var channel = new NotificationChannel(channelId, "WiFi扫描服务", NotificationImportance.Default)
            {
                Description = "持续扫描附近WiFi网络"
            };
            var notificationManager = (NotificationManager)GetSystemService(NotificationService);
            notificationManager.CreateNotificationChannel(channel);
        }

        var launchIntent = PackageManager.GetLaunchIntentForPackage(PackageName);
        var pendingIntent = PendingIntent.GetActivity(this, 0, launchIntent, PendingIntentFlags.Immutable);

        return new Notification.Builder(this, channelId)
            .SetContentTitle("WiFi扫描中")
            .SetContentText("正在更新附近WiFi列表")
            .SetSmallIcon(Resource.Drawable.ic_notification)
            .SetContentIntent(pendingIntent)
            .Build();
    }

    public override void OnDestroy()
    {
        base.OnDestroy();
        UnregisterReceiver(_scanResultReceiver);
        _scanHandler.RemoveCallbacks(_periodicScanAction);
    }
}

// 扫描结果接收器
public class WifiScanResultReceiver : BroadcastReceiver
{
    public override void OnReceive(Context context, Intent intent)
    {
        if (intent.Action != WifiManager.ScanResultsAvailableAction) return;

        var wifiManager = (WifiManager)context.GetSystemService(WifiService);
        var scanResults = wifiManager.ScanResults;
        // 用MAUI的弱引用信使传递结果到MainPage
        WeakReferenceMessenger.Default.Send(new WifiScanUpdateMessage(scanResults));
    }
}

// 消息模型
public class WifiScanUpdateMessage
{
    public List<ScanResult> Results { get; }
    public WifiScanUpdateMessage(List<ScanResult> results) => Results = results;
}

3. MainPage端权限请求与结果更新

启动服务前必须请求完整权限,同时订阅扫描结果更新ListView:

public partial class MainPage : ContentPage
{
    public MainPage()
    {
        InitializeComponent();
        // 订阅扫描结果更新
        WeakReferenceMessenger.Default.Register<WifiScanUpdateMessage>(this, (_, message) =>
        {
            MainThread.BeginInvokeOnMainThread(() =>
            {
                // 过滤目标SSID并更新ListView
                var targetNetworks = message.Results.Where(r => r.Ssid == "AndroidWifi").ToList();
                WifiListView.ItemsSource = targetNetworks;
            });
        });
    }

    private async void StartServiceBtn_Clicked(object sender, EventArgs e)
    {
        // 请求定位权限(含后台)
        var locationStatus = await Permissions.CheckStatusAsync<Permissions.LocationAlways>();
        if (locationStatus != PermissionStatus.Granted)
        {
            locationStatus = await Permissions.RequestAsync<Permissions.LocationAlways>();
        }

        // 请求通知权限
        var notificationStatus = await Permissions.CheckStatusAsync<Permissions.PostNotifications>();
        if (notificationStatus != PermissionStatus.Granted)
        {
            notificationStatus = await Permissions.RequestAsync<Permissions.PostNotifications>();
        }

        // 启动前台服务
        if (DeviceInfo.Platform == DevicePlatform.Android && locationStatus == PermissionStatus.Granted)
        {
            var intent = new Intent(Android.App.Application.Context, typeof(WifiScanForegroundService));
            Android.App.Application.Context.StartForegroundService(intent);
        }
    }

    // 引导用户关闭电池优化(厂商后台限制的关键)
    private void OpenBatterySettingsBtn_Clicked(object sender, EventArgs e)
    {
        if (DeviceInfo.Platform == DevicePlatform.Android && Build.VERSION.SdkInt >= BuildVersionCodes.M)
        {
            var intent = new Intent(Android.Provider.Settings.ActionRequestIgnoreBatteryOptimizations);
            intent.SetData(Android.Net.Uri.Parse($"package:{Android.App.Application.Context.PackageName}"));
            Android.App.Application.Context.StartActivity(intent);
        }
    }
}

关键注意点

  1. 安卓后台限制:多数国产厂商会对后台应用做额外限制,必须引导用户关闭当前应用的「电池优化」,否则即使是前台服务也可能被限制扫描。
  2. 权限必须齐全:后台WiFi扫描依赖后台定位权限,仅申请前台定位权限在应用关闭后会失效。
  3. 避免依赖Activity上下文:服务中必须使用ApplicationContext,不能绑定到MainActivity的上下文,否则应用关闭后上下文销毁会导致扫描失败。

内容的提问来源于stack exchange,提问作者loury Pe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 21:40:33