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

如何让Xamarin应用在设备重启/关闭或应用关闭后持续运行任务?

跨平台定时任务解决方案(Xamarin Android + iOS)

核心思路

放弃纯.NET的System.Timers.Timer,分别调用Android和iOS的原生后台定时任务API,在共享项目中通过**依赖服务(Dependency Service)**封装统一接口,实现跨平台兼容。


Android 端实现(使用AlarmManager)

Android 推荐用AlarmManager实现系统级定时任务,即使应用被杀死或设备重启后也能触发,步骤如下:

  1. 创建广播接收器,用于接收定时触发的广播并执行语音播报逻辑:
[BroadcastReceiver(Enabled = true, Exported = false)]
[IntentFilter(new[] { "com.yourapp.ACTION_SCHEDULE_TASK" })]
public class ScheduleTaskReceiver : BroadcastReceiver
{
    public override void OnReceive(Context context, Intent intent)
    {
        // 执行语音播报逻辑
        var speechManager = DependencyService.Get<ISpeechService>();
        speechManager.Speak("定时播报内容");
    }
}
  1. 创建依赖服务实现类,封装AlarmManager调度逻辑,同时处理设备重启后的任务恢复:
[assembly: Dependency(typeof(AndroidScheduleService))]
namespace YourApp.Droid.Services
{
    public class AndroidScheduleService : IScheduleService
    {
        public void ScheduleTask(DateTime triggerTime)
        {
            var alarmManager = (AlarmManager)Android.App.Application.Context.GetSystemService(Context.AlarmService);
            var intent = new Intent("com.yourapp.ACTION_SCHEDULE_TASK");
            var pendingIntent = PendingIntent.GetBroadcast(Android.App.Application.Context, 0, intent, PendingIntentFlags.UpdateCurrent | PendingIntentFlags.Immutable);

            // 转换为毫秒级时间戳
            var triggerAtMillis = (long)(triggerTime - new DateTime(1970, 1, 1)).TotalMilliseconds;
            // 使用精确闹钟(Android 12+ 需要SCHEDULE_EXACT_ALARM权限)
            alarmManager.SetExactAndAllowWhileIdle(AlarmType.RtcWakeup, triggerAtMillis, pendingIntent);
        }

        public void RegisterBootReceiver()
        {
            // 注册开机广播接收器,重启后恢复任务
            var filter = new IntentFilter(Intent.ActionBootCompleted);
            Android.App.Application.Context.RegisterReceiver(new BootCompletedReceiver(), filter);
        }
    }

    [BroadcastReceiver(Enabled = true, Exported = true)]
    [IntentFilter(new[] { Intent.ActionBootCompleted })]
    public class BootCompletedReceiver : BroadcastReceiver
    {
        public override void OnReceive(Context context, Intent intent)
        {
            // 从本地存储读取保存的定时任务,重新调度
            var savedTasks = LoadSavedTasks();
            foreach(var task in savedTasks)
            {
                var scheduleService = DependencyService.Get<IScheduleService>();
                scheduleService.ScheduleTask(task.TriggerTime);
            }
        }
    }
}
  1. 配置权限:在AndroidManifest.xml中添加必要权限:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />

注意:Android 12及以上版本需要动态申请SCHEDULE_EXACT_ALARM权限,用户拒绝后只能使用非精确闹钟。


iOS 端实现(使用UNUserNotificationCenter + Background Tasks)

iOS 后台限制严格,需结合本地通知和后台任务实现,步骤如下:

  1. 创建依赖服务实现类,使用UNUserNotificationCenter调度本地通知:
[assembly: Dependency(typeof(IosScheduleService))]
namespace YourApp.iOS.Services
{
    public class IosScheduleService : IScheduleService
    {
        public void ScheduleTask(DateTime triggerTime)
        {
            var content = new UNMutableNotificationContent();
            content.Title = "定时播报";
            content.Body = "即将开始语音播报";
            content.Sound = UNNotificationSound.Default;
            // 添加自定义标识区分任务
            content.UserInfo = new NSDictionary("taskId", "voice_schedule_task");

            // 转换为NSDate
            var triggerDate = (NSDate)triggerTime;
            var trigger = UNCalendarNotificationTrigger.CreateTrigger(
                new NSDateComponents
                {
                    Year = triggerDate.Year,
                    Month = triggerDate.Month,
                    Day = triggerDate.Day,
                    Hour = triggerDate.Hour,
                    Minute = triggerDate.Minute,
                    Second = triggerDate.Second
                },
                repeats: false);

            var request = UNNotificationRequest.FromIdentifier("voice_schedule_request", content, trigger);
            UNUserNotificationCenter.Current.AddNotificationRequest(request, (error) =>
            {
                if (error != null)
                {
                    // 处理调度错误
                }
            });
        }

        // 在AppDelegate中注册通知回调
        public static void SetupNotificationHandler()
        {
            UNUserNotificationCenter.Current.Delegate = new NotificationDelegate();
        }
    }

    public class NotificationDelegate : UNUserNotificationCenterDelegate
    {
        public override void DidReceiveNotificationResponse(UNUserNotificationCenter center, UNNotificationResponse response, Action completionHandler)
        {
            if (response.Notification.Request.Content.UserInfo["taskId"].ToString() == "voice_schedule_task")
            {
                // 执行语音播报逻辑
                var speechManager = DependencyService.Get<ISpeechService>();
                speechManager.Speak("定时播报内容");
            }
            completionHandler();
        }

        // 前台收到通知时执行播报
        public override void WillPresentNotification(UNUserNotificationCenter center, UNNotification notification, Action<UNNotificationPresentationOptions> completionHandler)
        {
            if (notification.Request.Content.UserInfo["taskId"].ToString() == "voice_schedule_task")
            {
                var speechManager = DependencyService.Get<ISpeechService>();
                speechManager.Speak("定时播报内容");
            }
            completionHandler(UNNotificationPresentationOptions.Sound | UNNotificationPresentationOptions.Alert);
        }
    }
}
  1. 配置后台权限:在Info.plist中添加后台模式和通知权限:
<key>UIBackgroundModes</key>
<array>
    <string>remote-notification</string>
    <string>audio</string> <!-- 需要后台播放音频时添加 -->
</array>
<key>NSUserNotificationUsageDescription</key>
<string>需要使用通知触发定时语音播报</string>

注意:iOS 若应用被用户强制关闭,本地通知仍会触发,但播报可能受限于后台音频权限,需确保权限已申请。


共享项目封装统一接口

在共享项目中定义接口,通过依赖服务调用各平台实现:

public interface IScheduleService
{
    void ScheduleTask(DateTime triggerTime);
}

// 调用示例
var scheduleService = DependencyService.Get<IScheduleService>();
scheduleService.ScheduleTask(DateTime.Now.AddMinutes(30));

同时需将定时任务信息保存到本地存储(如SQLite、Preferences),设备重启或应用重启后恢复任务。


内容的提问来源于stack exchange,提问作者Noé Sánchez

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 10:53:12