Hi all,
Today, we will look at how to programmatically add an application to the Login Items. We will also look at removing it from the Login Items.
Pre-requirements

We are going to be using the LaunchServices/LSSharedFileList.h to modify the list of login items. This is only available in OS X 10.5 and above. To support systems less than 10.5, you would have to use Apple Events. This will not be covered in this post.

Methods

There are basically four methods we will have to use to add/remove a LoginItem. One will retrieve the list of LoginItems, the second will add a new item to that list, the third will remove an item from the list and that one is used to resolve the LoginItem with an URL.

The following method will retrieve the list of existing LoginItems

extern LSSharedFileListRef
  LSSharedFileListCreate(
  CFAllocatorRef   inAllocator,
  CFStringRef      inListType,
  CFTypeRef        listOptions)

Parameters:

  1. inAllocator - CFAllocatorRef used to allocate the LSSharedFileListRef . NULL means default allocator.
  2. inListType - A constant indicating list type to create (in our case, it will be kLSSharedFileListSessionLoginItems or
    kLSSharedFileListGlobalLoginItems).
  3. listOptions – Other options. This is generally NULL.

The second that we are going to look at will insert a new Login Item into the list, if it already does not exist. If it already exists, it will just move the item to the particular location in the list specified by the insertAfterThisItem parameter

extern LSSharedFileListItemRef
  LSSharedFileListInsertItemURL(
  LSSharedFileListRef       inList,
  LSSharedFileListItemRef   insertAfterThisItem,
  CFStringRef               inDisplayName,
  IconRef                   inIconRef,
  CFURLRef                  inURL,
  CFDictionaryRef           inPropertiesToSet,
  CFArrayRef                inPropertiesToClear)

Parameters:

  1. inList – The list to which we want to add a new Login Item.
  2. insertAfterThisItem - Item after which new item has to be inserted. To insert at the beginning of
    the list use kLSSharedFileListItemBeforeFirst or to insert at the end of the list use kLSSharedFileListItemLast.
  3. inDisplayName – Display name of the new item. Can be NULL. If NULL, it will use the application’s name.
  4. inIconRef – Icon of the new item. Can be NULL. If NULL, it will use the default application icon.
  5. inURL – URL of the new item. This will be the full path where the .app is found(includes dummy.app).

The other two parameters are not that important at this point of time and they can be NULL.
The third method will allow the application to be removed from the list of Login Items.

extern OSStatus
  LSSharedFileListItemRemove(
  LSSharedFileListRef       inList,
  LSSharedFileListItemRef   inItem)

Parameters:

  1. inList – The list from which the item will be removed.
  2. inItem – The item to be removed

The last method is used to resolve the LoginItem with an URL when we are searching through the list of Login Items.

extern OSStatus
LSSharedFileListItemResolve(
LSSharedFileListItemRef   inItem,
UInt32                    inFlags,
CFURLRef *                outURL,
FSRef *                   outRef)
Parameters:
  1. inItem – The item we are trying to resolve.
  2. inFlags – This is generally NULL.
  3. outURL – The URL to which we are trying to resolve the item to.
  4. outRef – FSRef of original item. Can be NULL.

Implementation

For this example, I have created two methods. The first method will add your application to the login item and the second will remove the application from the list of Login Items.


-(void) addAppAsLoginItem{
	NSString * appPath = [[NSBundle mainBundle] bundlePath];

	// This will retrieve the path for the application
	// For example, /Applications/test.app
	CFURLRef url = (CFURLRef)[NSURL fileURLWithPath:appPath]; 

	// Create a reference to the shared file list.
        // We are adding it to the current user only.
        // If we want to add it all users, use
        // kLSSharedFileListGlobalLoginItems instead of 
        //kLSSharedFileListSessionLoginItems
	LSSharedFileListRef loginItems = LSSharedFileListCreate(NULL,
                                                     kLSSharedFileListSessionLoginItems, NULL);
	if (loginItems) {
		//Insert an item to the list.
		LSSharedFileListItemRef item = LSSharedFileListInsertItemURL(loginItems,
                                                     kLSSharedFileListItemLast, NULL, NULL,
                                                     url, NULL, NULL);
		if (item){
			CFRelease(item);
                }
	}	

	CFRelease(loginItems);
}

-(void) deleteAppFromLoginItem{
	NSString * appPath = [[NSBundle mainBundle] bundlePath];

	// This will retrieve the path for the application
	// For example, /Applications/test.app
	CFURLRef url = (CFURLRef)[NSURL fileURLWithPath:appPath]; 

	// Create a reference to the shared file list.
	LSSharedFileListRef loginItems = LSSharedFileListCreate(NULL,
                                               kLSSharedFileListSessionLoginItems, NULL);

	if (loginItems) {
		UInt32 seedValue;
		//Retrieve the list of Login Items and cast them to
		// a NSArray so that it will be easier to iterate.
		NSArray  *loginItemsArray = (NSArray *)LSSharedFileListCopySnapshot(loginItems, &seedValue);
		int i = 0;
		for(i ; i< [loginItemsArray count]; i++){
			LSSharedFileListItemRef itemRef = (LSSharedFileListItemRef)[loginItemsArray
                                                                               objectAtIndex:i];
			//Resolve the item with URL
			if (LSSharedFileListItemResolve(itemRef, 0, (CFURLRef*) &url, NULL) == noErr) {
				NSString * urlPath = [(NSURL*)url path];
				if ([urlPath compare:appPath] == NSOrderedSame){
					LSSharedFileListItemRemove(loginItems,itemRef);
				}
			}
		}
		[loginItemsArray release];
	}
}

That is it. You can basically have a preference that asks the user whether he wants the app to open at login. Depending on the answer, you can invoke one of the method.

Good Luck.

Tags: , , , , , , ,