Start dockless apps at login with App Sandbox enabled
The Problem
If we want to run a dockless application at login and we are using Mac OS X 10.5 or later, we can add login items using a shared file list with LaunchServices/LSSharedFileList.h
API.
This technique works well until App Sandbox has been introduced. Now, with the file permissions enforcements, accessing the shared file list of login items is forbidden.
This is remarked by Apple here:
“With App Sandbox, you cannot create a login item using functions in the
LSSharedFileList.h
header file. For example, you cannot use the functionLSSharedFileListInsertItemURL.
”
The Solution Recommended by Apple
In the “App Sandbox Design Guide”, Apple says:
“Instead, use the
SMLoginItemSetEnabled
function along with theLSRegisterURL
function, as described in “Adding Login Items Using the Service Management Framework” in Daemons and Services Programming Guide.”
Here the details:
“Applications can contain a helper application as a full application bundle, stored inside the main application bundle in the
Contents/Library/LoginItems
directory. Set either theLSUIElement
orLSBackgroundOnly
key in theInfo.plist
file of the helper application’s bundle.Use the
SMLoginItemSetEnabled
function (available in Mac OS X v10.6.6 and later) to enable a helper application. It takes two arguments, a CFStringRef containing the bundle identifier of the helper application, and a Boolean specifying the desired state. Pass true to start the helper application immediately and indicate that it should be started every time the user logs in. Pass false to terminate the helper application and indicate that it should no longer be launched when the user logs in. This function returns true if the requested change has taken effect; otherwise, it returns false. This function can be used to manage any number of helper applications.Note: Before calling the
SMLoginItemSetEnabled
function, first register with Launch Services by calling theLSRegisterURL
function with the URL for the helper application bundle.”
The Helper Application
Why not directly set the application with SMLoginItemSetEnabled?
Why do we need to use a helper application?
Because the SMLoginItemSetEnabled
function works only with executables stored in the Contents/Library/LoginItems
directory of the bundle.
Taking into account this, we can create a minimal (i.e. helper) application with these features:
- Standalone, sandboxed and sharing the same bundle.
- Stored in
Contents/Library/LoginItems.
- It must load the main application and then terminate.
The first point can be accomplished creating a new project, enabling App Sandboxing and adding it to the main application project. It's out of topic explain how to do this, there is plenty of tutorials about this argument.
To store the helper app binary in Contents/Library/LoginItems
enter the main project info, click on target and go into the Build Phases tab. Here go to the Copy Files detail and set Wrapper as Destination, Contents/Library/LoginItems
as Subpath, leave unchecked Copy only when installing and add the Helper Application binary in the list:

Then insert a code like this to load your main application applicationDidFinishLaunching:
[[NSWorkspace sharedWorkspace] launchApplication: @"/Path/To/Main/App/Bundle"];
To enable the helper app the main app must:
- Register the helper application.
- Enable or disable helper application startup loading.
This can be accomplished by the following code:
#import <ServiceManagement/ServiceManagement.h> + (void)setStartAtLogin:(NSURL *)bundleURL enabled:(BOOL)enabled { // Creating helper app complete URL NSURL *url = [bundleURL URLByAppendingPathComponent: @"Contents/Library/LoginItems/MyHelperApp.app"]; // Registering helper app if (LSRegisterURL((CFURLRef)url, true) != noErr) { NSLog(@"LSRegisterURL failed!"); } // Setting login if (!SMLoginItemSetEnabled((CFStringRef)@"com.mycompany.MyHelperApp", enabled)) { NSLog(@"SMLoginItemSetEnabled failed!"); } }
/Applications
(not in your Xcode build folder), otherwise you'll get a sandbox violation. And SMLoginItemSetEnabled
appears to work even when LSRegisterURL
fails.
Some Tips
Setting an application to auto-launch at startup without express consent from the user is forbidden by the Mac App Store Review Guideline #2.26, so if you want to submit your program to the Mac App Store you can:
- Leave it off by default and make it customizable.
- Show an alert to get the consent from the user.
[…] by the sandbox is adding a login item. A good tutorial on creating login items is available at delite studio, although some changes to the code are needed. That code follows Apple’s earlier guideline of […]
[…] followed the instructions here and here and it works like a charm – the problem is, of course, code signing. I have two targets; the […]
[…] Start dockless apps at login with App Sandbox enabled | Delite Studio has some info. Reading time. Not sure how it works for a menubar app. […]
[…] followed a instructions here and here and it works like a attract – a problem is, of course, formula signing. we have twin targets; […]
[…] it is quite tricky to achieve. This tutorial will show how. It is a more comprehensive sequel to Delite Studio’s tutorial from October 2011 and /dev/random’s tutorial from January […]