conanwin

导航

添加移除开机启动项

 

一 写plist到~/Library/LaunchAgents/ 目录下

 

[plain] view plaincopy
 
  1. // 配置开机默认启动  
  2. -(void)installDaemon{  
  3.     NSString* launchFolder = [NSString stringWithFormat:@"%@/Library/LaunchAgents",NSHomeDirectory()];  
  4.     NSString * boundleID = [[NSBundle mainBundle] objectForInfoDictionaryKey:(NSString *)kCFBundleIdentifierKey];   
  5.     NSString* dstLaunchPath = [launchFolder stringByAppendingFormat:@"/%@.plist",boundleID];  
  6.     NSFileManager* fm = [NSFileManager defaultManager];  
  7.     BOOL isDir = NO;  
  8.     //已经存在启动项中,就不必再创建  
  9.     if ([fm fileExistsAtPath:dstLaunchPath isDirectory:&isDir] && !isDir) {  
  10.         return;  
  11.     }  
  12.     //下面是一些配置  
  13.     NSMutableDictionary* dict = [[NSMutableDictionary alloc] init];  
  14.     NSMutableArray* arr = [[NSMutableArray alloc] init];  
  15.     [arr addObject:[[NSBundle mainBundle] executablePath]];  
  16.     [arr addObject:@"-runMode"];  
  17.     [arr addObject:@"autoLaunched"];  
  18.     [dict setObject:[NSNumber numberWithBool:true] forKey:@"RunAtLoad"];  
  19.     [dict setObject:boundleID forKey:@"Label"];  
  20.     [dict setObject:arr forKey:@"ProgramArguments"];  
  21.     isDir = NO;  
  22.     if (![fm fileExistsAtPath:launchFolder isDirectory:&isDir] && isDir) {  
  23.         [fm createDirectoryAtPath:launchFolder withIntermediateDirectories:NO attributes:nil error:nil];  
  24.     }  
  25.     [dict writeToFile:dstLaunchPath atomically:NO];  
  26.     [arr release];  arr = nil;  
  27.     [dict release]; dict = nil;  
  28. }  

 

 

关于启动项的配置可以去开发文档搜索:Creating launchd Daemons and Agents。

取消开机启动则只要删除~/Library/LaunchAgents/ 目录下相应的plist文件即可。

 

[plain] view plaincopy
 
  1. // 取消配置开机默认启动  
  2. -(void)unInstallDaemon{  
  3.     NSString* launchFolder = [NSString stringWithFormat:@"%@/Library/LaunchAgents",NSHomeDirectory()];  
  4.     BOOL isDir = NO;  
  5.     NSFileManager* fm = [NSFileManager defaultManager];  
  6.     if (![fm fileExistsAtPath:launchFolder isDirectory:&isDir] && isDir) {  
  7.         return;  
  8.     }  
  9.     NSString * boundleID = [[NSBundle mainBundle] objectForInfoDictionaryKey:(NSString *)kCFBundleIdentifierKey];   
  10.     NSString* srcLaunchPath = [launchFolder stringByAppendingFormat:@"/%@.plist",boundleID];  
  11.     [fm removeItemAtPath:srcLaunchPath error:nil];  
  12. }  

 

 

二.使用LoginItemsAE 

在开发文档中搜索LoginItemsAE即可搜到它的源码,包含LoginItemsAE.c和LoginItemsAE.h两个文件。其原理是写配置信息到~/Library/Preferences/com.apple.loginitems.plist 文件。打开com.apple.loginitems.plist文件找到CustomListItems那一项,展开就可以看到开机启动项的一些信息(包括app名称,所在路径。。。)

图1:com.apple.loginitems.plist 开机启动项内容

下面简单介绍下LoginItemsAE.h 中的几个API。

 

[plain] view plaincopy
 
  1. //返回开机启动项列表,传入itemsPtr地址即可,  
  2. extern OSStatus LIAECopyLoginItems(CFArrayRef *itemsPtr);  

 

[plain] view plaincopy
 
  1. //添加开机启动项,hideIt参数一般是传 NO  
  2. extern OSStatus LIAEAddURLAtEnd(CFURLRef item,     Boolean hideIt);  

 

 

[plain] view plaincopy
 
  1. //移除开机启动项  
  2. extern OSStatus LIAERemove(CFIndex itemIndex);  

 

 

 

是不是觉得上面的接口不是很好用呢,特别是移除启动项的那个接口,必须得知道要移除的index,如果能根据文件路径移除就好了。下面用Objective-C语法重新封装这几个接口,更方便调用。

 

[plain] view plaincopy
 
  1. #import "UKLoginItemRegistry.h"  
  2.   
  3.   
  4. @implementation UKLoginItemRegistry  
  5.   
  6. +(NSArray*) allLoginItems  
  7. {  
  8.     NSArray*    itemsList = nil;  
  9.     OSStatus    err = LIAECopyLoginItems( (CFArrayRef*) &itemsList );   // Take advantage of toll-free bridging.  
  10.     if( err != noErr )  
  11.     {  
  12.         NSLog(@"Couldn't list login items error %ld", err);  
  13.         return nil;  
  14.     }  
  15.       
  16.     return [itemsList autorelease];  
  17. }  
  18.   
  19. +(BOOL)     addLoginItemWithPath: (NSString*)path hideIt: (BOOL)hide  
  20. {  
  21.     NSURL*  url = [NSURL fileURLWithPath: path];  
  22.       
  23.     return [self addLoginItemWithURL: url hideIt: hide];  
  24. }  
  25.   
  26. //根据文件路径移除启动项  
  27. +(BOOL)     removeLoginItemWithPath: (NSString*)path  
  28. {  
  29.     int     idx = [self indexForLoginItemWithPath: path];  
  30.       
  31.     return (idx != -1) && [self removeLoginItemAtIndex: idx];   // Found item? Remove it and return success flag. Else return NO.  
  32. }  
  33.   
  34. +(BOOL)     addLoginItemWithURL: (NSURL*)url hideIt: (BOOL)hide         // Main bottleneck for adding a login item.  
  35. {  
  36.     OSStatus err = LIAEAddURLAtEnd( (CFURLRef) url, hide ); // CFURLRef is toll-free bridged to NSURL.  
  37.       
  38.     if( err != noErr )  
  39.         NSLog(@"Couldn't add login item error %ld", err);  
  40.       
  41.     return( err == noErr );  
  42. }  
  43.   
  44.   
  45. +(BOOL)     removeLoginItemAtIndex: (int)idx            // Main bottleneck for getting rid of a login item.  
  46. {  
  47.     OSStatus err = LIAERemove( idx );  
  48.       
  49.     if( err != noErr )  
  50.         NSLog(@"Couldn't remove login intem error %ld", err);  
  51.       
  52.     return( err == noErr );  
  53. }  
  54.   
  55.   
  56. +(int)      indexForLoginItemWithURL: (NSURL*)url       // Main bottleneck for finding a login item in the list.  
  57. {  
  58.     NSArray*        loginItems = [self allLoginItems];  
  59.     NSEnumerator*   enny = [loginItems objectEnumerator];  
  60.     NSDictionary*   currLoginItem = nil;  
  61.     int             x = 0;  
  62.       
  63.     while(( currLoginItem = [enny nextObject] ))  
  64.     {  
  65.         if( [[currLoginItem objectForKey: UKLoginItemURL] isEqualTo: url] )  
  66.             return x;  
  67.           
  68.         x++;  
  69.     }  
  70.       
  71.     return -1;  
  72. }  
  73.   
  74. +(int)      indexForLoginItemWithPath: (NSString*)path  
  75. {  
  76.     NSURL*  url = [NSURL fileURLWithPath: path];  
  77.       
  78.     return [self indexForLoginItemWithURL: url];  
  79. }  
  80.   
  81.   
  82. +(BOOL)     removeLoginItemWithURL: (NSURL*)url  
  83. {  
  84.     int     idx = [self indexForLoginItemWithURL: url];  
  85.       
  86.     return (idx != -1) && [self removeLoginItemAtIndex: idx];   // Found item? Remove it and return success flag. Else return NO.  
  87. }  
  88.   
  89. @end  

 

 

上面的代码是不是觉得亲切多了啊?

不过这几个接口有点缺陷:只能用i386来编译,用x86_64编译会报错的。

 

三. 使用LaunchServices修改启动项

可以使用LaunchServices/LSSharedFileList.h 里面的方法来更改启动项,但是这些方法只支持10.5及以上的系统。下面简单的介绍下这些方法。

 

[plain] view plaincopy
 
  1. //这个方法返回启动项列表  
  2. extern LSSharedFileListRef  
  3. LSSharedFileListCreate(  
  4.                        CFAllocatorRef   inAllocator,  
  5.                        CFStringRef      inListType,  
  6.                        CFTypeRef        listOptions)  

 

[plain] view plaincopy
 
  1. //添加新的启动项  
  2. extern LSSharedFileListItemRef LSSharedFileListInsertItemURL(  
  3.                               LSSharedFileListRef       inList,  
  4.                               LSSharedFileListItemRef   insertAfterThisItem,  
  5.                               CFStringRef               inDisplayName,  
  6.                               IconRef                   inIconRef,  
  7.                               CFURLRef                  inURL,  
  8.                               CFDictionaryRef           inPropertiesToSet,  
  9.                               CFArrayRef                inPropertiesToClear)  

 

 

[plain] view plaincopy
 
  1. //移除启动项  
  2. extern OSStatus LSSharedFileListItemRemove(  
  3.                            LSSharedFileListRef       inList,  
  4.                            LSSharedFileListItemRef   inItem)  

 

 

[plain] view plaincopy
 
  1. //最后一个方法用来解析启动项的 URL,用来检索启动项列表里的东西  
  2. extern OSStatus LSSharedFileListItemResolve(  
  3.                             LSSharedFileListItemRef   inItem,  
  4.                             UInt32                    inFlags,  
  5.                             CFURLRef *                outURL,  
  6.                             FSRef *                   outRef)  

 

 

 

使用下面两个方法来封装上面的这些API,使更易于使用。你也可以改成传入app路径添加启动项。- (void) addAppAsLoginItem:(NSString *)appPath,把这句NSString * appPath = [[NSBundle mainBundle] bundlePath];注视掉就行了。

 

[plain] view plaincopy
 
  1. -(void) addAppAsLoginItem{  
  2.     NSString * appPath = [[NSBundle mainBundle] bundlePath];  
  3.       
  4.     // This will retrieve the path for the application  
  5.     // For example, /Applications/test.app  
  6.     CFURLRef url = (CFURLRef)[NSURL fileURLWithPath:appPath];   
  7.       
  8.     // Create a reference to the shared file list.  
  9.     // We are adding it to the current user only.  
  10.     // If we want to add it all users, use  
  11.     // kLSSharedFileListGlobalLoginItems instead of  
  12.     //kLSSharedFileListSessionLoginItems  
  13.     LSSharedFileListRef loginItems = LSSharedFileListCreate(NULL,  
  14.                                                             kLSSharedFileListSessionLoginItems, NULL);  
  15.     if (loginItems) {  
  16.         //Insert an item to the list.  
  17.         LSSharedFileListItemRef item = LSSharedFileListInsertItemURL(loginItems,  
  18.                                                                      kLSSharedFileListItemLast, NULL, NULL,  
  19.                                                                      url, NULL, NULL);  
  20.         if (item){  
  21.             CFRelease(item);  
  22.         }  
  23.     }  
  24.       
  25.     CFRelease(loginItems);  
  26. }  
  27.   
  28. -(void) deleteAppFromLoginItem{  
  29.     NSString * appPath = [[NSBundle mainBundle] bundlePath];  
  30.       
  31.     // This will retrieve the path for the application  
  32.     // For example, /Applications/test.app  
  33.     CFURLRef url = (CFURLRef)[NSURL fileURLWithPath:appPath];   
  34.       
  35.     // Create a reference to the shared file list.  
  36.     LSSharedFileListRef loginItems = LSSharedFileListCreate(NULL,  
  37.                                                             kLSSharedFileListSessionLoginItems, NULL);  
  38.       
  39.     if (loginItems) {  
  40.         UInt32 seedValue;  
  41.         //Retrieve the list of Login Items and cast them to  
  42.         // a NSArray so that it will be easier to iterate.  
  43.         NSArray  *loginItemsArray = (NSArray *)LSSharedFileListCopySnapshot(loginItems, &seedValue);  
  44.         int i = 0;  
  45.         for(i ; i< [loginItemsArray count]; i++){  
  46.             LSSharedFileListItemRef itemRef = (LSSharedFileListItemRef)[loginItemsArray  
  47.                                                                         objectAtIndex:i];  
  48.             //Resolve the item with URL  
  49.             if (LSSharedFileListItemResolve(itemRef, 0, (CFURLRef*) &url, NULL) == noErr) {  
  50.                 NSString * urlPath = [(NSURL*)url path];  
  51.                 if ([urlPath compare:appPath] == NSOrderedSame){  
  52.                     LSSharedFileListItemRemove(loginItems,itemRef);  
  53.                 }  
  54.             }  
  55.         }  
  56.         [loginItemsArray release];  
  57.     }  
  58. }  

 

 

详情请打开:http://cocoatutorial.grapewave.com/2010/02/creating-andor-removing-a-login-item/

 

四. 使用NSUserDefaults修改启动项

下面通过分类给NSUserDefaults添加新的方法。

 

[plain] view plaincopy
 
  1. @implementation NSUserDefaults (Additions)  
  2.   
  3. - (BOOL)addApplicationToLoginItems:(NSString *)path {  
  4.     NSDictionary *domain = [self persistentDomainForName:@"loginwindow"];  
  5.     NSArray *apps = [domain objectForKey:@"AutoLaunchedApplicationDictionary"];  
  6.     NSArray *matchingApps = [apps filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"Path CONTAINS %@", path]];  
  7.     if ([matchingApps count] == 0) {  
  8.         NSMutableDictionary *newDomain = [domain mutableCopy];  
  9.         NSMutableArray *newApps = [[apps mutableCopy] autorelease];  
  10.         NSDictionary *app = [NSDictionary dictionaryWithObjectsAndKeys:path, @"Path", [NSNumber numberWithBool:NO], @"Hide", nil];  
  11.         [newApps addObject:app];  
  12.         [newDomain setObject:newApps forKey:@"AutoLaunchedApplicationDictionary"];  
  13.         [self setPersistentDomain:newDomain forName:@"loginwindow"];  
  14.         return [self synchronize];  
  15.     }  
  16.     return NO;  
  17. }  
  18.   
  19. - (BOOL)removeApplicationFromLoginItems:(NSString *)name {  
  20.     NSDictionary *domain = [self persistentDomainForName:@"loginwindow"];  
  21.     NSArray *apps = [domain objectForKey:@"AutoLaunchedApplicationDictionary"];  
  22.     NSArray *newApps = [apps filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"not Path CONTAINS %@", name]];  
  23.     if (![apps isEqualToArray:newApps]) {  
  24.         NSMutableDictionary *newDomain = [domain mutableCopy];  
  25.         [newDomain setObject:newApps forKey:@"AutoLaunchedApplicationDictionary"];  
  26.         [self setPersistentDomain:newDomain forName:@"loginwindow"];  
  27.         return [self synchronize];  
  28.     }  
  29.     return NO;  
  30. }  
  31.   
  32. @end  



 

详情请打开:http://www.danandcheryl.com/2011/02/how-to-modify-the-dock-or-login-items-on-os-x

 

后面三种方法都是写配置到~/Library/Preferences/com.apple.loginitems.plist文件中,只不过实现的方式不一样罢了。

posted on 2015-07-23 16:00  conanwin  阅读(714)  评论(0编辑  收藏  举报