LaunchAgents для приложения с графическим интерфейсом

Я хотел бы запускать свое приложение каждый раз, когда пользователь входит в систему.

Я добавил plist-файл в папку /Libray/LaunchAgents:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
 <key>KeepAlive</key>
 <false/>
 <key> LaunchOnlyOnce</key>
 <true/>
 <key>OnDemand</key>
 <false/>
 <key>RunAtLoad</key>
 <true/>
 <key>Label</key>
 <string>com.mycompany.myapp</string>
 <key>ProgramArguments</key>
 <array>
  <string>/Applications/mayapp.app/Contents/MacOS/myapp</string>
 </array>
</dict>
</plist>

Все выглядит хорошо, приложение загружается, однако, когда я закрываю свое приложение, оно запускается сервисом launchd.

Какой ключ я должен добавить / изменить в моем файле plist, чтобы предотвратить постоянный перезапуск моего приложения.

3 ответа

Если вы хотите запустить обычное приложение при входе в систему, я бы порекомендовал использовать API списка общих файлов LaunchServices, а не launchd. Вместо того, чтобы устанавливать plist launchd, вы можете просто использовать этот API, чтобы добавить свое приложение к элементам входа пользователя (те, которые вы видите на преф-панели "Учетные записи" в Системных настройках). Преимущества этого: а) для пользователя более очевидно, почему приложение запускается при входе в систему, б) пользователю легче удалить его, и в) если пользователь удаляет ваше приложение, launchd будет жаловаться на ошибки консоли. когда не удается запустить (теперь отсутствует) приложение.

Похоже, что нет никакой справочной документации по API, но соответствующие функции находятся в LSSharedFileList.h. Код для этого будет выглядеть примерно так:

#import <CoreServices/CoreServices.h>

...

LSSharedFileListRef loginItemList = LSSharedFileListCreate(kCFAllocatorDefault, kLSSharedFileListSessionLoginItems, NULL);
if (loginItemList != NULL)
{
    LSSharedFileListRef myItem = LSSharedFileListInsertItemURL(loginItemList, kLSSharedFileListItemLast, NULL, NULL, (CFURLRef)[[NSBundle mainBundle] bundleURL], NULL, NULL);
    //We don't do anything with the new item, but we need to release it so it doesn't leak
    if (myItem != NULL)
        CFRelease(myItem);
    CFRelease(loginItemList);
}

Если вы хотите, чтобы этот элемент запускался для всех пользователей, а не только для текущего зарегистрированного пользователя, вы можете использовать kLSSharedFileListGlobalLoginItems вместо kLSSharedFileListSessionLoginItems.

Удалите ключ Keep Alive и запустите ключ только один раз... так как вам нужно запустить приложение только один раз. Вот пример кода для запуска приложения с именем приложения входа в систему.

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"           "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>RunAtLoad</key>
<true/>
<key>Label</key>
<string>com.apple.LoginApp</string>
<key>Program</key>
<string>/Library/Log Files/LoginApp.app/Contents/MacOS/LoginApp</string>
<key>onDemand</key>
<false/>
</dict>
</plist>

Надеюсь это поможет

Я вижу две проблемы: основная из них заключается в том, что у вас есть <key>OnDemand</key><false/>, который говорит launchd, что агент должен быть в живых (и это, кажется, переопределяет <key>KeepAlive</key><false/>, что означает с точностью до наоборот). Вторая проблема заключается в том, что перед именем ключа есть пробел <key> LaunchOnlyOnce</key><true/>, Простое решение: удалите оба ключа OnDemand и LaunchOnlyOnce, и все должно работать нормально.

Другие вопросы по тегам