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

.NET MAUI Android端:关闭APP后持续扫描WiFi网络的问题

解决.NET MAUI前台服务在APP关闭后停止WiFi扫描的问题

问题根源分析

你的代码存在几个关键问题导致APP关闭后扫描停止:

  1. 服务重启策略错误:OnStartCommand返回StartCommandResult.NotSticky,系统不会在服务被回收后重启它,APP关闭后服务可能被系统杀死。
  2. 扫描逻辑嵌套循环冲突:ScanWifiNetworks内部的while(isScanning)和外层的Task.Run循环重复,且每次调用都会重新创建cancellationTokenSource,导致取消令牌失效。
  3. 扫描结果等待不可靠:用固定的Task.Delay(5000)等待扫描结果,无法保证扫描完成,可能导致结果为空。
  4. 服务启动方式不兼容高版本Android:Android 8.0+要求用StartForegroundService启动前台服务,否则会触发ANR。

修复步骤

1. 调整服务重启策略

在OnStartCommand中返回StartCommandResult.Sticky,确保系统在服务意外终止后自动重启:

return StartCommandResult.Sticky;

2. 重构扫描逻辑,移除嵌套循环

删除ScanWifiNetworks内部的while(isScanning)循环,由外层的Task.Run循环控制扫描周期,避免重复创建取消令牌。

3. 用TaskCompletionSource可靠等待扫描结果

替换固定延迟,通过TaskCompletionSource等待广播接收器触发,确保获取到扫描结果。

4. 适配高版本Android的服务启动方式

修改Start()方法,使用StartForegroundService:

if (Build.VERSION.SdkInt >= BuildVersionCodes.O)
{
    MainActivity.ActivityCurrent.StartForegroundService(startService);
}
else
{
    MainActivity.ActivityCurrent.StartService(startService);
}

5. 确保权限配置正确

在Android项目的AndroidManifest.xml中添加必要权限:

<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" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

修改后的完整服务代码

[Service(ForegroundServiceType = Android.Content.PM.ForegroundService.TypeDataSync)]
public class DemoServices : Service, IServicesTest
{
    private bool isScanning = false;
    private CancellationTokenSource cancellationTokenSource;

    public override void OnCreate()
    {
        base.OnCreate();
    }

    public override IBinder OnBind(Intent intent)
    {
        throw new NotImplementedException();
    }

    [return: GeneratedEnum]
    public override StartCommandResult OnStartCommand(Intent intent, [GeneratedEnum] StartCommandFlags flags, int startId)
    {
        if (intent.Action == "START_SERVICE")
        {
            System.Diagnostics.Debug.WriteLine("服务已启动");

            if (!isScanning)
            {
                isScanning = true;
                cancellationTokenSource = new CancellationTokenSource();

                Task.Run(async () =>
                {
                    while (!cancellationTokenSource.Token.IsCancellationRequested)
                    {
                        await ScanWifiNetworks(cancellationTokenSource.Token);
                        await Task.Delay(TimeSpan.FromMinutes(2), cancellationTokenSource.Token);
                    }
                }, cancellationTokenSource.Token);

                RegisterNotification();
            }
        }
        else if (intent.Action == "STOP_SERVICE")
        {
            System.Diagnostics.Debug.WriteLine("服务已停止");
            cancellationTokenSource?.Cancel();
            isScanning = false;
            StopForeground(true);
            StopSelfResult(startId);
        }
        // 改为Sticky,让系统重启服务
        return StartCommandResult.Sticky;
    }

    public async Task ScanWifiNetworks(CancellationToken token)
    {
        if (Device.RuntimePlatform != Device.Android)
            throw new NotSupportedException("此功能仅支持Android设备。");

        var wifiManager = (WifiManager)Android.App.Application.Context.GetSystemService(Context.WifiService);
        if (!wifiManager.IsWifiEnabled)
        {
            wifiManager.SetWifiEnabled(true);
            await Task.Delay(2000, token);
        }

        var tcs = new TaskCompletionSource<IList<ScanResult>>();
        var wifiScanReceiver = new WifiScanReceiver(wifiManager, tcs);
        var intentFilter = new IntentFilter(WifiManager.ScanResultsAvailableAction);

        try
        {
            Android.App.Application.Context.RegisterReceiver(wifiScanReceiver, intentFilter);
            wifiManager.StartScan();

            // 等待扫描结果,超时时间设为10秒
            var scanResults = await Task.WhenAny(tcs.Task, Task.Delay(10000, token)).Unwrap();

            var database = new Database();
            bool found = scanResults.Any(r => r.Ssid == "AndroidWifi");

            MessItem nuovoGeoItem = new MessItem
            {
                Data = DateTime.Now,
                Descrizione = found ? "进入" : "离开"
            };
            int esito = await database.AggiungiGeoItem(nuovoGeoItem);
        }
        finally
        {
            try
            {
                Android.App.Application.Context.UnregisterReceiver(wifiScanReceiver);
            }
            catch
            {
                // 忽略注销失败的情况
            }
        }
    }

    class WifiScanReceiver : BroadcastReceiver
    {
        private readonly WifiManager _wifiManager;
        private readonly TaskCompletionSource<IList<ScanResult>> _tcs;

        public WifiScanReceiver(WifiManager wifiManager, TaskCompletionSource<IList<ScanResult>> tcs)
        {
            _wifiManager = wifiManager;
            _tcs = tcs;
        }

        public override void OnReceive(Context context, Intent intent)
        {
            if (intent.Action == WifiManager.ScanResultsAvailableAction && !_tcs.Task.IsCompleted)
            {
                var results = _wifiManager.ScanResults;
                _tcs.SetResult(results.ToList());
            }
        }
    }

    public void Start()
    {
        Intent startService = new Intent(MainActivity.ActivityCurrent, typeof(DemoServices));
        startService.SetAction("START_SERVICE");

        // 适配Android 8.0+的前台服务启动方式
        if (Build.VERSION.SdkInt >= BuildVersionCodes.O)
        {
            MainActivity.ActivityCurrent.StartForegroundService(startService);
        }
        else
        {
            MainActivity.ActivityCurrent.StartService(startService);
        }
    }

    public void Stop()
    {
        Intent stopIntent = new Intent(MainActivity.ActivityCurrent, this.Class);
        stopIntent.SetAction("STOP_SERVICE");
        MainActivity.ActivityCurrent.StartService(stopIntent);
    }

    public override void OnDestroy()
    {
        cancellationTokenSource?.Cancel();
        isScanning = false;
        base.OnDestroy();
    }

    private void RegisterNotification()
    {
        NotificationChannel channel = new NotificationChannel("ServicioChannel", "服务演示", NotificationImportance.Max);
        NotificationManager manager = (NotificationManager)GetSystemService(Context.NotificationService);
        manager.CreateNotificationChannel(channel);

        Notification notification = new Notification.Builder(this, "ServicioChannel")
            .SetContentTitle("服务活跃中")
            .SetSmallIcon(Resource.Drawable.abc_ab_share_pack_mtrl_alpha)
            .SetOngoing(true)
            .Build();

        StartForeground(100, notification);
    }
}

额外注意事项

  • Android 10+对WiFi扫描频率有限制,短时间内多次扫描会被系统限制,所以2分钟的间隔是合理的,不要设置过短。
  • 测试时不要通过开发者选项的"停止应用"来关闭APP,这种方式会直接杀死进程,正常用户通过最近任务列表关闭APP,前台服务应该能继续运行。
  • 确保MainActivity.ActivityCurrent是正确的当前Activity引用,避免空引用异常。

内容的提问来源于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 15:20:55