Xamarin 表单后台任务仅在应用程序在 ios 上打开时运行 [英] Xamarin forms background tasks run only when app is open on ios

查看:30
本文介绍了Xamarin 表单后台任务仅在应用程序在 ios 上打开时运行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  1. 预期行为
    • ios
      • 当应用最小化并且每 5 秒收到一次通知时.
    • 安卓
      • 当应用最小化并且每 5 秒收到一次通知时.
  2. 实际行为
    • ios
      • 应用会最小化并且不会收到通知,打开应用会导致每 5 秒收到一次通知.
    • 安卓
      • 当应用最小化并且每 5 秒收到一次通知时.<块引用>

        //来自app.xaml.cs受保护的覆盖无效 OnSleep(){void ScheduleNotification(){//启动一个在 5 秒后运行的计时器.Device.StartTimer(TimeSpan.FromSeconds(5), () =>{System.Threading.Tasks.Task.Factory.StartNew(() =>{//执行实际请求并等待它完成.执行通知();//切换回UI线程更新UIDevice.BeginInvokeOnMainThread(() =>{//更新界面//...//现在通过调度新请求来重复调度通知();计数++;});}, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);//不要重复定时器(当请求完成时我们将启动一个新的定时器)返回假;});}无效执行通知(){CrossLocalNotifications.Current.Show("title", "body"+ count.ToString());}调度通知();}

解决方案

在 iOS 上,不要求在后台运行的应用程序不能在后台运行超过 10 秒.为了让一些代码在后台运行,你可以在 iOS 和 android 上实现一个 DependencyService.您可以将以下代码放入 iOS 上的该服务中:

public async Task RunCodeInBackgroundMode(Func action, string name = "MyBackgroundTaskName"){nint taskId = 0;var taskEnded = false;taskId = UIApplication.SharedApplication.BeginBackgroundTask(name, () =>{//当时间到了任务还没有完成时,调用该方法完成任务,防止app被终止Console.WriteLine($"后台任务'{name}'被杀了");任务结束=真;UIApplication.SharedApplication.EndBackgroundTask(taskId);});await Task.Factory.StartNew(async() =>{//这里我们运行实际的任务Console.WriteLine($"后台任务'{name}'已启动");等待动作();任务结束=真;UIApplication.SharedApplication.EndBackgroundTask(taskId);Console.WriteLine($"后台任务'{name}'已完成");});await Task.Factory.StartNew(async () =>{//只是一个记录我们剩余时间的方法.通常一个后台任务有大约 180 秒的时间来完成.while (!taskEnded){Console.WriteLine($"后台任务 '{name}' 剩余时间:{UIApplication.SharedApplication.BackgroundTimeRemaining}");等待 Task.Delay(1000);}});}

在 Android 上,您可以使用以下代码:

public async Task RunCodeInBackgroundMode(Func action, string name = "MyBackgroundTaskName"){var powerManager = (PowerManager)Application.Context.GetSystemService(Context.PowerService);var wakeLock = powerManager.NewWakeLock(WakeLockFlags.Partial,姓名);//获取部分唤醒锁.这可以防止手机在不释放的情况下进入睡眠状态.唤醒锁.获取();var taskEnded = false;await Task.Factory.StartNew(async () =>{//这里我们运行实际的代码Console.WriteLine($"后台任务'{name}'已启动");等待动作();Console.WriteLine($"后台任务'{name}'完成");唤醒锁.释放();任务结束=真;});await Task.Factory.StartNew(async() =>{//只是一种跟踪任务运行时间的方法var 秒表 = 新秒表();秒表.开始();while (!taskEnded){Console.WriteLine($"Background '{name}' task with wakelock is still running ({stopwatch.Elapsed.TotalSeconds} seconds)");等待 Task.Delay(1000);}秒表.停止();});}

在共享项目中,您可以通过以下方式调用这些方法:

var deviceInfoServic = ServiceLocator.Instance.Get();等待 deviceInfoServic.RunCodeInBackgroundMode(async () =>{//你的代码在这里});

  1. Expected behavior
    • ios
      • When the app is minimized and notifications come in every 5 seconds.
    • Android
      • When the app is minimized and notifications come in every 5 seconds.
  2. Actual behavior
    • ios
      • App minimizes and no notifications come in, opening the app causes notifications to come in every 5 seconds.
    • Android
      • When the app is minimized and notifications come in every 5 seconds.

        //from app.xaml.cs
        protected override void OnSleep()
            {
                void ScheduleNotification()
                {
                    // Start a timer that runs after 5 seconds.
                    Device.StartTimer(TimeSpan.FromSeconds(5), () =>
                    {
                        System.Threading.Tasks.Task.Factory.StartNew( () =>
                        {
                            // Do the actual request and wait for it to finish.
                             PerformNotification();
                            // Switch back to the UI thread to update the UI
                            Device.BeginInvokeOnMainThread(() =>
                            {
                                // Update the UI
                                // ...
                                // Now repeat by scheduling a new request
                                ScheduleNotification();
                                count++;
                            });
                        }, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
        
                        // Don't repeat the timer (we will start a new timer when the request is finished)
                        return false;
                    });
                }
               void PerformNotification()
                {
                    CrossLocalNotifications.Current.Show("title", "body"+ count.ToString());
        
                }
                ScheduleNotification();
            }
        

解决方案

On iOS, apps that don't request to be run in the Background, can not run in the Background for longer than 10 seconds. In order to make some code run in the Background you could implement a DependencyService on iOS and on android. You would put the following code inside that service on iOS:

public async Task RunCodeInBackgroundMode(Func<Task> action, string name = "MyBackgroundTaskName")
    {
        nint taskId = 0;
        var taskEnded = false;
        taskId = UIApplication.SharedApplication.BeginBackgroundTask(name, () =>
        {
            //when time is up and task has not finished, call this method to finish the task to prevent the app from being terminated
            Console.WriteLine($"Background task '{name}' got killed");
            taskEnded = true;
            UIApplication.SharedApplication.EndBackgroundTask(taskId);
        });
        await Task.Factory.StartNew(async () =>
        {
            //here we run the actual task
            Console.WriteLine($"Background task '{name}' started");
            await action();
            taskEnded = true;
            UIApplication.SharedApplication.EndBackgroundTask(taskId);
            Console.WriteLine($"Background task '{name}' finished");
        });

        await Task.Factory.StartNew(async () =>
        {
            //Just a method that logs how much time we have remaining. Usually a background task has around 180 seconds to complete. 
            while (!taskEnded)
            {
                Console.WriteLine($"Background task '{name}' time remaining: {UIApplication.SharedApplication.BackgroundTimeRemaining}");
                await Task.Delay(1000);
            }
        });
    }

On Android you could use the following code:

public async Task RunCodeInBackgroundMode(Func<Task> action, string name = "MyBackgroundTaskName")
        {
            var powerManager = (PowerManager)Application.Context.GetSystemService(Context.PowerService);
            var wakeLock = powerManager.NewWakeLock(WakeLockFlags.Partial,
                                                    name);
            //acquire a partial wakelock. This prevents the phone from going to sleep as long as it is not released.
            wakeLock.Acquire();
            var taskEnded = false;

            await Task.Factory.StartNew(async () =>
            {
                //here we run the actual code
                Console.WriteLine($"Background task '{name}' started");
                await action();
                Console.WriteLine($"Background task '{name}' finished");
                wakeLock.Release();
                taskEnded = true;
            });

            await Task.Factory.StartNew(async () =>
            {
                //just a method to keep track of how long the task runs
                var stopwatch = new Stopwatch();
                stopwatch.Start();
                while (!taskEnded)
                {
                    Console.WriteLine($"Background '{name}' task with wakelock still running ({stopwatch.Elapsed.TotalSeconds} seconds)");
                    await Task.Delay(1000);
                }
                stopwatch.Stop();
            });
        }

Inside the shared project, you could call those methods in the following way:

var deviceInfoServic = ServiceLocator.Instance.Get<YourService Interface here>();
await deviceInfoServic.RunCodeInBackgroundMode(async () =>
{
    //your code here
});

这篇关于Xamarin 表单后台任务仅在应用程序在 ios 上打开时运行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆