Как определить, было ли запущено приложение Mac Cocoa нормально или как элемент входа?

#cocoa #macos

#cocoa #macos

Вопрос:

Есть ли какой-либо способ определить, было ли запущено приложение Cocoa как элемент журнала, а не двойным щелчком по нему?

Ответ №1:

Когда приложение запускается без документа для открытия или печати, оно получает 'oapp' (он же kAEOpenApplication ) событие Apple. Это событие может иметь параметр property data ( keyAEPropData ). При обычном запуске этот параметр отсутствует или равен 0. Для запуска из элемента входа это keyAELaunchedAsLogInItem . (Когда ваше приложение запускается для предоставления услуги, это keyAELaunchedAsServiceItem .)

https://developer.apple.com/legacy/library/documentation/Carbon/Reference/Apple_Event_Manager/index.html#//apple_ref/doc/constant_group/Launch_Apple_Event_Constants

Вы можете проверить это с помощью следующего кода в вашем -applicationWill/DidFinishLaunching: методе:

 NSAppleEventDescriptor* event = [[NSAppleEventManager sharedAppleEventManager] currentAppleEvent];
if ([event eventID] == kAEOpenApplication amp;amp;
    [[event paramDescriptorForKeyword:keyAEPropData] enumCodeValue] == keyAELaunchedAsLogInItem)
{
    // you were launched as a login item
}
  

Swift 3:

 let event = NSAppleEventManager.shared().currentAppleEvent
let launchedAsLogInItem =
    event?.eventID == kAEOpenApplication amp;amp;
    event?.paramDescriptor(forKeyword: keyAEPropData)?.enumCodeValue == keyAELaunchedAsLogInItem
  

Комментарии:

1. ссылка теперь недоступна: (

2. Множество материалов в области устаревшей документации Apple нарушено. Похоже, им все равно.

3. @Michael: Хорошо, я отредактировал его, добавив ссылку, которая у меня работает.

4. Спасибо. Кстати, код все еще работает сейчас (в начале 2015 года) — это далеко от нормы для API Apple 😉

5. Не работает в macOS 12 Monterey при запуске ServiceManagement.framework.

Ответ №2:

В проекте Chromium есть некоторый код для этого. Следует описанному здесь подходу, проверяя родительский процесс и список элементов входа.

Комментарии:

1. Для тех, кому лень искать код, это включает вызов ProcessInformationCopyDictionary сначала текущего процесса, чтобы найти родительский, а затем родительского процесса, чтобы выяснить, является ли это процессом окна входа в систему.

2. Здесь также показано, как найти приложение в списке элементов запуска, чтобы увидеть, было ли оно помечено как «скрытый запуск».

Ответ №3:

Насколько мне известно, нет надлежащего способа проверить это, но есть некоторые мысли:

Лучшее решение:

Создайте два разных приложения, например TheApp и TheAppLauncher.
Добавьте приложение в папку applications, а TheAppLaucher — в элементы startup.
Просто запустите приложение с определенным флагом при запуске appplauncher.
Надеюсь, это понятно 🙂

Другой «уродливый» вариант:

Проверьте, действительно ли приложение указано в элементах входа:
https://github.com/carpeaqua/Shared-File-List-Example/

Запишите в журнал точное время запуска приложения.
Затем сравните это с последним входом пользователя в систему.
Команда finger предоставляет эту информацию (используйте NSTask).
Хорошее изменение, оно запускается как элемент входа в систему, когда разница невелика.
Но да, это не совсем надежно 🙂

Ответ №4:

Возможно, вы могли бы запустить приложение с опцией, если оно запущено в качестве элемента входа. Например, вызывайте его MyApp.app --startupItem при использовании в качестве элемента запуска и вызывайте без этой опции при регулярном запуске.

Параметры командной строки можно проверить классическим способом C, поскольку они передаются main функции в качестве аргументов.

Комментарии:

1. Мое решение отличается от решения Энн тем, что вам нужно только одно приложение.

2. Я согласен, ваше решение лучше с точки зрения разработчика. Но для удобства пользователя вам лучше использовать метод запуска. Обычный пользователь может добавлять приложения к элементам входа, но он не может использовать дополнительные опции, о которых вы упомянули. Чтобы сделать его еще более удобным для пользователя: проверьте, указано ли приложение в элементах входа, если да, замените его на AppLauncher. Таким образом, пользователь может добавить как TheApp, так и TheAppLaunch с тем же результатом.

3. Хорошая мысль, Энн. Это начинает становиться интересным. Моей следующей идеей было взглянуть на родительский процесс, но это launchd для обоих случаев. Честно говоря, я не просматривал документы Apple об этой проблеме, так что, возможно, я что-то упускаю.

4. Спасибо, ребята. В прошлом я помещал приложения в элементы входа программно, но это довольно опасно, потому что это недокументировано. При выходе Tiger возникло много проблем, и программа добавляла себя при каждом запуске, медленно заполняя диалоговое окно элементов запуска .. по этой причине я не хочу переходить к передаче аргументов, хотя в целом это, вероятно, самое чистое решение. Идея «пальца» на самом деле довольно хороша и не слишком сложна в реализации.. Забавно, что вы можете указать «скрыть» в качестве опции в элементах входа, но я не вижу, как это передается..

Ответ №5:

Настройте элемент входа так, чтобы был установлен флажок «Скрыть», а затем при каждом запуске вашего приложения (awakeFromNib или init) проверяйте, скрыто приложение или нет.

Комментарии:

1. @Raffael Для настройки его скрытия при запуске смотрите Здесь и используйте [NSApp isHidden], чтобы узнать, скрыто приложение или нет.

Ответ №6:

В зависимости от того, что именно вы делаете, NSApplicationLaunchIsDefaultLaunchKey здесь может быть полезно. Это ключ, включенный в NSNotification отправленное applicationDidFinishLaunching: . Из документации:

Значением для этого ключа является NSNumber, содержащий логическое значение. Значение равно NO, если приложение было запущено для открытия или печати файла, для выполнения действия службы, если приложение сохранило состояние, которое будет восстановлено, или если запуск приложения в каком-то другом смысле не был запуском по умолчанию. В противном случае его значением будет YES.

В дополнение к упомянутым случаям, для него также установлено значение NO , если приложение запускается автоматически при входе в систему. Итак, если вы решаете, показывать ли, например, какой-либо элемент интерфейса, этой информации может быть достаточно, чтобы сделать то, что вам нужно.

Проверка [[NSApplication sharedApplication] isHidden] также может быть полезна, если вы хотите узнать, было ли запущено приложение с установленным флажком «скрыть».

Редактировать: при дальнейшем тестировании я не уверен, что это действительно так. Когда приложение открыто нормально, NSApplicationLaunchIsDefaultLaunchKey обычно YES . В тестировании, которое я проводил до сих пор, обычно так и происходит, когда оно запускается автоматически NO . Но ни то, ни другое не всегда верно, поэтому, похоже, этот ключ в конце концов может оказаться бесполезным.

Комментарии:

1. Привет, спасибо за совет. Я немного изучил это в Интернете, но, хотя это должно работать, похоже, что в него вложена ошибка. Кто-то уже открыл радар на нем .. позор; можно подумать, что они уже поддерживают это к настоящему времени.