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添加新的方法。

@implementation NSUserDefaults (Additions)

- (BOOL)addApplicationToLoginItems:(NSString *)path {
    NSDictionary *domain = [self persistentDomainForName:@"loginwindow"];
    NSArray *apps = [domain objectForKey:@"AutoLaunchedApplicationDictionary"];
    NSArray *matchingApps = [apps filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"Path CONTAINS %@", path]];
    if ([matchingApps count] == 0) {
        NSMutableDictionary *newDomain = [domain mutableCopy];
        NSMutableArray *newApps = [[apps mutableCopy] autorelease];
        NSDictionary *app = [NSDictionary dictionaryWithObjectsAndKeys:path, @"Path", [NSNumber numberWithBool:NO], @"Hide", nil];
        [newApps addObject:app];
        [newDomain setObject:newApps forKey:@"AutoLaunchedApplicationDictionary"];
        [self setPersistentDomain:newDomain forName:@"loginwindow"];
        return [self synchronize];
    }
    return NO;
}

- (BOOL)removeApplicationFromLoginItems:(NSString *)name {
    NSDictionary *domain = [self persistentDomainForName:@"loginwindow"];
    NSArray *apps = [domain objectForKey:@"AutoLaunchedApplicationDictionary"];
    NSArray *newApps = [apps filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"not Path CONTAINS %@", name]];
    if (![apps isEqualToArray:newApps]) {
        NSMutableDictionary *newDomain = [domain mutableCopy];
        [newDomain setObject:newApps forKey:@"AutoLaunchedApplicationDictionary"];
        [self setPersistentDomain:newDomain forName:@"loginwindow"];
        return [self synchronize];
    }
    return NO;
}

@end


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


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

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值