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

     

  • 相关阅读:
    classpath详解
    xml详解
    pojo、po、dto、dao、bo区别
    事务的四种隔离级别
    spring相关知识点易错
    Orm
    100+个Java项目视频教程+源码+笔记,项目经验不用愁了!
    使用TM1629A芯片驱动米字数码管
    关于安装airflow遇到的问题
    Semver(语义化版本号)扫盲
  • 原文地址:https://www.cnblogs.com/watchdatalearn2012620/p/3336414.html
Copyright © 2020-2023  润新知