简介
建议不要默认就开启自启动,可以放到设置中,让用户自己选择开启/关闭。
Mac OS上运行的App,想要支持用户登录后App自动启动的功能,可以使用Service Management Framework 或 Shared File List实现。对于沙箱开启的应用,苹果推荐的做法是使用Service Management Framework;对于沙箱未开启的应用,苹果推荐使用Shared File List。Service Management Framework对于沙箱未开启的APP也是可以实现登录后自动启动的。二者的区别主要如下:
.使用Service Management Framework方式添加的登录项不会显示在系统偏好设置->用户与群组->登录项中,只有把应用.app文件移到废纸篓,自动启动才会失效。
.使用System Preferences方式添加的登录项会显示在系统偏好设置->用户与群组->登录项中,因此可以勾选隐藏按钮来控制自动启动的功能是否生效。
以下是Service Management Framework的实现方式
步骤
1.在主项目中添加target
我们需要注册一个Helper Target App用来作为开机自启动我们的NeewerLiveProject(主项目),点击Targets下面的加号,添加一个新的OS X APP。取名为NeewerLiveHelper(帮助项目)
2.分别开启NeewerLiveProject和NeewerLiveHelper的App Sandbox,注意两边的设置要一致
3.配置属性
-
删除NeewerLiveHelper(帮助项目)中的windows,让它没有可展示的Window。
-
设置NeewerLiveHelper(帮助项目)的Info中Application is background only为YES
-
在NeewerLiveProject(主项目)中添加CopyFile到Contents/Library/LoginItems
-
在NeewerLiveProject(主项目)中设置Build Setting 下Strip Debug Symbols During Copy为NO, 这个是默认的为No
-
在NeewerLiveProject(主项目)链接所需要的库Cocoa.framwork 和ServiceManagerment.framework
4.代码添加
- 主项目NeewerLiveProject AppDelegate方法中
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
//在启动主项目的时候 发送通知 关闭帮助程序
[[NSDistributedNotificationCenter defaultCenter]postNotificationName:@"TerminateAppHelperNotificationName" object:[NSBundle mainBundle].bundleIdentifier];
}
- 主项目NeewerLiveProject 控制自启动的开关方法中
//根据开关状态控制是否启动自启动
- (void) setAppAutoStart:(BOOL) isAutoStart
{
//这里注意改成自己的帮助工程名称
NSString *helperPath = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:@"Contents/Library/LoginItems/帮助工程.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!");
}
// 这里是帮助项目的bundle identifier
//SMLoginItemSetEnabled注册开机自启动项 传入两个参数 第一个帮助程序可执行包的标识符。第二个表示辅助可执行文件状态的布尔值。该值仅对当前登录的用户有效。如果YES,帮助工具可立即执行(并在后续登录时)并保持运行。如果NO,辅助可执行文件停止。
if (!SMLoginItemSetEnabled((CFStringRef)@"helper.bunduleID",isAutoStart))
{
NSLog(@"SMLoginItemSetEnabled failed!");
}
BOOL alreadRunning = NO;
NSArray *runnings = [NSWorkspace sharedWorkspace].runningApplications;
for (NSRunningApplication *app in runnings) {
//这里是帮助项目的bundle identifier
if ([app.bundleIdentifier isEqualToString:@"helper.bunduleID"]) {
alreadRunning = YES;
break;
}
}
if (alreadRunning) {
//发送终止帮助程序的通知
[[NSDistributedNotificationCenter defaultCenter]postNotificationName:@"TerminateAppHelperNotificationName" object:[NSBundle mainBundle].bundleIdentifier];
}
}
- 在帮助项目NeewerLiveHelper AppDelegate方法中
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
//主项目的bundle identifier
NSString *mainAPP = @"mainApp.bunduleID";
BOOL alreadRunning = NO;
NSArray *runnings = [NSWorkspace sharedWorkspace].runningApplications;
for (NSRunningApplication *app in runnings) {
if ([app.bundleIdentifier isEqualToString:mainAPP]) {
alreadRunning = YES;
break;
}
}
if (!alreadRunning) {
//这里是注册的关闭帮助程序的通知监听
[[NSDistributedNotificationCenter defaultCenter] addObserver:self
selector:@selector(terminate) name:@"TerminateAppHelperNotificationName" object:mainAPP];
NSString *appPath = [[NSBundle mainBundle] bundlePath];
//这里是帮助程序的路径
appPath = [appPath stringByReplacingOccurrencesOfString:@"/Contents/Library/LoginItems/帮助程序.app" withString:@""];
//这里是主程序的路径
appPath = [appPath stringByAppendingPathComponent:@"Contents/MacOS/NeewerLiveProject(主程序)"];
if (![[NSFileManager defaultManager] fileExistsAtPath:appPath])
{
return;
}
[[NSWorkspace sharedWorkspace] launchApplication:appPath];
}else{
[self terminate];
}
}
- (void)terminate{
[NSApp terminate:nil];
}
5.测试
运行程序,打开自己项目中自动启动的开关。接下来就可以重新启动电脑看应用程序是否重启成功。
.在终端输入命令查看自启动是否注册成功 launchctl print-disabled “user/$(id -u)”
特别注意
1.打包测试,主程序必须移到Application目录下
2.需要把电脑内的所有的主程序包删除掉,避免路径冲突造成自启动失败
例如
.~Library/Developer/Xcode/Archives中的包
.~Library/Developer/Xcode/DerivedData中的包
.下载文件中的包
.废纸篓中的包
3.以下还未得到验证
在发布app时,遇到因为使用了testHelper证书而导致上传到app store时的错误,这时需要深入到“…/Products/Applications/test.app/Contents/Library/LoginItems/testHelper.app/Contents”目录下,删除embedded.provisionprofile文件,就可以正确上传了。