I need to start my app at system launch, but the problem is: it is already in App Store, so I must follow some rules like using sandboxing. This leads to fail of desired fun
For Sandboxed applications you need to create special Login Item helper application (located inside Contents/Library/LoginItems). See more here. Also note that your app must be launched from /Applications folder for correct work of Login Item.
I recently went through this same process, unfortunately with sandboxing it's not nearly as easy to do as it used to be. I made a test application with very detailed instructions that is now on Github
This demo application and your application will only work if they are deployed preferably in the /Applications/MyGreat.app
and will not work reliably from the Xcode debug folder.
These are the settings of my project that worked perfectly with this implementation.
Contents/Library/LoginItems
leave Copy only when installing unchecked. Drag your helper application from Products on the left into the tableview.#import <ServiceManagement/ServiceManagement.h>
in your .h fileStartAtLoginController.h
into your h file.- (IBAction)checkChanged:(id)sender
I made a simple checkbox tied to the StandardUserDefaults. (If you chose to do something else your implementation for this may vary.) I also bound the checkbox to IBOutlet NSButton *loginCheck;
in order to determine it's state. This could also be done through [[NSUserDefaults standardUserDefaults] boolForKey:YourKey]
Implement code similar to this in your .m file.
StartAtLoginController *loginController = [[StartAtLoginController alloc] init];
[loginController setBundle:[NSBundle bundleWithPath:[[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:@"Contents/Library/LoginItems/HelperApp.app"]]];
// Change "HelperApp.app" to the name of your helper
if ([loginCheck state]) {
if (![loginController startAtLogin]) {
[loginController setStartAtLogin: YES];
}
} else {
if ([loginController startAtLogin]) {
[loginController setStartAtLogin:NO];
}
}
That's it. As you can see in this project there are some other methods you may want to use such as:
if ([loginController startAtLogin]) {
NSLog(@"Error");
}
For checking after you enable or disable the setting to make sure it worked correctly. Or this:
BOOL startsAtLogin = [loginController startAtLogin];
if (startsAtLogin) {
// Do stuff
}
To do something if the login helper is enabled.
Make sure to test this code vigorously with your implementation.
Application is agent (UIElement)
and YES
as the Value (this will suppress the application from flashing a dock icon each time the user enables launch at login) I also deleted everything except for the App Delegate in interface builder- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
and replace it with - (void)applicationWillFinishLaunching:(NSNotification *)aNotification
Within this method implement code similar to this.
NSString *appPath = [[[[[[NSBundle mainBundle] bundlePath] stringByDeletingLastPathComponent] stringByDeletingLastPathComponent] stringByDeletingLastPathComponent] stringByDeletingLastPathComponent];
// This string takes you from MyGreat.App/Contents/Library/LoginItems/MyHelper.app to MyGreat.App This is an obnoxious but dynamic way to do this since that specific Subpath is required
NSString *binaryPath = [[NSBundle bundleWithPath:appPath] executablePath]; // This gets the binary executable within your main application
[[NSWorkspace sharedWorkspace] launchApplication:binaryPath];
[NSApp terminate:nil];
This code finds your main application, determines it's binary executable(required to launch the application within the sandbox) opens your application, then quits
The last thing you should do when deploying your application for yourself or to the Mac App store is remove your Helper app from the Archived items. Do this by navigating to the Target of your HelperApp -> Build Settings -> Skip Install and set Yes for Release. Apple provides more information at (http://developer.apple.com/library/ios/#documentation/ToolsLanguages/Conceptual/Xcode4UserGuide/000-About_Xcode/about.html)
The setup for getting your sandboxed app to launch at login is time-consuming and it's too easy to get a step wrong. That's why I made a Swift package to automate it. With my LaunchAtLogin package, all you have to do is add a build step in Xcode and then write two lines of code:
import LaunchAtLogin
LaunchAtLogin.isEnabled = true
I just implemented a LoginItem for my own app and found information at these links useful:
How to create a helper application for Mac App to start it on user login?
http://developer.apple.com/library/mac/#documentation/Security/Conceptual/AppSandboxDesignGuide/DesigningYourSandbox/DesigningYourSandbox.html
https://github.com/tcurdt/TCLoginItemHelper
http://www.delitestudio.com/2011/10/25/start-dockless-apps-at-login-with-app-sandbox-enabled/