以编程方式启动Mac app

时间:2014-06-12 06:14:11

标签: macos launchd

我开发了一款Mac应用程序,我想在Mac启动后立即启动它。如何以编程方式实现此功能?

我知道launchd,但找不到一个有效的例子。

3 个答案:

答案 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;
}