问题描述
我有一个应用程序 (App1),它在 UI 的很大一部分中使用了 WKWebView
。有一个场景,HTTP PUT 请求从 WKWebView
发送到后端服务器以保存一些数据。要完成此保存操作,服务器将需要通过另一个应用程序 (App2) 的批准。用户通常会切换到 App2 进行批准,然后切换回 App1 以查看保存结果。问题是当 App1 进入后台时,它会导致对保存请求的响应被取消,即使在后端服务器上保存完全成功。没有实际记录任何错误,但我相当肯定它正在发生,因为当应用程序在后台挂起时,iOS 正在终止连接。我的想法基于 this discussion。
由于批准在 App2 上保存所需的时间并不长,我想我可以尝试延长 App1 的后台时间,它似乎在我测试过的时间有效。
>但是,我想知道这是否真的是最佳策略,如果是,是否对我的代码有任何建议(例如,我是否应该将 BeginBackgroundTask
移到 Task.Run
内) :
我以这些 microsoft docs 为例。
public override async void DidEnterBackground(UIApplication application)
{
ExtendBackgroundTime(application);
}
private nint? webViewBgTaskId = null;
private CancellationTokenSource webViewBgTaskTokenSrc = null;
private void ExtendBackgroundTime(UIApplication application)
{
// cancel the prevIoUs background task that was created in this function
webViewBgTaskTokenSrc?.Cancel();
webViewBgTaskTokenSrc = null;
if (webViewBgTaskId.HasValue)
{
application.EndBackgroundTask(webViewBgTaskId.Value);
webViewBgTaskId = null;
}
var cts = new CancellationTokenSource();
nint taskId = default;
taskId = application.BeginBackgroundTask(() =>
{
cts.Cancel();
webViewBgTaskTokenSrc = null;
application.EndBackgroundTask(taskId);
webViewBgTaskId = null;
});
_ = Task.Run(async () =>
{
// For Now,this is just set to 5 minutes,but in my experience,// the background task will never be allowed to continue for that long.
// It's usually only about 30 seconds as of iOS 13.
// But this at least gives it some finite upper bound.
await Task.Delay(TimeSpan.FromMinutes(5),cts.Token);
application.EndBackgroundTask(taskId);
webViewBgTaskId = null;
},cts.Token);
webViewBgTaskTokenSrc = cts;
webViewBgTaskId = taskId;
}
解决方法
以下代码片段演示了注册要在后台运行的任务:
nint taskID = UIApplication.SharedApplication.BeginBackgroundTask( () => {});
//runs on main or background thread
FinishLongRunningTask(taskID);
UIApplication.SharedApplication.EndBackgroundTask(taskID);
注册过程将任务与唯一标识符 taskID
配对,然后将其包装在匹配的 BeginBackgroundTask
和 EndBackgroundTask
调用中。为了生成标识符,我们调用 UIApplication
对象上的 BeginBackgroundTask 方法,然后启动长时间运行的任务,通常是在一个新线程上。当任务完成时,我们调用 EndBackgroundTask
并传入相同的标识符。这很重要,因为如果 BeginBackgroundTask
调用没有匹配的 EndBackgroundTask
,iOS 将终止应用程序。
注意:如果您想在 DidEnterBackground
方法中执行 Tasks,这些任务必须在单独的线程上调用。因此,示例项目使用 Task 来调用 FinishLongRunningTask
。
Task.Factory.StartNew(() => FinishLongRunningTask(taskID));