一 写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.c和LoginItemsAE.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 != -) && [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 = ; while(( currLoginItem = [enny nextObject] ))
{
if( [[currLoginItem objectForKey: UKLoginItemURL] isEqualTo: url] )
return x; x++;
} return -;
} +(int) indexForLoginItemWithPath: (NSString*)path
{
NSURL* url = [NSURL fileURLWithPath: path]; return [self indexForLoginItemWithURL: url];
} +(BOOL) removeLoginItemWithURL: (NSURL*)url
{
int idx = [self indexForLoginItemWithURL: url]; return (idx != -) && [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 = ;
for(i ; i< [loginItemsArray count]; i++){
LSSharedFileListItemRef itemRef = (LSSharedFileListItemRef)[loginItemsArray
objectAtIndex:i];
//Resolve the item with URL
if (LSSharedFileListItemResolve(itemRef, , (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. - (BOOL)addApplicationToLoginItems:(NSString *)path {
    3. NSDictionary *domain = [self persistentDomainForName:@"loginwindow"];
    4. NSArray *apps = [domain objectForKey:@"AutoLaunchedApplicationDictionary"];
    5. NSArray *matchingApps = [apps filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"Path CONTAINS %@", path]];
    6. if ([matchingApps count] == 0) {
    7. NSMutableDictionary *newDomain = [domain mutableCopy];
    8. NSMutableArray *newApps = [[apps mutableCopy] autorelease];
    9. NSDictionary *app = [NSDictionary dictionaryWithObjectsAndKeys:path, @"Path", [NSNumber numberWithBool:NO], @"Hide", nil];
    10. [newApps addObject:app];
    11. [newDomain setObject:newApps forKey:@"AutoLaunchedApplicationDictionary"];
    12. [self setPersistentDomain:newDomain forName:@"loginwindow"];
    13. return [self synchronize];
    14. }
    15. return NO;
    16. }
    17. - (BOOL)removeApplicationFromLoginItems:(NSString *)name {
    18. NSDictionary *domain = [self persistentDomainForName:@"loginwindow"];
    19. NSArray *apps = [domain objectForKey:@"AutoLaunchedApplicationDictionary"];
    20. NSArray *newApps = [apps filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"not Path CONTAINS %@", name]];
    21. if (![apps isEqualToArray:newApps]) {
    22. NSMutableDictionary *newDomain = [domain mutableCopy];
    23. [newDomain setObject:newApps forKey:@"AutoLaunchedApplicationDictionary"];
    24. [self setPersistentDomain:newDomain forName:@"loginwindow"];
    25. return [self synchronize];
    26. }
    27. return NO;
    28. }
    29. @end

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

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

Cocoa -- 添加和移除开机启动项的更多相关文章

  1. Centos7 设置、查看、添加、删除服务的开机启动项

    查看开机启动项 systemctl list-unit-files |   grep enable 为服务添加开机启动项 systemctl enable zabbix-server.service ...

  2. Windows手动添加开机启动项

    @方法1. 添加程序完整路径到注册表HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run下 或者添加到HKEY_CURREN ...

  3. PowerShell添加或修改注册表开机启动项脚本

    代码如下: $name = Read-Host "请输入开机启动项的名字(随便起)" $value = Read-Host "请输入开机启动项的值" try{ ...

  4. CentOS7 添加开机启动项

     centos6 加入开机启动:   vim /etc/rc.d/rc.local 注意命令不要出错,重启后生效   或者   centos 7 下: vim /lib/systemd/system/ ...

  5. windows添加开机启动项

    http://www.cnblogs.com/jokey/archive/2010/06/17/1759370.html添加开机启动项(通过注册表) 例子:增加QQ开机启动项 第一步:找到注册表的启动 ...

  6. Linux 添加开机启动项的三种方法

    linux 添加开机启动项的三种方法. (1)编辑文件 /etc/rc.local 输入命令:vim /etc/rc.local 将出现类似如下的文本片段: #!/bin/sh## This scri ...

  7. win10应用程序添加到开机启动项的两种解决办法

    原文 win10应用程序添加到开机启动项的两种解决办法 在windows10系统中,如果想让应用程序在开机之后自动运行起来,可以怎么做呢? 方法一: 1.首先创建应用程序的快捷方式 找到自己想加入开机 ...

  8. centos7如何添加开机启动项?

    centos7提供开启服务启动的方式: 1.系统服务管理命令,如果是通过yum安装的软件,开机启动脚本,已经自动创建好了,直接执行如下命令 nginx.service后缀可以省略 systemctl ...

  9. Win10怎么添加开机启动项?Win10添加开机自动运行软件三种方法

    Win10管理开机启动项的方法相信大家已经非常熟悉,msconfig命令各系统都通用,那么很多用户发觉Win10和Win7 XP等系统不同,没有启动文件夹,那么我们怎么添加开机启动项呢?如晨软件或程序 ...

随机推荐

  1. 为什么前后端分离不利于seo

    搜索引擎的基础爬虫的原理就是抓取你的url,然后获取你的html源代码并解析. 而你的页面通常用了vue等js的数据绑定机制来展示页面数据,爬虫获取到的html是你的模型页面而不是最终数据的渲染页面, ...

  2. web api 二

    接着上一回说,上回说到,web api有几种访问方式,具体有几种,我还真没去研究过,但是这里打算从get.post.put.delete四种请求方式分别谈谈基础类型(包括int/string/date ...

  3. 致创业者:APP已死 服务永生

    前几日,有位创业者和我讲他在带领团队做一个将爱踢球的人集中在一起的App,我告诉他你的创业方向错了.原因在于你的目的是要为爱踢球的人提供服务,而你现在却在竭尽全力的做App,你应该做的是设计你为爱踢球 ...

  4. IPython、Notebook、qtconsole使用教程

    IPython.Notebook.qtconsole使用教程 上一篇为Python,IPython,qtconsole,Notebook,Jupyter快速安装教程 1. 使用IPython 自动补全 ...

  5. 深度优先搜索DFS和广度优先搜索BFS简单解析

    转自:https://www.cnblogs.com/FZfangzheng/p/8529132.html 深度优先搜索DFS和广度优先搜索BFS简单解析 与树的遍历类似,图的遍历要求从某一点出发,每 ...

  6. h5页面长按保存图片

    由于之前几乎没有使用过canvas:今天遇到了一个很棘手的问题.canvas生成后,然后长按保存到手机. 正常的流程应该是先用canvas进行画图,然后再把canvas转成地址,最后再把转化的地址给i ...

  7. Coin Toss(uva 10328,动态规划递推,限制条件,至少转至多,高精度)

    有n张牌,求出至少有k张牌连续是正面的排列的种数.(1=<k<=n<=100) Toss is an important part of any event. When everyt ...

  8. libevent reference Mannual IV --Helper functions and types

    FYI: http://www.wangafu.net/~nickm/libevent-book/Ref5_evutil.html Helper functions and types for Lib ...

  9. NOIp2017——追求那些我一直追求的

    谨以此祭奠我即将爆炸的NOIP2017. $Mingqi\_H\ \ 2017.09.24$ Day -47 突然发现半年来自己从来没有写对过SPFA,最近几天才发现自己的板子一直是错的...赶紧找个 ...

  10. UVA - 11214 Guarding the Chessboard(迭代加深搜索)

    题目: 输入一个n*m的棋盘(n,m<10),某些格子有标记,用最少的皇后守卫(即占据或攻击)所有的标记的格子.输出皇后的个数. 思路: 一开始没有想到用迭代加深搜索,直接dfs结果还没写完就发 ...