Does Mac Catalyst support Background Processing?

I have an app for macOS that is built using Mac Catalyst. I need to perform some background processing. I'm using BGProcessingTaskRequest to schedule the request. I have also integrated CKSyncEngine so I need that to be able to perform its normal background processing.

On iOS, when the user leaves the app, I can see a log message that the request was scheduled and a bit later I see log messages coming from the actual background task code.

On macOS I ran the app from Xcode. I then quit the app (Cmd-q). I can see the log message that the request was scheduled. But the actual task is never run. In my test, I ran my app on a MacBook Pro running macOS 26.0. When I quit the app, I checked the log file in the app sandbox and saw the message that the task was scheduled. About 20 minutes later I closed the lid on the MacBook Pro for the night. I did not power down, it just went to sleep. Roughly 10 hours later I opened the lid on the MacBook Pro, logged in, and checked the log file. It had not been updated since quitting the app. I should also mention that the laptop was not plugged in at all during this period.

My question is, does a Mac Catalyst app support background processing after the user quits the app? If so, how is it enabled?

The documentation for BGProcessingTaskRequest and BGProcessingTask show they are supported under Mac Catalyst, but I couldn't find any documentation in the Background Tasks section that mentioned anything specific to setup for Mac Catalyst.

Running the Settings app and going to General -> Login Items & Extension, I do not see my app under the App Background Activity section. Does it need to be listed there? If so, what steps are needed to get it there?

If this is all documented somewhere, I'd appreciate a link since I was not able to find anything specific to making this work under Mac Catalyst.

Answered by DTS Engineer in 866509022

My question is, does a Mac Catalyst app support background processing after the user quits the app?

No. More specifically, the BackgroundTask framework will not launch your app on macOS, though I believe your tasks may run if your app is running already. The issue here is that because the macOS app model and interface is so different than iOS, the system generally avoids launching apps "automatically" instead of trying to replicate the way iOS works.

Running the Settings app and going to General -> Login Items & Extension, I do not see my app under the App Background Activity section. Does it need to be listed there? If so, what steps are needed to get it there?

Sort of. That UI is tied to macOS APIs/features which can be used to provide somewhat similar functionality; however, this area of the system is so different than iOS that the APIs aren't really direct equivalents.

That leads to here:

If this is all documented somewhere, I'd appreciate a link since I was not able to find anything specific to making this work under Mac Catalyst.

What you're looking for is "SMAppService". That's the high-level API for managing LaunchAgents, which would let you create a helper process that runs in the background and does whatever you want/need.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

My question is, does a Mac Catalyst app support background processing after the user quits the app?

No. More specifically, the BackgroundTask framework will not launch your app on macOS, though I believe your tasks may run if your app is running already. The issue here is that because the macOS app model and interface is so different than iOS, the system generally avoids launching apps "automatically" instead of trying to replicate the way iOS works.

Running the Settings app and going to General -> Login Items & Extension, I do not see my app under the App Background Activity section. Does it need to be listed there? If so, what steps are needed to get it there?

Sort of. That UI is tied to macOS APIs/features which can be used to provide somewhat similar functionality; however, this area of the system is so different than iOS that the APIs aren't really direct equivalents.

That leads to here:

If this is all documented somewhere, I'd appreciate a link since I was not able to find anything specific to making this work under Mac Catalyst.

What you're looking for is "SMAppService". That's the high-level API for managing LaunchAgents, which would let you create a helper process that runs in the background and does whatever you want/need.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

@DTS Engineer I really appreciate the response. Very helpful. After looking into SMAppService, it does seem like a launch agent is most appropriate.

The biggest issue I have now is trying to figure out how to make this work. My app and its needs are very far from simple. I have a very large data model that is stored locally in a SQLite database and the user can optionally choose to sync their data via iCloud (CloudKit).

Trying to figure out how refactor all of the existing code and logic that deals with CKSyncEngine syncing, reading and writing the SQLite database, and updating the in-memory data model into the launch agent, all in a way that can be coordinated with the main GUI app (when it might happen to be running), it going to be, shall I say, challenging.

Oh, and doing this in such a way that doesn't change how the iOS version currently works using background tasks.

Yep, that’s definitely a challenge.

In these situations I like to turn my agent into a ‘server’ and have the GUI app be a client of that server. And if you implement the client-server IPC using XPC, you have a number of ways to make that work on iOS:

  • In iOS 26, you can actually put it into a separate process courtesy of the new helper extension feature.
  • If you need to support older systems and want to preserve the XPC-ness of things, you can use an anonymous listener. TN3113 Testing and debugging XPC code with an anonymous listener talks about this, and while its focus is testing and debugging, there’s no reason you can’t use this in production.
  • With NSXPCConnection, you can cut out the XPC layer entirely and use the real objects for your proxy objects.

In your case another option might be to run the agent and GUI app as completely separate things, and let your CloudKit syncing keep them in sync. That’s certainly keep your synching logic honest (-:

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Thanks Quinn. Good information.

Does Mac Catalyst support Background Processing?
 
 
Q