macoscocoalaunchdxpclaunch-agent

Using a LaunchAgent inside the Mac app sandbox


How would you use a LaunchAgent inside the sandbox? I want to distribute a UI-less LaunchAgent app bundle inside my main application that I can launch on demand. The reason I want this instead of an XPC service is for the KeepAlive option, which will prevent launchd from automatically killing my process when its idle. This option doesn't exist on XPC services.

The documentation says that there's a plist that needs to be copied into ~/Library/LaunchAgents, and this is obviously not possible inside the sandbox. Is there some sort of system API that would handle copy the plist for me? I've seen Apple's SMJobBless sample code, but it seems like that's for registering a privileged LaunchDaemon rather than an unprivileged LaunchAgent.


Solution

  • The API you're looking for is SMLoginItemSetEnabled(). You'll have to package your long-running agent as a regular .app bundle and put it into your main app's bundle at Content/Library/LoginItems.

    Then at runtime in the main application you can use the SMLoginItemSetEnabled() call with the agent's bundle identifier to enable and disable your agent. If your main application quits, the agent stays alive. If the user logs out and back in or reboots, the OS will relaunch your agent when the user logs back in.

    Update: As Dmitry notes, the documentation no longer comes with the sample I originally mentioned, but another Apple sample code project, for App Sandbox, demonstrates the same API (see the file NSXPCConnection+LoginItem.m).

    Update December 2023: The current documentation says that SMLoginItemSetEnabled is deprecated. The recommended replacement is SMAppService, which has register and unregister methods. Quoting from there:

    In macOS 13 and later, use SMAppService to register and control LoginItems, LaunchAgents, and LaunchDaemons as helper executables for your app.