我开发了一款Mac应用程序,我想在Mac启动后立即启动它。如何以编程方式实现此功能?
我知道launchd,但找不到一个有效的例子。
答案 0 :(得分:2)
以下代码是根据Tim Schroeder撰写的优秀博客文章开发的:The Launch At Login Sandbox Project。实际上或多或少地从那里借来的东西 - 看起来我只需要改变在那里记录消息和字符串,所以如果我从不搞砸它,那它就非常坚固。
我的观点与该帖子不同的是应该没有"帮助"应用程序,即使您希望应用程序在登录时不使用GUI启动。这是不必要的。如果您希望您的应用具有在登录时运行的后台模式或当用户关闭GUI时,您应该将应用切换到附件模式detailed in my answer here.您不需要处理子项目并单独编译可执行文件。只要一个。
无论如何,蒂姆非常有用的代码。它使用首选项面板上的分段控件来打开/关闭应用程序。 segmentedControl值使用cocoa-bindings将控件值绑定到NSUserDefaults,因此这里看到的所有内容都是注册/取消注册应用程序作为登录项,以及错误检查/警报。
- (IBAction)toggleRunAtLogin:(NSSegmentedControl*)sender {
NSLog(@"toggling run at login");
NSUInteger clickedSegment = [sender selectedSegment];
if (clickedSegment == 0) { // ON
// Turn on launch at login
NSLog(@"... to ON");
if (!SMLoginItemSetEnabled ((__bridge CFStringRef)@"com.yourCo.yourApp", YES)) {
NSAlert *alert = [NSAlert alertWithMessageText:@"An error ocurred"
defaultButton:@"OK"
alternateButton:nil
otherButton:nil
informativeTextWithFormat:@"Couldn't add App to launch at login item list."];
[alert runModal];
}
}
if (clickedSegment == 1) { // OFF
// Turn off launch at login
NSLog(@"... to OFF");
if (!SMLoginItemSetEnabled ((__bridge CFStringRef)@"com.yourCo.yourApp", NO)) {
NSAlert *alert = [NSAlert alertWithMessageText:@"An error ocurred"
defaultButton:@"OK"
alternateButton:nil
otherButton:nil
informativeTextWithFormat:@"Couldn't remove App from launch at login item list."];
[alert runModal];
}
}
}
答案 1 :(得分:1)
可以在https://github.com/nfarina/feeds/blob/master/Feeds/LoginItems.m
找到实现此功能的一个很好的例子#import "LoginItems.h"
@implementation LoginItems
// Copied from https://github.com/carpeaqua/Shared-File-List-Example
- (void)enableLoginItemWithLoginItemsReference:(LSSharedFileListRef )theLoginItemsRefs ForPath:(NSString *)appPath {
// We call LSSharedFileListInsertItemURL to insert the item at the bottom of Login Items list.
CFURLRef url = (CFURLRef)[NSURL fileURLWithPath:appPath];
LSSharedFileListItemRef item = LSSharedFileListInsertItemURL(theLoginItemsRefs, kLSSharedFileListItemLast, NULL, NULL, url, NULL, NULL);
if (item)
CFRelease(item);
}
- (void)disableLoginItemWithLoginItemsReference:(LSSharedFileListRef )theLoginItemsRefs ForPath:(NSString *)appPath {
UInt32 seedValue;
CFURLRef thePath = NULL;
// We're going to grab the contents of the shared file list (LSSharedFileListItemRef objects)
// and pop it in an array so we can iterate through it to find our item.
CFArrayRef loginItemsArray = LSSharedFileListCopySnapshot(theLoginItemsRefs, &seedValue);
for (id item in (NSArray *)loginItemsArray) {
LSSharedFileListItemRef itemRef = (LSSharedFileListItemRef)item;
if (LSSharedFileListItemResolve(itemRef, 0, (CFURLRef*) &thePath, NULL) == noErr) {
if ([[(NSURL *)thePath path] hasPrefix:appPath]) {
LSSharedFileListItemRemove(theLoginItemsRefs, itemRef); // Deleting the item
}
// Docs for LSSharedFileListItemResolve say we're responsible
// for releasing the CFURLRef that is returned
if (thePath != NULL) CFRelease(thePath);
}
}
if (loginItemsArray != NULL) CFRelease(loginItemsArray);
}
- (BOOL)loginItemExistsWithLoginItemReference:(LSSharedFileListRef)theLoginItemsRefs ForPath:(NSString *)appPath {
BOOL found = NO;
UInt32 seedValue;
CFURLRef thePath = NULL;
// We're going to grab the contents of the shared file list (LSSharedFileListItemRef objects)
// and pop it in an array so we can iterate through it to find our item.
CFArrayRef loginItemsArray = LSSharedFileListCopySnapshot(theLoginItemsRefs, &seedValue);
for (id item in (NSArray *)loginItemsArray) {
LSSharedFileListItemRef itemRef = (LSSharedFileListItemRef)item;
if (LSSharedFileListItemResolve(itemRef, 0, (CFURLRef*) &thePath, NULL) == noErr) {
if ([[(NSURL *)thePath path] hasPrefix:appPath]) {
found = YES;
break;
}
// Docs for LSSharedFileListItemResolve say we're responsible
// for releasing the CFURLRef that is returned
if (thePath != NULL) CFRelease(thePath);
}
}
if (loginItemsArray != NULL) CFRelease(loginItemsArray);
return found;
}
// Our code
+ (LoginItems *)userLoginItems {
static LoginItems *userItems = nil;
return userItems ?: (userItems = [LoginItems new]);
}
- (BOOL)currentAppLaunchesAtStartup {
NSString * appPath = [[NSBundle mainBundle] bundlePath];
LSSharedFileListRef loginItems = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL);
BOOL exists = [self loginItemExistsWithLoginItemReference:loginItems ForPath:appPath];
CFRelease(loginItems);
return exists;
}
- (void)setCurrentAppLaunchesAtStartup:(BOOL)currentAppLaunchesAtStartup {
NSString * appPath = [[NSBundle mainBundle] bundlePath];
LSSharedFileListRef loginItems = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL);
if (loginItems) {
if (!self.currentAppLaunchesAtStartup)
[self enableLoginItemWithLoginItemsReference:loginItems ForPath:appPath];
else
[self disableLoginItemWithLoginItemsReference:loginItems ForPath:appPath];
CFRelease(loginItems);
}
}
@end
答案 2 :(得分:0)
我找到了解决方案 感谢强>
- (void)enableLoginItemWithLoginItemsReference:(LSSharedFileListRef)theLoginItemsRefs ForPath:(NSString *)appPath {
// We call LSSharedFileListInsertItemURL to insert the item at the bottom of Login Items list.
CFURLRef url = (__bridge CFURLRef)[NSURL fileURLWithPath:appPath];
LSSharedFileListItemRef item = LSSharedFileListInsertItemURL(theLoginItemsRefs, kLSSharedFileListItemLast, NULL, NULL, url, NULL, NULL);
if (item)
CFRelease(item);
}
- (void)disableLoginItemWithLoginItems {
UInt32 seedValue;
CFURLRef thePath = NULL;
NSString * appPath = [[NSBundle mainBundle] bundlePath];
// Create a reference to the shared file list.
LSSharedFileListRef loginItems = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL);
// We're going to grab the contents of the shared file list (LSSharedFileListItemRef objects)
// and pop it in an array so we can iterate through it to find our item.
CFArrayRef loginItemsArray = LSSharedFileListCopySnapshot(loginItems, &seedValue);
for (id item in (__bridge NSArray *)loginItemsArray) {
LSSharedFileListItemRef itemRef = (__bridge LSSharedFileListItemRef)item;
if (LSSharedFileListItemResolve(itemRef, 0, (CFURLRef*) &thePath, NULL) == noErr) {
if ([[(__bridge NSURL *)thePath path] hasPrefix:appPath]) {
LSSharedFileListItemRemove(loginItems, itemRef); // Deleting the item
}
// Docs for LSSharedFileListItemResolve say we're responsible
// for releasing the CFURLRef that is returned
if (thePath != NULL) CFRelease(thePath);
}
}
if (loginItemsArray != NULL) CFRelease(loginItems);
}
- (BOOL)loginItemExistsWithLoginItemReference:(LSSharedFileListRef)theLoginItemsRefs ForPath:(NSString *)appPath {
BOOL found = NO;
UInt32 seedValue;
CFURLRef thePath = NULL;
// We're going to grab the contents of the shared file list (LSSharedFileListItemRef objects)
// and pop it in an array so we can iterate through it to find our item.
CFArrayRef loginItemsArray = LSSharedFileListCopySnapshot(theLoginItemsRefs, &seedValue);
for (id item in (__bridge NSArray *)loginItemsArray) {
LSSharedFileListItemRef itemRef = (__bridge LSSharedFileListItemRef)item;
if (LSSharedFileListItemResolve(itemRef, 0, (CFURLRef*) &thePath, NULL) == noErr) {
if ([[(__bridge NSURL *)thePath path] hasPrefix:appPath]) {
found = YES;
break;
}
// Docs for LSSharedFileListItemResolve say we're responsible
// for releasing the CFURLRef that is returned
if (thePath != NULL) CFRelease(thePath);
}
}
if (loginItemsArray != NULL) CFRelease(loginItemsArray);
return found;
}