Android API33下.NET MAUI前台服务仍休眠的解决方法问询
Android API 33下.NET MAUI前台服务持续运行解决方案
确保前台服务的通知符合API 33要求
API 33对前台服务的通知规则卡得很严,必须提前创建合法的通知渠道,且通知优先级不能设为最低。在Android项目里初始化通知渠道的代码可以这么写:if (Build.VERSION.SdkInt >= BuildVersionCodes.O) { var channel = new NotificationChannel("foreground_service_channel", "前台服务通知", NotificationImportance.Default) { Description = "用于保持服务持续运行的通知" }; var notificationManager = (NotificationManager)GetSystemService(NotificationService); notificationManager.CreateNotificationChannel(channel); }启动前台服务时,通知必须包含可见的文字内容,不能只放个图标——系统会把无意义的通知判定为无效,直接停掉服务。
加个唤醒锁防止CPU休眠
前台服务本身自带部分唤醒机制,但保险起见可以额外申请PARTIAL_WAKE_LOCK锁,避免CPU进入休眠状态。首先要在AndroidManifest.xml里加权限:<uses-permission android:name="android.permission.WAKE_LOCK" />然后在服务的生命周期里获取和释放锁:
private PowerManager.WakeLock _wakeLock; public override void OnCreate() { base.OnCreate(); var powerManager = (PowerManager)GetSystemService(PowerService); _wakeLock = powerManager.NewWakeLock(WakeLockFlags.Partial, "MyApp:ForegroundWakeLock"); _wakeLock.Acquire(); } public override void OnDestroy() { _wakeLock?.Release(); base.OnDestroy(); }主动引导用户确认电池优化豁免
有些厂商的系统会无视手动设置的电池优化选项,你可以通过代码跳转到应用的电池优化设置页面,让用户手动确认豁免:var intent = new Intent(); var packageName = PackageName; var pm = (PackageManager)GetSystemService(PackageService); if (Build.VERSION.SdkInt >= BuildVersionCodes.M) { if (!pm.IsIgnoringBatteryOptimizations(packageName)) { intent.SetAction(Android.Provider.Settings.ActionRequestIgnoreBatteryOptimizations); intent.SetData(Android.Net.Uri.Parse($"package:{packageName}")); StartActivity(intent); } }注意:这个操作需要申请
REQUEST_IGNORE_BATTERY_OPTIMIZATIONS权限,但Google Play对这个权限的审核很严,如果你的应用不是导航、健康监测这类必须后台持续运行的场景,可能过不了审。搞定厂商定制系统的后台限制
国内小米、华为、OPPO、vivo这些厂商都有自己的后台管理逻辑,光靠系统默认设置没用,得引导用户开自启动和后台权限:- 小米:设置→应用设置→应用管理→找到你的应用→权限管理→自启动→允许;后台设置→无限制
- 华为:设置→应用和服务→应用管理→你的应用→权限管理→自启动→允许;电池→应用启动管理→关闭自动管理,手动开允许后台活动
- OPPO:设置→应用→应用管理→你的应用→权限管理→自启动→允许;电池→应用耗电管理→你的应用→允许后台耗电
- vivo:设置→应用与权限→应用管理→你的应用→权限管理→自启动→允许;电池→后台高耗电→允许你的应用后台高耗电
可以在应用里加个引导页,根据设备品牌跳对应设置页面,或者直接给用户写清楚操作步骤。
用WorkManager做兜底检查(慎用)
如果以上方法都不管用,可以用WorkManager做个周期性任务,每隔十几分钟检查前台服务是否还在运行,停了就重启。但这种方法容易被系统判定为恶意保活,非必要别用:// 创建周期性检查任务 var constraints = new Constraints.Builder() .SetRequiresBatteryNotLow(false) .Build(); var workRequest = PeriodicWorkRequest.Builder.From<ServiceCheckWorker>(TimeSpan.FromMinutes(15)) .SetConstraints(constraints) .Build(); WorkManager.Instance.EnqueueUniquePeriodicWork("ServiceCheck", ExistingPeriodicWorkPolicy.Replace, workRequest);然后实现Worker类的检查逻辑:
public class ServiceCheckWorker : Worker { public ServiceCheckWorker(Context context, WorkerParameters workerParams) : base(context, workerParams) { } public override Result DoWork() { if (!IsServiceRunning(typeof(MyForegroundService))) { var intent = new Intent(Context, typeof(MyForegroundService)); Context.StartForegroundService(intent); } return Result.Success(); } private bool IsServiceRunning(Type serviceType) { var activityManager = (ActivityManager)Context.GetSystemService(Context.ActivityService); foreach (var service in activityManager.GetRunningServices(int.MaxValue)) { if (service.Service.ClassName.Equals(serviceType.FullName)) { return true; } } return false; } }
内容的提问来源于stack exchange,提问作者Netricity
相关产品推荐
相关产品推荐

