Registre-se como Item de Login com Cocoa?

O Google me deu: http://developer.apple.com/samplecode/LoginItemsAE/index.html

E achei que deve haver uma maneira melhor do que usar events do AppleScript.

Então baixei as fonts do Growl. Eles usam as fonts exatas do artigo do desenvolvedor da Apple.

Existe uma maneira melhor?

(Refiro-me a itens de login em contas nas preferências do sistema, ou seja, fazer o meu programa iniciar quando o usuário faz o login, programaticamente)

Há uma API nova no Leopard chamada LSSharedFileList. Uma das coisas que permite fazer é visualizar e editar a lista Itens de Login (chamados de Itens de Login da Sessão nessa API).

BTW, eu sou o principal desenvolvedor do Growl. Nós ainda não trocamos o AE porque ainda precisamos do Tiger, mas estou pensando em deixar isso para o 1.2 (ainda não falei com os outros desenvolvedores). Quando derrubarmos o Tiger, também descartaremos o LoginItemsAE e mudaremos para a API de lista de arquivos compartilhados.


EDITAR desde o ano de 2012: Desde 2009, quando escrevi originalmente esta resposta, Growl mudou para LSSharedFileList e deixei o projeto.

Eu tropecei no LaunchAtLoginController de Ben Clark-Robinson. Uma solução muito elegante para um problema muito comum.

Isso funciona no xcode 5.

 - (BOOL)isLaunchAtStartup { // See if the app is currently in LoginItems. LSSharedFileListItemRef itemRef = [self itemRefInLoginItems]; // Store away that boolean. BOOL isInList = itemRef != nil; // Release the reference if it exists. if (itemRef != nil) CFRelease(itemRef); return isInList; } - (void)toggleLaunchAtStartup { // Toggle the state. BOOL shouldBeToggled = ![self isLaunchAtStartup]; // Get the LoginItems list. LSSharedFileListRef loginItemsRef = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL); if (loginItemsRef == nil) return; if (shouldBeToggled) { // Add the app to the LoginItems list. CFURLRef appUrl = (__bridge CFURLRef)[NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]]; LSSharedFileListItemRef itemRef = LSSharedFileListInsertItemURL(loginItemsRef, kLSSharedFileListItemLast, NULL, NULL, appUrl, NULL, NULL); if (itemRef) CFRelease(itemRef); } else { // Remove the app from the LoginItems list. LSSharedFileListItemRef itemRef = [self itemRefInLoginItems]; LSSharedFileListItemRemove(loginItemsRef,itemRef); if (itemRef != nil) CFRelease(itemRef); } CFRelease(loginItemsRef); } - (LSSharedFileListItemRef)itemRefInLoginItems { LSSharedFileListItemRef res = nil; // Get the app's URL. NSURL *bundleURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]]; // Get the LoginItems list. LSSharedFileListRef loginItemsRef = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL); if (loginItemsRef == nil) return nil; // Iterate over the LoginItems. NSArray *loginItems = (__bridge NSArray *)LSSharedFileListCopySnapshot(loginItemsRef, nil); for (id item in loginItems) { LSSharedFileListItemRef itemRef = (__bridge LSSharedFileListItemRef)(item); CFURLRef itemURLRef; if (LSSharedFileListItemResolve(itemRef, 0, &itemURLRef, NULL) == noErr) { // Again, use toll-free bridging. NSURL *itemURL = (__bridge NSURL *)itemURLRef; if ([itemURL isEqual:bundleURL]) { res = itemRef; break; } } } // Retain the LoginItem reference. if (res != nil) CFRetain(res); CFRelease(loginItemsRef); CFRelease((__bridge CFTypeRef)(loginItems)); return res; } 

Eu faço isso em um aplicativo que estou escrevendo :

Confira UKLoginItemRegistry para uma maneira fácil de fazer isso pragmaticamente. Afaik, não há como Tiger fazer isso sem os events da Apple; no Leopard há uma maneira melhor, mas se você usar o UKLoginItemRegistry, não há problema. Aqui está o código completo para implementar um item de menu “Abrir no Logon”

 + (bool)isAppSetToRunAtLogon { int ret = [UKLoginItemRegistry indexForLoginItemWithPath:[[NSBundle mainBundle] bundlePath]]; NSLog(@"login item index = %i", ret); return (ret >= 0); } - (IBAction)toggleOpenAtLogon:(id)sender { if ([PopupController isAppSetToRunAtLogon]) { [UKLoginItemRegistry removeLoginItemWithPath:[[NSBundle mainBundle] bundlePath]]; } else { [UKLoginItemRegistry addLoginItemWithPath:[[NSBundle mainBundle] bundlePath] hideIt: NO]; } } 

Eu refatorei algumas das respostas aqui para fornecer uma categoria no NSApplication que forneça uma propriedade launchAtLogin .

https://gist.github.com/joerick/73670eba228c177bceb3

SMLoginItemSetEnabled é outra opção moderna, veja o artigo

Confira aqui um exemplo de código aberto: https://github.com/invariant/rhpnotifier (LoginItem.m, LoginItem.h)