Setup LaunchAgent in Xcode

Hi there :)

I try to put an Xcode project in place within a LaunchAgent.

The ultimate goal is to have an "application" with two component:

  • macOS application with just an basic UI
  • all the logic happens in a LaunchAgent that runs on background and is launch at startup.

The macOS app uses XPC to send messages to the agent that will run either the app is opened or not.

I struggled at first having this error (for the agent):

An XPC Service cannot be run directly.

Then I found using MachServices key in the .plist of the agent fixes the issue, plus:

let listener = NSXPCListener.init(machServiceName: "com.tonygo.NetworkMonitorAgent")

Then I wonder:

  • Do we have somewhere a documentation about how to setup a LaunchAgent in Xcode
  • I create the plist of the agent on side and run it manually, I could do this in a more automatic way
  • How could I package a macOS applciation that will contains the agent, install it and load the agent?

Note: This is mainly for learning and understanding what we could do at each level (XPCService, LaunchAgents, LaunchDaemon, etc.).

Don’t put code, in this case the NetworkMonitor executable, in Contents/Resources. See Placing Content in a Bundle for info on where it should be.

Don’t forget to adjust com.tonygo.NetworkMonitorAgent.plist to account for this change.

When you call SMAppService.agent(plistName:), include the .plist extension.

Do you actually want to sandbox this app? If so, let me know because that involves further work.

Share and Enjoy

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

Hey @eskimo, ssup?

Don’t put code, in this case the NetworkMonitor executable, in Contents/Resources. See Placing Content in a Bundle for info on where it should be.

"privileged helper tool - macOS - Contents/Library/LaunchServices/" seems to be appropriate ?

Do you actually want to sandbox this app? If so, let me know because that involves further work.

yeah that is the whole, package a full-blown macOS application with a LaunchAgent (with notarization)

Contents/Library/LaunchServices/ seems to be appropriate ?

No. You want Contents/MacOS or Contents/Helpers. The Contents/Library/LaunchServices/ is meant for tools installed with SMJobBless.

yeah that is the whole, package a full-blown macOS application with a LaunchAgent (with notarization)

Notarising implies that you’re distributing the app directly, which means not on the Mac App Store. That means that sandboxing is optional. There are good reasons to sandbox your product, but be aware that it makes this particular task harder.

Specifically, if you sandbox your app then you need to sandbox your launchd agent. That means that you need to sign your agent with entitlements:

  • com.apple.security.app-sandbox to enable the sandbox.

  • com.apple.security.application-groups to facility XPC.

Specifically, to use XPC in a sandboxed process the XPC endpoint name must be an immediate child of one of your app group IDs. So, going back to my earlier example:

  • The app group ID was SKMME9E2Y8.com.example.apple-samplecode.SandboxedAgent.group.

  • The XPC endpoint name was SKMME9E2Y8.com.example.apple-samplecode.SandboxedAgent.group.agent.

You also need to give your agent an Info.plist. If you continue to use an executable as your agent (rather than putting it in its own bundle) set this up with the Info.plist File and Create Info.plist Section in Binary build settings.

Share and Enjoy

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

Notarising implies that you’re distributing the app directly, which means not on the Mac App Store.

You mean that the app on store are not natorized?

Thanks for all these details @eskimo :)

Specifically, if you sandbox your app then you need to sandbox your launchd agent. That means that you need to sign your agent with entitlements: com.apple.security.app-sandbox to enable the sandbox. com.apple.security.application-groups to facility XPC.

These should be present in the entitlements file right?

Specifically, to use XPC in a sandboxed process the XPC endpoint name must be an immediate child of one of your app group IDs. So, going back to my earlier example:

Seems good on my side.

You also need to give your agent an Info.plist. If you continue to use an executable as your agent (rather than putting it in its own bundle) set this up with the Info.plist File and Create Info.plist Section in Binary build settings.

Do we need a Info.plist event with an executbale? When should I put it? "In Contents/MacOS too ?

Also, add .plist to the SMAppService call worked :) But the agent never started, here is the agent plist

You mean that the app on store are not natorized?

Not in the way that that term is usually used.

Note I’m talking about macOS here. We recently announced notarisation for iOS, which I’m not going to discuss on this thread.

On macOS:

  • Code that’s distributed directly, using Developer ID signing, must be notarised in order to pass Gatekeeper.

  • Apps distributed on the Mac App Store do not need to be notarised.

Notarisation performs a bunch of checks. Doing those checks separately is not required for an App Store app. The App Store performs (more or less) equivalent checks as part of its standard submission process.

These should be present in the entitlements file right?

Yes.

Do we need a Info.plist event with an executbale?

There are two cases:

  • If your agent lives within a bundle structure [1], that bundle needs an Info.plist.

  • If not — that is, your agent is a standalone execution — you must embed the contents of the Info.plist into your agent using the Create Info.plist Section in Binary build setting.

But the agent never started, here is the agent plist

Did it crash? Did that generate a crash report?

Share and Enjoy

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

[1] I’m not talking about the bundle structure of your app here, but rather a bundle for the agent that’s nested within your app’s main bundle.

Hey @eskimo :)

Thanks for this clarification about notarisation :)

Did it crash? Did that generate a crash report?

No at all. When I try to run the application I saw these logs:

Unable to register Error Domain=SMAppServiceErrorDomain Code=1 "Operation not permitted" UserInfo={NSLocalizedFailureReason=Operation not permitted}
Received XPC error: Error Domain=NSCocoaErrorDomain Code=4099 "The connection to service named W4MF6H9XZ6.com.tonygo.NetworkMonitorApp.group.agent was invalidated: failed at lookup with error 3 - No such process." UserInfo={NSDebugDescription=The connection to service named W4MF6H9XZ6.com.tonygo.NetworkMonitorApp.group.agent was invalidated: failed at lookup with error 3 - No such process.}

That makes totaly sense as the agent never starts ... I checked with the Console application like I usually did, but I see no messages.

I put all my last changed on this branch: https://github.com/tony-go/NetworkMonitor/tree/sma-app-service

I’m not sure if there’s anything else going on, but there’s a mismatch between your app group entitlement (TTT.com.tonygo.NetworkMonitorApp) and your service name (TTT.com.tonygo.NetworkMonitorApp.group.agent). Remember that the service name must be an immediate child of the app group.

Share and Enjoy

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

Setup LaunchAgent in Xcode
 
 
Q