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

如何将Xamarin.Forms函数改为后台运行(支持重启后执行)

解决方案实现

1. 定义任务模型与本地存储(SQLite)

先安装NuGet包:sqlite-net-pcl

任务实体类

using SQLite;

namespace YourAppName.Models
{
    [Table("ScheduledTasks")]
    public class ScheduledTask
    {
        [PrimaryKey, AutoIncrement]
        public int Id { get; set; }
        public string TaskName { get; set; }
        public DateTime ScheduleTime { get; set; }
        public string Message { get; set; } // 要播报的内容
        public bool IsActive { get; set; } = true;
    }
}

任务数据访问层(CRUD)

using SQLite;
using System.Collections.Generic;
using System.Threading.Tasks;
using YourAppName.Models;

namespace YourAppName.Data
{
    public class TaskDatabase
    {
        readonly SQLiteAsyncConnection _database;

        public TaskDatabase(string dbPath)
        {
            _database = new SQLiteAsyncConnection(dbPath);
            _database.CreateTableAsync<ScheduledTask>().Wait();
        }

        // 获取所有活跃任务
        public Task<List<ScheduledTask>> GetTasksAsync()
        {
            return _database.Table<ScheduledTask>().Where(t => t.IsActive).ToListAsync();
        }

        // 获取单个任务
        public Task<ScheduledTask> GetTaskAsync(int id)
        {
            return _database.Table<ScheduledTask>().Where(t => t.Id == id).FirstOrDefaultAsync();
        }

        // 添加/更新任务
        public Task<int> SaveTaskAsync(ScheduledTask task)
        {
            if (task.Id != 0)
            {
                return _database.UpdateAsync(task);
            }
            else
            {
                return _database.InsertAsync(task);
            }
        }

        // 软删除任务(标记为非活跃)
        public Task<int> DeleteTaskAsync(ScheduledTask task)
        {
            task.IsActive = false;
            return _database.UpdateAsync(task);
            // 物理删除用:return _database.DeleteAsync(task);
        }
    }
}

初始化数据库(App.xaml.cs)

using YourAppName.Data;
using Xamarin.Forms;
using System.IO;

namespace YourAppName
{
    public partial class App : Application
    {
        static TaskDatabase _database;

        public static TaskDatabase Database
        {
            get
            {
                if (_database == null)
                {
                    _database = new TaskDatabase(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Tasks.db3"));
                }
                return _database;
            }
        }

        public App()
        {
            InitializeComponent();
            MainPage = new NavigationPage(new Views.TaskListPage());
        }

        protected override async void OnStart()
        {
            // 启动时重新注册所有活跃任务
            var tasks = await App.Database.GetTasksAsync();
            foreach (var task in tasks)
            {
                DependencyService.Get<Services.IScheduledTaskService>().ScheduleTask(task);
            }
        }
    }
}

2. 定义跨平台定时任务服务接口

using YourAppName.Models;

namespace YourAppName.Services
{
    public interface IScheduledTaskService
    {
        // 调度任务
        void ScheduleTask(ScheduledTask task);
        // 取消任务
        void CancelTask(int taskId);
        // 重启后重新注册所有任务
        void ReRegisterAllTasks();
    }
}

3. Android平台实现

权限配置(AndroidManifest.xml)

添加以下权限与组件注册:

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

<receiver android:name=".BootCompletedReceiver" android:enabled="true" android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED" />
        <action android:name="android.intent.action.QUICKBOOT_POWERON" />
    </intent-filter>
</receiver>

<service android:name=".TaskExecutionService" android:foregroundServiceType="mediaPlayback" />
<receiver android:name=".TaskAlarmReceiver" />

BootCompletedReceiver(重启后重新注册任务)

using Android.Content;
using YourAppName.Services;

namespace YourAppName.Droid
{
    [BroadcastReceiver(Enabled = true, Exported = true)]
    [IntentFilter(new[] { Intent.ActionBootCompleted, "android.intent.action.QUICKBOOT_POWERON" })]
    public class BootCompletedReceiver : BroadcastReceiver
    {
        public override async void OnReceive(Context context, Intent intent)
        {
            if (intent.Action == Intent.ActionBootCompleted)
            {
                var taskService = DependencyService.Get<IScheduledTaskService>();
                taskService.ReRegisterAllTasks();
            }
        }
    }
}

TaskAlarmReceiver(接收闹钟触发)

using Android.Content;

namespace YourAppName.Droid
{
    [BroadcastReceiver(Exported = true)]
    public class TaskAlarmReceiver : BroadcastReceiver
    {
        public override void OnReceive(Context context, Intent intent)
        {
            var message = intent.GetStringExtra("Message");
            var taskId = intent.GetIntExtra("TaskId", 0);

            // 启动前台服务执行语音播报
            var serviceIntent = new Intent(context, typeof(TaskExecutionService));
            serviceIntent.PutExtra("Message", message);
            serviceIntent.PutExtra("TaskId", taskId);

            if (Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.O)
            {
                context.StartForegroundService(serviceIntent);
            }
            else
            {
                context.StartService(serviceIntent);
            }
        }
    }
}

TaskExecutionService(前台服务执行语音播报)

using Android.App;
using Android.Content;
using Android.Media;
using Android.OS;
using AndroidX.Core.App;
using YourAppName.Data;
using YourAppName.Models;

namespace YourAppName.Droid
{
    [Service(ForegroundServiceType = Android.Content.PM.ForegroundService.TypeMediaPlayback)]
    public class TaskExecutionService : Service
    {
        private int _notificationId = 1001;

        public override IBinder OnBind(Intent intent)
        {
            return null;
        }

        public override async StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
        {
            var message = intent.GetStringExtra("Message");
            var taskId = intent.GetIntExtra("TaskId", 0);

            // 创建前台通知(Android 8+必须)
            var notificationBuilder = new NotificationCompat.Builder(this, "TaskChannel")
                .SetContentTitle("定时播报")
                .SetContentText(message)
                .SetSmallIcon(Resource.Drawable.ic_notification)
                .SetPriority(NotificationCompat.PriorityDefault);

            // 创建通知渠道(Android 8+)
            if (Build.VERSION.SdkInt >= BuildVersionCodes.O)
            {
                var channel = new NotificationChannel("TaskChannel", "定时任务频道", NotificationImportance.Default);
                channel.Description = "用于定时语音播报的通知渠道";
                var notificationManager = GetSystemService(NotificationService) as NotificationManager;
                notificationManager.CreateNotificationChannel(channel);
            }

            StartForeground(_notificationId, notificationBuilder.Build());

            // 执行语音播报
            var tts = new TextToSpeech(this, status => 
            {
                if (status == OperationResult.Success)
                {
                    tts.Speak(message, QueueMode.Flush, null, null);
                }
            });

            // 播报完成后标记任务为非活跃
            var task = await App.Database.GetTaskAsync(taskId);
            if (task != null)
            {
                task.IsActive = false;
                await App.Database.SaveTaskAsync(task);
            }

            StopForeground(true);
            StopSelf();

            return StartCommandResult.NotSticky;
        }
    }
}

IScheduledTaskService的Android实现

using Android.App;
using Android.Content;
using Android.OS;
using YourAppName.Data;
using YourAppName.Models;
using YourAppName.Services;

namespace YourAppName.Droid.Services
{
    public class ScheduledTaskService : IScheduledTaskService
    {
        public void ScheduleTask(ScheduledTask task)
        {
            var alarmManager = (AlarmManager)Android.App.Application.Context.GetSystemService(Context.AlarmService);
            var intent = new Intent(Android.App.Application.Context, typeof(TaskAlarmReceiver));
            intent.PutExtra("TaskId", task.Id);
            intent.PutExtra("Message", task.Message);

            var pendingIntent = PendingIntent.GetBroadcast(
                Android.App.Application.Context,
                task.Id,
                intent,
                PendingIntentFlags.UpdateCurrent | PendingIntentFlags.Immutable);

            // 计算触发时间的毫秒数
            var triggerTime = (long)(task.ScheduleTime - DateTime.Now).TotalMilliseconds;
            if (triggerTime <= 0) triggerTime = 1000; // 防止立即触发

            if (Build.VERSION.SdkInt >= BuildVersionCodes.M)
            {
                alarmManager.SetExactAndAllowWhileIdle(AlarmType.RtcWakeup, SystemClock.ElapsedRealtime() + triggerTime, pendingIntent);
            }
            else if (Build.VERSION.SdkInt >= BuildVersionCodes.Kitkat)
            {
                alarmManager.SetExact(AlarmType.RtcWakeup, SystemClock.ElapsedRealtime() + triggerTime, pendingIntent);
            }
            else
            {
                alarmManager.Set(AlarmType.RtcWakeup, SystemClock.ElapsedRealtime() + triggerTime, pendingIntent);
            }
        }

        public void CancelTask(int taskId)
        {
            var alarmManager = (AlarmManager)Android.App.Application.Context.GetSystemService(Context.AlarmService);
            var intent = new Intent(Android.App.Application.Context, typeof(TaskAlarmReceiver));
            var pendingIntent = PendingIntent.GetBroadcast(
                Android.App.Application.Context,
                taskId,
                intent,
                PendingIntentFlags.UpdateCurrent | PendingIntentFlags.Immutable);

            alarmManager.Cancel(pendingIntent);
            pendingIntent.Cancel();
        }

        public async void ReRegisterAllTasks()
        {
            var tasks = await App.Database.GetTasksAsync();
            foreach (var task in tasks)
            {
                ScheduleTask(task);
            }
        }
    }
}

4. iOS平台实现

Info.plist配置

添加后台模式与权限:

<key>UIBackgroundModes</key>
<array>
    <string>audio</string>
</array>
<key>NSSpeechRecognitionUsageDescription</key>
<string>需要使用语音播报功能</string>

IScheduledTaskService的iOS实现

using Foundation;
using UserNotifications;
using AVFoundation;
using YourAppName.Data;
using YourAppName.Models;
using YourAppName.Services;

namespace YourAppName.iOS.Services
{
    public class ScheduledTaskService : IScheduledTaskService, IUNUserNotificationCenterDelegate
    {
        public ScheduledTaskService()
        {
            UNUserNotificationCenter.Current.Delegate = this;
            RequestNotificationPermissions();
        }

        private void RequestNotificationPermissions()
        {
            UNUserNotificationCenter.Current.RequestAuthorization(UNAuthorizationOptions.Alert | UNAuthorizationOptions.Sound, (granted, error) =>
            {
                if (granted)
                {
                    UIKit.UIApplication.SharedApplication.RegisterForRemoteNotifications();
                }
            });
        }

        public void ScheduleTask(ScheduledTask task)
        {
            var content = new UNMutableNotificationContent();
            content.Title = "定时播报";
            content.Body = task.Message;
            content.Sound = UNNotificationSound.Default;

            // 计算触发时间(转UTC)
            var triggerDate = new DateTimeOffset(task.ScheduleTime).ToUniversalTime();
            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(task.Id.ToString(), content, trigger);
            UNUserNotificationCenter.Current.AddNotificationRequest(request, (error) =>
            {
                // 可在此处理错误
            });
        }

        public void CancelTask(int taskId)
        {
            UNUserNotificationCenter.Current.RemovePendingNotificationRequests(new string[] { taskId.ToString() });
        }

        public async void ReRegisterAllTasks()
        {
            var tasks = await App.Database.GetTasksAsync();
            foreach (var task in tasks)
            {
                ScheduleTask(task);
            }
        }

        // 前台收到通知时触发播报
        [Export("userNotificationCenter:willPresentNotification:withCompletionHandler:")]
        public void WillPresentNotification(UNUserNotificationCenter center, UNNotification notification, Action<UNNotificationPresentationOptions> completionHandler)
        {
            SpeakMessage(notification.Request.Content.Body);
            completionHandler(UNNotificationPresentationOptions.Alert | UNNotificationPresentationOptions.Sound);
        }

        // 用户点击通知时触发播报
        [Export("userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:")]
        public void DidReceiveNotificationResponse(UNUserNotificationCenter center, UNNotificationResponse response, Action completionHandler)
        {
            SpeakMessage(response.Notification.Request.Content.Body);
            completionHandler();
        }

        private void SpeakMessage(string message)
        {
            var synthesizer = new AVSpeechSynthesizer();
            var utterance = new AVSpeechUtterance(message)
            {
                Voice = AVSpeechSynthesisVoice.FromLanguage("zh-CN"),
                Rate = 0.5f
            };
            synthesizer.SpeakUtterance(utterance);
        }
    }
}

iOS启动注册(AppDelegate.cs)

using Foundation;
using UIKit;
using YourAppName.Services;

namespace YourAppName.iOS
{
    [Register("AppDelegate")]
    public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
    {
        public override bool FinishedLaunching(UIApplication app, NSDictionary options)
        {
            global::Xamarin.Forms.Forms.Init();
            LoadApplication(new App());

            // 注册依赖服务
            DependencyService.Register<IScheduledTaskService, iOS.Services.ScheduledTaskService>();
            // 重启后重新注册任务
            DependencyService.Get<IScheduledTaskService>().ReRegisterAllTasks();

            return base.FinishedLaunching(app, options);
        }
    }
}

5. 视图层实现

TaskListPage.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="YourAppName.Views.TaskListPage"
             Title="定时任务列表">
    <ContentPage.ToolbarItems>
        <ToolbarItem Text="添加" Clicked="AddTask_Clicked"/>
    </ContentPage.ToolbarItems>
    <StackLayout>
        <ListView x:Name="TasksListView" Margin="10">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <StackLayout Orientation="Horizontal" Padding="10">
                            <StackLayout>
                                <Label Text="{Binding TaskName}" FontSize="Medium" FontAttributes="Bold"/>
                                <Label Text="{Binding ScheduleTime, StringFormat='执行时间: {0:yyyy-MM-dd HH:mm:ss}'}" FontSize="Small"/>
                                <Label Text="{Binding Message}" FontSize="Small" TextColor="Gray"/>
                            </StackLayout>
                            <Button Text="删除" Clicked="DeleteTask_Clicked" CommandParameter="{Binding Id}" Margin="10,0"/>
                        </StackLayout>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </StackLayout>
</ContentPage>

TaskListPage.xaml.cs

using YourAppName.Models;
using YourAppName.Services;
using Xamarin.Forms;

namespace YourAppName.Views
{
    public partial class TaskListPage : ContentPage
    {
        public TaskListPage()
        {
            InitializeComponent();
        }

        protected override async void OnAppearing()
        {
            base.OnAppearing();
            var tasks = await App.Database.GetTasksAsync();
            TasksListView.ItemsSource = tasks;
        }

        private async void AddTask_Clicked(object sender, EventArgs e)
        {
            await Navigation.PushAsync(new AddTaskPage());
        }

        private async void DeleteTask_Clicked(object sender, EventArgs e)
        {
            var taskId = (int)((Button)sender).CommandParameter;
            var task = await App.Database.GetTaskAsync(taskId);
相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 06:10:13