I’ve been developing an utility app. I’m really excited about this and I do hope to release it quite soon (still have some issues with choctop and sparkle stuff). I even got an icon for it (thanks, Scarlet Bits!). In this blog post I’d like to share about a solution to a problem that I faced while developing my app – launching it at the beginning of user’s session, i.e. on login.
Since Mac OS X Leopard (10.5) apple has dedicated API for these kind of things. And by writing “kind of” I’m going to quote the Apple developer documentation itself:
The Shared File List API is new to Launch Services in Mac OS X Leopard. This API provides access to several kinds of system-global and per-user persistent lists of file system objects, such as recent documents and applications, favorites, and login items. For details, see the new interface file LSSharedFileList.h.
Read on if you’d like to know how to add your app to login items list.
Getting login items list
First off – we’ll fetch login items to see if our app is already in that list. Well, at first it won’t be there, but it will pay off in the future, trust me. So here’s the code snippet for fetching existing login items and assigning them to an NSArray:
// Some seed data
UInt32 seedValue;
// Let's create reference to shared file list
LSSharedFileListRef loginItems = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL);
// Then just pop values from referenced list into array
NSArray *loginItemsArray = (NSArray *)LSSharedFileListCopySnapshot(loginItems, &seedValue);
You can now use this array as any table’s data source to see what this list contains. If you’re too lazy, then I can tell you that each item has “assigned display name, icon, and url as well as other optional properties” (quote from source code).
Now that we’ve got the list of login items – it’s really easy to add/remove our app to/from the list of login items. But for starters – we’re going to check for item’s presence in the list.
Checking for item’s existence
Since it is my first experience with login items and LSSharedFileList, from what I found on the net, I believe that main criteria is to check item’s url against given one. This code snippet shows how it should be done:
- (BOOL)loginItemExistsWithLoginItemReference:(LSSharedFileListRef)theLoginItemsRefs ForPath:(CFURLRef)thePath {
BOOL exists = NO;
UInt32 seedValue;
// We're going to grab the contents of the shared file list (LSSharedFileListItemRef objects)
// and pop it in an array so we can iterate through it to find our item.
NSArray *loginItemsArray = (NSArray *)LSSharedFileListCopySnapshot(theLoginItemsRefs, &seedValue);
for (id item in loginItemsArray) {
LSSharedFileListItemRef itemRef = (LSSharedFileListItemRef)item;
if (LSSharedFileListItemResolve(itemRef, 0, (CFURLRef*) &thePath, NULL) == noErr) {
if ([[(NSURL *)thePath path] hasPrefix:@"/Applications/MyApp.app"])
exists = YES;
}
return exists;
};
Adding an item to login items list
Method for adding an item to login items list is LSSharedFileListInsertItemURL. – method for inserting. This method accepts 7 parameters, but only 3 of them will be of interest to us. These are the accepted parameters:
- Reference to login item list (created in the code above. Do not mix up with array of items)
- Position of where to insert new login item. To insert item to the beginning of the list use
kLSSharedFileListItemBeforeFirst. To insert item to the ending of the list use kLSSharedFileListItemLast. Otherwise pass LSSharedFileListItemRef.
- Display name of new login item. Can be NULL. Defaults to app name.
- Icon of the login item. Can be NULL. Defaults to app icon.
CFURLRef of item to insert. This usually is a path to your app (like /Applications/MyApp.app)
CFDictionary – dictionary of options for new login item.
CFDictionary – dictionary of options to clear if item already exists in the list.
The ones interesting for us are 1, 2 and 5. So the code for adding an item to login items list could be as follows:
// Reference to shared file list
LSSharedFileListRef theLoginItemsRefs = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL);
// CFURLRef to the insertable item.
CFURLRef url = (CFURLRef)[NSURL fileURLWithPath:@"/Applications/MyApp.app"];
// Actual insertion of an item.
LSSharedFileListItemRef item = LSSharedFileListInsertItemURL(theLoginItemsRefs, kLSSharedFileListItemLast, NULL, NULL, thePath, NULL, NULL);
// Clean up in case of success
if (item)
CFRelease(item);
Removing an item from login items list
Method for removal of item in question is LSSharedFileListItemRemove. This method contrary to the one for adding the item to login items list accepts only two parameters:
- The reference to login items list
- The item reference in question
It could not get simpler than this:
LSSharedFileListItemRemove(theLoginItemsRefs, itemRef);
Conclusion
This is the first part of managing login items in Mac OS X. In next part I’ll show you how to keep track of changes while your app is not running and adding/removing your app to/from login items isn’t handled by your app.
Please note that I found code samples in one place on the internet but was too lazy to bookmark it, hence this code was extracted from the app. If you recognize your stuff – please post a note/link in the comments. Thanks a heap for reading this!