Some issues and questions regarding the use of the BGContinuedProcessingTask API

Hi, I have been recently debugging the BGContinuedProcessingTask API and encountered some of the following issues. I hope you can provide some answers: First, let me explain my understanding of this API. I believe its purpose is to allow an app to trigger tasks that can be represented with progress indicators and require a certain amount of time to complete. After entering the background, these tasks can continue to be completed through the BGContinuedProcessingTask, preventing the system from terminating them before they are finished.

In the launchHandler of the registration process, we only need to do a few things:

  1. Determine whether the actual business processing is still ongoing.
  2. Update the progress, title, and subtitle.
  3. Handle the expirationHandler.
  4. Set the task as completed.

Here are some issues I encountered during my debugging process:

  1. After I called register and submit, the BGContinuedProcessingTask could not be triggered. The return values from my API calls were all normal.

I tried different device models, and some could trigger the task normally, such as the 15 Pro Max and 12 Pro Max. However, there were also some models, such as the 17 Pro, 15 Pro, and 15, that could not trigger the task properly. Moreover, there was no additional error information to help locate the issue.

  1. The background task failed unexpectedly, but my app was still running normally. As I mentioned above, my launchHandler only retrieves the actual business status and updates it.

If a background task fails unexpectedly while the app is still running normally, it can mislead users and degrade the user experience of the app.

  1. Others have also mentioned the issue of inconsistent behavior on devices that do not support Dynamic Island. On devices that support Dynamic Island,

when a task is triggered in the foreground, the app does not immediately display a pop-up notification within the app. However, on devices that do not support Dynamic Island, the app directly displays a pop-up notification within the app, and this notification does not disappear when switching between different screens within the same app. The user needs to actively swipe up to dismiss it. I think this experience is too intrusive for users. I would like to know whether this will be maintained in the future or if there is a plan to fix it.

  1. On devices that do not support Dynamic Island, using the beta version 26.1 of the system,

if the system is in dark mode but the app triggers a business interface in white, the pop-up notification will have the same color as the current page, making it difficult to read the content inside the pop-up.

  1. Users can actively stop background tasks by using the stop button, or the system can also stop tasks automatically when resources are insufficient or when a task is abnormal.

However, according to the current API, all these actions are triggered through the expirationHandler. Currently, there is no way to distinguish whether the task was stopped by the user, by the system due to resource insufficiency, or due to an abnormal task. I would like to know whether there will be more information provided in the future to help distinguish these different scenarios.

I believe that the user experience issues mentioned in points 2 and 3 are the most important. Please help to answer the questions and concerns above. Thank you!

Answered by DTS Engineer in 865210022

First, let me explain my understanding of this API. I believe its purpose is to allow an app to trigger tasks that can be represented with progress indicators and require a certain amount of time to complete.

I put things much more simply than that and say that the goal is simply to provide an API that gives apps an extended period of time to complete user-critical work after they enter the background. The progress requirement exists as a practical UI compromise so that the user can see "something" and the system has some assurance that the app is still functioning.

I'd also push back on the "trigger tasks" part of this. Nothing requires your app to actually "bind" its activity to the continuing task and, in fact, I think there are many situations where your app should simply "start the work" immediately, with the continuing task acting as a "backup" in case your app is sent to the foreground. See this forum thread for an extended discussion of this.

  1. After I called register and submit, the BGContinuedProcessingTask could not be triggered. The return values from my API calls were all normal.

If you're able to reliably reproduce this, then please file a bug on this and post the bug number back here. In general, I'd expect task failure or expiration to be a rare/unusual edge case and not something the foreground app should regularly experience*.

*One notable exception to that would be if you're specifically starting "lots" of tasks. There is a limit to the number of tasks the system will run and you could hit that limit if you're throwing out "enough" tasks. However, this is easy to avoid by either consolidating your work into fewer tasks or by changing your strategy to BGContinuedProcessingTaskRequest.SubmissionStrategy.queue.

I tried different device models, and some could trigger the task normally, such as the 15 Pro Max and 12 Pro Max. However, there were also some models, such as the 17 Pro, 15 Pro, and 15, that could not trigger the task properly. Moreover, there was no additional error information to help locate the issue.

Interesting. I'd liked to get a bug with a sysdiagnose so we can figure out why this is happening.

However, on devices that do not support Dynamic Island, the app directly displays a pop-up notification within the app, and this notification does not disappear when switching between different screens within the same app. The user needs to actively swipe up to dismiss it. I think this experience is too intrusive for users. I would like to know whether this will be maintained in the future or if there is a plan to fix it.

I can't talk about any of our future plans, but if you don't like the behavior of one of our APIs, then please file bugs. If you post the bug number back here, I'll make sure the bug gets to the right place.

If the system is in dark mode but the app triggers a business interface in white, the pop-up notification will have the same color as the current page, making it difficult to read the content inside the pop-up.

This is definitely a bug but, as noted below, I think it's already been addressed.

Currently, there is no way to distinguish whether the task was stopped by the user, by the system due to resource insufficiency, or due to an abnormal task. I would like to know whether there will be more information provided in the future to help distinguish these different scenarios.

This is a serious issue I hadn't considered. Again, please file a bug and post the bug number back here!

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

I hope that some developers can answer the questions above. This interface was designed with the expectation of enhancing app experience. However, there are still some issues that need to be optimized.

I tried different device models, and some could trigger the task normally, such as the 15 Pro Max and 12 Pro Max. However, there were also some models, such as the 17 Pro, 15 Pro, and 15, that could not trigger the task properly. Moreover, there was no additional error information to help locate the issue.

I assume you're doing this on device and not the simulator, right? And did you check the Console logs to see if an error was reported there? (look for the dasd process)

I also just wanted to reiterate your other points about the BGContinuedProcessingTask API, in case someone from Apple is listening:

  1. I agree that the experience on non-Dynamic Island devices is not great. The task notification banner thing is a obtrusive and redundant. My app already displays a progress bar, so displaying another progress indicator is redundant. Moreover, the banner obscures my app's UI and does not disappear automatically like normal notifications. This leaves the user uncertain if they can safely dismiss it, or if dismissing it will cancel the task. The banner is important to make the user aware that a background task is running, but it should only appear if/when the user backgrounds the app – that's when it becomes relevant.

  2. Likewise, I've also noticed that the banner text is sometimes the wrong color – sometimes black text in dark mode, or white text in light mode. But I haven't been able to reproduce it consistently.

  3. I totally agree that the API is missing a distinction between (1) the user has stopped the task and (2) the system wants to stop the task. In the case of (1), I want to completely cancel the task. In the case of (2), I want to put the task into a paused state until the user is ready to resume it. Ideally, the UI should inform the user that the task has been paused.

Likewise, I've also noticed that the banner text is sometimes the wrong color – sometimes black text in dark mode, or white text in light mode. But I haven't been able to reproduce it consistently.

52/1000

This occurs on non-Dynamic Island devices, in dark mode, and when there is only one background task. However, the latest version of 26.1 Beta has been fixed.

The background task failed unexpectedly, but my app was still running normally. As I mentioned above, my launchHandler only retrieves the actual business status and updates it.If a background task fails unexpectedly while the app is still running normally, it can mislead users and degrade the user experience of the app.

Have you ever encountered this problem?

First, let me explain my understanding of this API. I believe its purpose is to allow an app to trigger tasks that can be represented with progress indicators and require a certain amount of time to complete.

I put things much more simply than that and say that the goal is simply to provide an API that gives apps an extended period of time to complete user-critical work after they enter the background. The progress requirement exists as a practical UI compromise so that the user can see "something" and the system has some assurance that the app is still functioning.

I'd also push back on the "trigger tasks" part of this. Nothing requires your app to actually "bind" its activity to the continuing task and, in fact, I think there are many situations where your app should simply "start the work" immediately, with the continuing task acting as a "backup" in case your app is sent to the foreground. See this forum thread for an extended discussion of this.

  1. After I called register and submit, the BGContinuedProcessingTask could not be triggered. The return values from my API calls were all normal.

If you're able to reliably reproduce this, then please file a bug on this and post the bug number back here. In general, I'd expect task failure or expiration to be a rare/unusual edge case and not something the foreground app should regularly experience*.

*One notable exception to that would be if you're specifically starting "lots" of tasks. There is a limit to the number of tasks the system will run and you could hit that limit if you're throwing out "enough" tasks. However, this is easy to avoid by either consolidating your work into fewer tasks or by changing your strategy to BGContinuedProcessingTaskRequest.SubmissionStrategy.queue.

I tried different device models, and some could trigger the task normally, such as the 15 Pro Max and 12 Pro Max. However, there were also some models, such as the 17 Pro, 15 Pro, and 15, that could not trigger the task properly. Moreover, there was no additional error information to help locate the issue.

Interesting. I'd liked to get a bug with a sysdiagnose so we can figure out why this is happening.

However, on devices that do not support Dynamic Island, the app directly displays a pop-up notification within the app, and this notification does not disappear when switching between different screens within the same app. The user needs to actively swipe up to dismiss it. I think this experience is too intrusive for users. I would like to know whether this will be maintained in the future or if there is a plan to fix it.

I can't talk about any of our future plans, but if you don't like the behavior of one of our APIs, then please file bugs. If you post the bug number back here, I'll make sure the bug gets to the right place.

If the system is in dark mode but the app triggers a business interface in white, the pop-up notification will have the same color as the current page, making it difficult to read the content inside the pop-up.

This is definitely a bug but, as noted below, I think it's already been addressed.

Currently, there is no way to distinguish whether the task was stopped by the user, by the system due to resource insufficiency, or due to an abnormal task. I would like to know whether there will be more information provided in the future to help distinguish these different scenarios.

This is a serious issue I hadn't considered. Again, please file a bug and post the bug number back here!

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

I discussed these issues with the engineering team and have a bit more follow-up:

(1)

Currently, there is no way to distinguish whether the task was stopped by the user, by the system due to resource insufficiency, or due to an abnormal task. I would like to know whether there will be more information provided in the future to help distinguish these different scenarios.

This is a serious issue I hadn't considered.

The engineering team agrees that differentiating between "system expiration" and "user cancellation" is a significant oversight in the current API. I can't comment on future plans/scheduling, but this is something I expect the API to address.

(2)

However, on devices that do not support Dynamic Island, the app directly displays a pop-up notification within the app, and this notification does not disappear when switching between different screens within the same app. The user needs to actively swipe up to dismiss it. I think this experience is too intrusive for users.

Just to clarify, the system should only be showing foreground app UI if tasks are active from other apps on the system. There may be some opportunity to refine that UI, but the fact that this is really about managing the activity of other apps means we do need to present some kind of UI. Also, if you're seeing UI when there are NOT tasks from other apps active, then that's worth filing a bug on.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

The engineering team agrees that differentiating between "system expiration" and "user cancellation" is a significant oversight in the current API. I can't comment on future plans/scheduling, but this is something I expect the API to address.

Thanks, this is good to know!

if you're seeing UI when there are NOT tasks from other apps active, then that's worth filing a bug on.

This is definitely happening to me. The BGContinuedProcessingTask UI (notification banner thing) shows up immediately every time I start such a task, even if there are no other apps running a background task (iPhone 12 mini, running iOS 26.1). I didn't realize that this was not the intended behavior.

It's kinda hard to file a bug because I don't think there's any specific documentation that states that this is not how the API is supposed to work.

This is definitely happening to me. The BGContinuedProcessingTask UI (notification banner thing) shows up immediately every time I start such a task, even if there are no other apps running a background task (iPhone 12 mini, running iOS 26.1). I didn't realize that this was not the intended behavior.

Sure. It doesn't help that we generally avoid documenting the specifics of how this kind of API (where the system is presenting UI that the app doesn't manage) works so that we can be as flexible as possible in evolving our interface. As a long standing example, I don't think the CallKit documentation ever actually says anything about the UI it presents, even though that's basically the entire "point" of the API.

Having said that...

It's kinda hard to file a bug because I don't think there's any specific documentation that states that this is not how the API is supposed to work.

...our intention here doesn't necessarily matter. The fact that the UI isn't working for your use case is worth a bug no matter what.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Some issues and questions regarding the use of the BGContinuedProcessingTask API
 
 
Q