Cocoa -- 添加和移除开机启动项

 plist~/Library/LaunchAgents/ 目录下

    // 配置开机默认启动  
    -(void)installDaemon{  
        NSString* launchFolder = [NSString stringWithFormat:@"%@/Library/LaunchAgents",NSHomeDirectory()];  
        NSString * boundleID = [[NSBundle mainBundle] objectForInfoDictionaryKey:(NSString *)kCFBundleIdentifierKey];   
        NSString* dstLaunchPath = [launchFolder stringByAppendingFormat:@"/%@.plist",boundleID];  
        NSFileManager* fm = [NSFileManager defaultManager];  
        BOOL isDir = NO;  
        //已经存在启动项中,就不必再创建  
        if ([fm fileExistsAtPath:dstLaunchPath isDirectory:&isDir] && !isDir) {  
            return;  
        }  
        //下面是一些配置  
        NSMutableDictionary* dict = [[NSMutableDictionary alloc] init];  
        NSMutableArray* arr = [[NSMutableArray alloc] init];  
        [arr addObject:[[NSBundle mainBundle] executablePath]];  
        [arr addObject:@"-runMode"];  
        [arr addObject:@"autoLaunched"];  
        [dict setObject:[NSNumber numberWithBool:true] forKey:@"RunAtLoad"];  
        [dict setObject:boundleID forKey:@"Label"];  
        [dict setObject:arr forKey:@"ProgramArguments"];  
        isDir = NO;  
        if (![fm fileExistsAtPath:launchFolder isDirectory:&isDir] && isDir) {  
            [fm createDirectoryAtPath:launchFolder withIntermediateDirectories:NO attributes:nil error:nil];  
        }  
        [dict writeToFile:dstLaunchPath atomically:NO];  
        [arr release];  arr = nil;  
        [dict release]; dict = nil;  
    }  

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

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

    // 取消配置开机默认启动  
    -(void)unInstallDaemon{  
        NSString* launchFolder = [NSString stringWithFormat:@"%@/Library/LaunchAgents",NSHomeDirectory()];  
        BOOL isDir = NO;  
        NSFileManager* fm = [NSFileManager defaultManager];  
        if (![fm fileExistsAtPath:launchFolder isDirectory:&isDir] && isDir) {  
            return;  
        }  
        NSString * boundleID = [[NSBundle mainBundle] objectForInfoDictionaryKey:(NSString *)kCFBundleIdentifierKey];   
        NSString* srcLaunchPath = [launchFolder stringByAppendingFormat:@"/%@.plist",boundleID];  
        [fm removeItemAtPath:srcLaunchPath error:nil];  
    }  

二.使用LoginItemsAE

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

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

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

    //返回开机启动项列表,传入itemsPtr地址即可,  
    extern OSStatus LIAECopyLoginItems(CFArrayRef *itemsPtr);  
//添加开机启动项,hideIt参数一般是传 NO  
extern OSStatus LIAEAddURLAtEnd(CFURLRef item,     Boolean hideIt);
    //移除开机启动项  
    extern OSStatus LIAERemove(CFIndex itemIndex);  

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

    #import "UKLoginItemRegistry.h"  
      
      
    @implementation UKLoginItemRegistry  
      
    +(NSArray*) allLoginItems  
    {  
        NSArray*    itemsList = nil;  
        OSStatus    err = LIAECopyLoginItems( (CFArrayRef*) &itemsList );   // Take advantage of toll-free bridging.  
        if( err != noErr )  
        {  
            NSLog(@"Couldn't list login items error %ld", err);  
            return nil;  
        }  
          
        return [itemsList autorelease];  
    }  
      
    +(BOOL)     addLoginItemWithPath: (NSString*)path hideIt: (BOOL)hide  
    {  
        NSURL*  url = [NSURL fileURLWithPath: path];  
          
        return [self addLoginItemWithURL: url hideIt: hide];  
    }  
      
    //根据文件路径移除启动项  
    +(BOOL)     removeLoginItemWithPath: (NSString*)path  
    {  
        int     idx = [self indexForLoginItemWithPath: path];  
          
        return (idx != -1) && [self removeLoginItemAtIndex: idx];   // Found item? Remove it and return success flag. Else return NO.  
    }  
      
    +(BOOL)     addLoginItemWithURL: (NSURL*)url hideIt: (BOOL)hide         // Main bottleneck for adding a login item.  
    {  
        OSStatus err = LIAEAddURLAtEnd( (CFURLRef) url, hide ); // CFURLRef is toll-free bridged to NSURL.  
          
        if( err != noErr )  
            NSLog(@"Couldn't add login item error %ld", err);  
          
        return( err == noErr );  
    }  
      
      
    +(BOOL)     removeLoginItemAtIndex: (int)idx            // Main bottleneck for getting rid of a login item.  
    {  
        OSStatus err = LIAERemove( idx );  
          
        if( err != noErr )  
            NSLog(@"Couldn't remove login intem error %ld", err);  
          
        return( err == noErr );  
    }  
      
      
    +(int)      indexForLoginItemWithURL: (NSURL*)url       // Main bottleneck for finding a login item in the list.  
    {  
        NSArray*        loginItems = [self allLoginItems];  
        NSEnumerator*   enny = [loginItems objectEnumerator];  
        NSDictionary*   currLoginItem = nil;  
        int             x = 0;  
          
        while(( currLoginItem = [enny nextObject] ))  
        {  
            if( [[currLoginItem objectForKey: UKLoginItemURL] isEqualTo: url] )  
                return x;  
              
            x++;  
        }  
          
        return -1;  
    }  
      
    +(int)      indexForLoginItemWithPath: (NSString*)path  
    {  
        NSURL*  url = [NSURL fileURLWithPath: path];  
          
        return [self indexForLoginItemWithURL: url];  
    }  
      
      
    +(BOOL)     removeLoginItemWithURL: (NSURL*)url  
    {  
        int     idx = [self indexForLoginItemWithURL: url];  
          
        return (idx != -1) && [self removeLoginItemAtIndex: idx];   // Found item? Remove it and return success flag. Else return NO.  
    }  
      
    @end  

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

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

. 使用LaunchServices修改启动项

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

    //这个方法返回启动项列表  
    extern LSSharedFileListRef  
    LSSharedFileListCreate(  
                           CFAllocatorRef   inAllocator,  
                           CFStringRef      inListType,  
                           CFTypeRef        listOptions)  
    //添加新的启动项  
    extern LSSharedFileListItemRef LSSharedFileListInsertItemURL(  
                                  LSSharedFileListRef       inList,  
                                  LSSharedFileListItemRef   insertAfterThisItem,  
                                  CFStringRef               inDisplayName,  
                                  IconRef                   inIconRef,  
                                  CFURLRef                  inURL,  
                                  CFDictionaryRef           inPropertiesToSet,  
                                  CFArrayRef                inPropertiesToClear)  
//移除启动项  
extern OSStatus LSSharedFileListItemRemove(  
                           LSSharedFileListRef       inList,  
                           LSSharedFileListItemRef   inItem) 
    //最后一个方法用来解析启动项的 URL,用来检索启动项列表里的东西  
    extern OSStatus LSSharedFileListItemResolve(  
                                LSSharedFileListItemRef   inItem,  
                                UInt32                    inFlags,  
                                CFURLRef *                outURL,  
                                FSRef *                   outRef)  

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

    -(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];  
        }  
    }  

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

使用NSUserDefaults修改启动项

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

    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文件中,只不过实现的方式不一样罢了。

 

原文地址:https://www.cnblogs.com/watchdatalearn2012620/p/3336414.html