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

求助:如何每日18:30执行后台任务?Xamarin本地通知后台不生效

解决Xamarin中应用未运行时每日本地通知不生效的问题

首先,咱们得明确核心问题:Android 8.0+对后台任务有严格的限制,普通的AlarmManager或者仅在应用运行时触发的逻辑,在应用被杀或未启动时会失效。要实现无论应用是否运行都能每日18:30触发通知,推荐使用Google官方的WorkManager(最可靠),或者调整AlarmManager的使用方式来适配后台限制。


方案一:使用WorkManager(推荐)

WorkManager是专门为需要保证执行的后台任务设计的,即使应用未运行、设备重启,它也会在合适的时机触发任务,完美适配Android的后台限制。

步骤1:创建Worker类

这个类负责执行发送通知的逻辑:

using Android.App;
using Android.Content;
using Android.OS;
using AndroidX.Core.App;
using AndroidX.Work;

public class DailyNotificationWorker : Worker
{
    public DailyNotificationWorker(Context context, WorkerParameters workerParams) 
        : base(context, workerParams) { }

    public override Result DoWork()
    {
        SendDailyNotification();
        return Result.Success;
    }

    private void SendDailyNotification()
    {
        const string channelId = "daily_reminder_channel";
        var notificationManager = NotificationManagerCompat.From(ApplicationContext);

        // Android 8.0+必须创建通知渠道
        if (Build.VERSION.SdkInt >= BuildVersionCodes.O)
        {
            var channel = new NotificationChannel(
                channelId, 
                "每日提醒", 
                NotificationImportance.Default)
            {
                Description = "每日18:30自动发送的通知"
            };
            notificationManager.CreateNotificationChannel(channel);
        }

        // 点击通知打开主页面
        var launchIntent = ApplicationContext.PackageManager.GetLaunchIntentForPackage(ApplicationContext.PackageName);
        var pendingIntent = PendingIntent.GetActivity(
            ApplicationContext, 
            0, 
            launchIntent, 
            PendingIntentFlags.UpdateCurrent | PendingIntentFlags.Immutable);

        // 构建通知
        var notification = new NotificationCompat.Builder(ApplicationContext, channelId)
            .SetSmallIcon(Resource.Drawable.ic_notification) // 替换成你的图标
            .SetContentTitle("每日提醒")
            .SetContentText("这是你设置的每日18:30通知")
            .SetPriority(NotificationCompat.PriorityDefault)
            .SetContentIntent(pendingIntent)
            .SetAutoCancel(true)
            .Build();

        notificationManager.Notify(1001, notification);
    }
}

步骤2:调度每日18:30的任务

在你的主Activity或者启动页中,添加调度逻辑,计算首次执行的延迟时间,然后设置周期性任务:

using AndroidX.Work;

private void ScheduleDailyNotificationTask()
{
    var now = DateTime.Now;
    var targetTime = new DateTime(now.Year, now.Month, now.Day, 18, 30, 0);
    
    // 如果当前时间已过18:30,就把目标时间设为明天的18:30
    if (now > targetTime)
    {
        targetTime = targetTime.AddDays(1);
    }
    
    // 计算从现在到目标时间的延迟
    var initialDelay = targetTime - now;

    // 创建周期性工作请求:每隔24小时重复一次,首次延迟initialDelay
    var workRequest = new PeriodicWorkRequest.Builder(
            typeof(DailyNotificationWorker), 
            TimeSpan.FromHours(24))
        .SetInitialDelay(initialDelay)
        .Build();

    // 唯一任务:如果已有相同任务,替换掉旧的
    WorkManager.Instance.EnqueueUniquePeriodicWork(
        "DailyNotificationTask",
        ExistingPeriodicWorkPolicy.Replace,
        workRequest);
}

步骤3:处理通知权限(Android 13+)

Android 13及以上需要主动请求POST_NOTIFICATIONS权限,在主Activity的OnCreate中添加:

using Android.Content.PM;
using AndroidX.Core.App;
using AndroidX.Core.Content;

protected override void OnCreate(Bundle savedInstanceState)
{
    base.OnCreate(savedInstanceState);
    
    // 请求通知权限
    if (Build.VERSION.SdkInt >= BuildVersionCodes.Tiramisu)
    {
        if (ContextCompat.CheckSelfPermission(this, Manifest.Permission.PostNotifications) != Permission.Granted)
        {
            ActivityCompat.RequestPermissions(this, new[] { Manifest.Permission.PostNotifications }, 1002);
        }
    }

    // 调度任务
    ScheduleDailyNotificationTask();
}

方案二:使用AlarmManager(兼容旧版本)

如果你坚持用AlarmManager,需要解决两个核心问题:静态注册广播接收器和使用精确闹钟适配后台限制。

步骤1:静态注册广播接收器

在AndroidManifest.xml中注册接收器(应用未运行时只有静态注册的接收器能被唤醒):

<receiver 
    android:name=".NotificationAlarmReceiver" 
    android:exported="false">
    <intent-filter>
        <action android:name="com.yourpackage.action.DAILY_NOTIFICATION" />
    </intent-filter>
</receiver>

步骤2:实现广播接收器

在接收器中发送通知,并重新设置下一次的闹钟(因为Android 7.0+不支持精确重复闹钟):

using Android.App;
using Android.Content;
using AndroidX.Core.App;

[BroadcastReceiver(Enabled = true)]
public class NotificationAlarmReceiver : BroadcastReceiver
{
    public override void OnReceive(Context context, Intent intent)
    {
        // 发送通知
        SendNotification(context);
        // 重新设置下一次的闹钟
        SetNextDailyAlarm(context);
    }

    private void SendNotification(Context context)
    {
        // 这里的逻辑和WorkManager中的SendDailyNotification一致,直接复用即可
        const string channelId = "daily_reminder_channel";
        var notificationManager = NotificationManagerCompat.From(context);

        if (Build.VERSION.SdkInt >= BuildVersionCodes.O)
        {
            var channel = new NotificationChannel(channelId, "每日提醒", NotificationImportance.Default)
            {
                Description = "每日18:30自动发送的通知"
            };
            notificationManager.CreateNotificationChannel(channel);
        }

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

        var notification = new NotificationCompat.Builder(context, channelId)
            .SetSmallIcon(Resource.Drawable.ic_notification)
            .SetContentTitle("每日提醒")
            .SetContentText("这是你设置的每日18:30通知")
            .SetPriority(NotificationCompat.PriorityDefault)
            .SetContentIntent(pendingIntent)
            .SetAutoCancel(true)
            .Build();

        notificationManager.Notify(1001, notification);
    }

    private void SetNextDailyAlarm(Context context)
    {
        var alarmManager = (AlarmManager)context.GetSystemService(Context.AlarmService);
        var intent = new Intent(context, typeof(NotificationAlarmReceiver));
        intent.SetAction("com.yourpackage.action.DAILY_NOTIFICATION");
        var pendingIntent = PendingIntent.GetBroadcast(context, 0, intent, PendingIntentFlags.UpdateCurrent | PendingIntentFlags.Immutable);

        var now = DateTime.Now;
        var targetTime = new DateTime(now.Year, now.Month, now.Day, 18, 30, 0).AddDays(1);
        var targetMillis = (long)(targetTime - new DateTime(1970, 1, 1)).TotalMilliseconds;

        // Android 6.0+使用setExactAndAllowWhileIdle,保证在Doze模式下也能触发
        if (Build.VERSION.SdkInt >= BuildVersionCodes.M)
        {
            alarmManager.SetExactAndAllowWhileIdle(AlarmType.RtcWakeup, targetMillis, pendingIntent);
        }
        else
        {
            alarmManager.SetExact(AlarmType.RtcWakeup, targetMillis, pendingIntent);
        }
    }
}

步骤3:初始化首次闹钟

在主Activity的OnCreate中调用初始化方法:

private void InitializeDailyAlarm()
{
    var alarmManager = (AlarmManager)GetSystemService(AlarmService);
    var intent = new Intent(this, typeof(NotificationAlarmReceiver));
    intent.SetAction("com.yourpackage.action.DAILY_NOTIFICATION");
    var pendingIntent = PendingIntent.GetBroadcast(this, 0, intent, PendingIntentFlags.UpdateCurrent | PendingIntentFlags.Immutable);

    var now = DateTime.Now;
    var targetTime = new DateTime(now.Year, now.Month, now.Day, 18, 30, 0);
    if (now > targetTime)
    {
        targetTime = targetTime.AddDays(1);
    }
    var targetMillis = (long)(targetTime - new DateTime(1970, 1, 1)).TotalMilliseconds;

    if (Build.VERSION.SdkInt >= BuildVersionCodes.M)
    {
        alarmManager.SetExactAndAllowWhileIdle(AlarmType.RtcWakeup, targetMillis, pendingIntent);
    }
    else
    {
        alarmManager.SetExact(AlarmType.RtcWakeup, targetMillis, pendingIntent);
    }
}

关键注意事项

  1. 应用被强制停止:无论是WorkManager还是AlarmManager,当用户在系统设置中强制停止应用后,所有任务都会被取消,这是Android的系统限制,无法绕过,只能提示用户不要强制停止应用。
  2. Doze模式适配:WorkManager会自动在系统维护窗口执行任务;AlarmManager的setExactAndAllowWhileIdle会在设备空闲时唤醒,但每9分钟只能触发一次,不过每日一次的场景完全不受影响。
  3. 权限声明:确保在AndroidManifest.xml中声明必要的权限(如RECEIVE_BOOT_COMPLETED如果需要开机自启,不过WorkManager已经支持开机自启)。

内容的提问来源于stack exchange,提问作者Aswathi PS

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 08:25:55