Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
157 views
in Technique[技术] by (71.8m points)

c# - How can I properly extend the background time of an iOS app so that an HTTP request doesn't get cancelled?

I have an app (App1) that makes use of the WKWebView for a good portion of the UI. There is a scenario where an HTTP PUT request is sent from the WKWebView to a backend server to save some data. For this save operation to complete, the server will need approval thru another app (App2). The user would normally switch to App2 to approve, then switch back to App1 to see the result of the save. The problem is that when App1 gets backgrounded, it can cause the response to the save request to be cancelled, even though the save was completely successful on the backend server. There isn't any errors actually logged, but I'm fairly certain it is happening because iOS is killing the connection when the app gets suspended after it gets backgrounded. I'm basing my thoughts on this discussion.

Since the time it takes to approve the save on App2 isn't that long, I figured I could just try to extend the background time of App1, and it appears to work in the times I've tested it.

However, I want to know if this is really the best strategy, and if so, are there any recommendations on my code (For example, should I move the BeginBackgroundTask inside of the Task.Run):

I used these microsoft docs as an example.

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;
}
question from:https://stackoverflow.com/questions/65928807/how-can-i-properly-extend-the-background-time-of-an-ios-app-so-that-an-http-requ

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The following code snippet demonstrates registering a task to run in the background:

nint taskID = UIApplication.SharedApplication.BeginBackgroundTask( () => {});

//runs on main or background thread
FinishLongRunningTask(taskID);

UIApplication.SharedApplication.EndBackgroundTask(taskID);

The registration process pairs a task with a unique identifier, taskID, and then wraps it in matching BeginBackgroundTask and EndBackgroundTask calls. To generate the identifier, we make a call to the BeginBackgroundTask method on the UIApplication object, and then start the long-running task, usually on a new thread. When the task is complete, we call EndBackgroundTask and pass in the same identifier. This is important because iOS will terminate the application if a BeginBackgroundTask call does not have a matching EndBackgroundTask.

Note: If you want to perform Tasks During DidEnterBackground method, these tasks must be invoked on a separate thread. Therefore, sample project uses Task to invoke FinishLongRunningTask.

Task.Factory.StartNew(() => FinishLongRunningTask(taskID));

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...