Sandboxed App <> Launch Agent - how to communicate?

I’m building a sandboxed macOS App Store app that registers an agent using SMAppService.

I’m trying to understand the IPC setup between the main app and the SMAppService-managed agent. The obvious options seem to be: XPC with a Mach service

But from what I understand, I’d need a special entitlement that allows me to communicate over XPC Mach service - which is unlikely to pass Mac App Store review.

So how do people communicate with processes registered with SMAppService?

Answered by Etresoft in 894171022

It depends.

First of all, you must setup an app group. No option there. However you do your communication, you'll need an app group.

Next, you'll need to make sure your launch agent is an "app-like wrapper". What you do is create a new app target and bundle it inside your main app. You can strip off all the things you won't need like storyboards and such. It needs to be an app-like wrapper to have a real bundle ID, sandbox, and understand that it's in a group.

Next, make sure the launch agent works. Run it every 60 seconds or something. Later you can change that.

There are multiple options for communication. You might not need anything. If you can run your launch agent on a schedule, you can save the configuration to a file the next time it launches.

If you do need a continuously running agent, then you'll need some kind of client/server connection. You could do that manually with sockets or named pipes. Or you could use XPC.

The first time I tried all of this with XPC, it failed miserably. I don't know what I did wrong. I didn't really need it as I could use a configuration file. However, I do have a test app right now with a functional launch agent talking via XPC. No entitlement needed. I'm not sure what I did differently this time. It is a fragile architecture.

Also pay careful attention to user authorization. Your app needs to gracefully handle when the user disables the launch agent. I recommend loading the agent first thing and then handle the case when the user later disables it. Otherwise, if not loaded for the first time, it'll be in an odd "not found" state.

Good luck!

It depends.

First of all, you must setup an app group. No option there. However you do your communication, you'll need an app group.

Next, you'll need to make sure your launch agent is an "app-like wrapper". What you do is create a new app target and bundle it inside your main app. You can strip off all the things you won't need like storyboards and such. It needs to be an app-like wrapper to have a real bundle ID, sandbox, and understand that it's in a group.

Next, make sure the launch agent works. Run it every 60 seconds or something. Later you can change that.

There are multiple options for communication. You might not need anything. If you can run your launch agent on a schedule, you can save the configuration to a file the next time it launches.

If you do need a continuously running agent, then you'll need some kind of client/server connection. You could do that manually with sockets or named pipes. Or you could use XPC.

The first time I tried all of this with XPC, it failed miserably. I don't know what I did wrong. I didn't really need it as I could use a configuration file. However, I do have a test app right now with a functional launch agent talking via XPC. No entitlement needed. I'm not sure what I did differently this time. It is a fragile architecture.

Also pay careful attention to user authorization. Your app needs to gracefully handle when the user disables the launch agent. I recommend loading the agent first thing and then handle the case when the user later disables it. Otherwise, if not loaded for the first time, it'll be in an odd "not found" state.

Good luck!

What Etresoft said plus…

XPC is our preferred IPC mechanism, but it has a bunch of history and it can be confusing. I have links to docs and so on in XPC Resources.

The XPC named endpoint published by your launchd agent must have a name that’s ‘within’ the app group. See the first entry in the table in App Groups Entitlement.

Both programs must claim access to that app group via an entitlement. That entitlements should be authorised by a provisioning profile. App groups have a whole bunch of history on the Mac. See App Groups: macOS vs iOS: Working Towards Harmony.

The requirement for a provisioning profile is why you need to embed the agent in an app-like wrapper. Embedding a command-line tool in a sandboxed app offers a rough outline of how to do that.

Share and Enjoy

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

Sandboxed App &lt;&gt; Launch Agent - how to communicate?
 
 
Q