老谭笔记

在SandBox沙盒下实现程序的开机启动

之前我们实现程序开机启动一般都是通过LSSharedFileList.h中的相应的方法将程序写入到启动项中。但在沙盒模式下因为权限的问题就再也不能实现这样的功能了,现在找到了一个新的方法来实现SandBox下的开机启动。

1.引入ServiceManagement.framework
2.创建一个新的Target,模块为一般的CocoaApplication就行了(称它为Helper吧)
3.在该Helper的Info中设置Application is background only(最好让它一个Window也没有)
4.在主程序中设计CopyFiles如下:

5.为防止Helper签名错误,在主工程中的Strip Debug Symbols During Copy都设置为No,如下:

6.解决Xcode 在提交时会出现错误“xxx does not contain a single–bundle application or contains multiple products” archive错误,所以需要设置Helper工程中的Skip Install ,如图:

7.在你需要设置开机启动的地方使用代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
NSString *helperPath = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:@"Contents/Library/LoginItems/yourHelper.app"];
if (![[NSFileManager defaultManager] fileExistsAtPath:helperPath])
{
return;
}
NSURL *helperUrl = [NSURL fileURLWithPath:helperPath];
// Registering helper app
if (LSRegisterURL((__bridge CFURLRef)helperUrl, true) != noErr)
{
NSLog(@"LSRegisterURL failed!");
}
// Setting login
// com.xxx.xxx为Helper的BundleID,ture/false设置开启还是关闭
if (!SMLoginItemSetEnabled((CFStringRef)@"com.xxx.xxx",ture))
{
NSLog(@"SMLoginItemSetEnabled failed!");
}

8.你的Helper的代码便是充当一个主程序的启动器角色,但注意以下的代码是获取的主程序的可执行文件,否则会出现SandBox的错误,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
NSString *appPath = [[NSBundle mainBundle] bundlePath];
appPath = [appPath stringByReplacingOccurrencesOfString:@"/Contents/Library/LoginItems/Helper.app" withString:@""];
appPath = [appPath stringByAppendingPathComponent:@"Contents/MacOS/mainApp"];
if (![[NSFileManager defaultManager] fileExistsAtPath:appPath])
{
return;
}
NSArray *runningArray = [NSRunningApplication runningApplicationsWithBundleIdentifier:@"com.xxx.mainapp"];
if ([runningArray count] > 0)
{
return;
}
[[NSWorkspace sharedWorkspace] launchApplication:appPath];

注意事项:你的主程序必须在Application的目录下,开机启动的设置才会生效,否则会失败。