Swift: могу ли я получить информацию для приложения, которое не запущено?

#swift #macos #bundle

#swift #macos #пакет

Вопрос:

Я пишу приложение, в котором хранятся данные о других приложениях. Я могу достаточно легко найти текущее основное приложение и его информацию:

 let frontApp = NSWorkspace.shared.frontmostApplication!
  

и оттуда я могу получить:

 let currentAppName = currentApp.localizedName ?? "Dunno"
let currentAppIcon = currentApp.icon
  

Если приложение не находится на переднем плане, я знаю, что могу перебирать другие запущенные приложения:

 let apps = NSWorkspace.shared.runningApplications
for app in apps as [NSRunningApplication] {
    print(app.localizedName ?? "whatever")
    print(app.bundleIdentifier ?? "bundle")
}
  

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

Ответ №1:

Сначала получите пакет приложения, используя

 let bundleURL = NSWorkspace.shared.urlForApplication(withBundleIdentifier: someBundleID)!
let bundle = Bundle(url: bundleURL)!
  

Получив пакет, вы можете получить большинство вещей, которые вы можете получить из NSRunningApplication :

  • bundleIdentifier вы уже знаете.
  • bundleURL вы только что ознакомились с приведенным выше кодом.
  • executableArchitecture теперь bundle.executableArchitectures во множественном числе. Поскольку оно не запущено, вы получаете все архитектуры, на которых оно может быть запущено, а не конкретную архитектуру, на которой оно запущено.
  • executableURL вы можете получить bundle.executableURL , никаких проблем нет.
  • launchDate , isFinishedLaunching , processIdentifier , ownsMenuBar бессмысленно получать, поскольку приложение не запущено.

Теперь у нас осталось icon и localizedName . Методы, которые я предлагаю для их получения, менее надежны. Чтобы получить icon , выполните

 NSWorkspace.shared.icon(forFile: bundleURL.path)
  

Я уверен, что это дает тот же результат, что и по NSRunningApplication.icon крайней мере в 99% случаев, но я не уверен, есть ли крайние случаи…

Получить localizedName более ненадежно. Есть 2 способа, ни один из которых не подходит. Выберите то, которое лучше всего подходит для ваших целей

  • FileManager.default.displayName(atPath: bundleURL.path) Это дает вам локализованное имя, но если пользователь переименует приложение, оно вернет новое имя, а не имя пакета

  • Получение CFBundleDisplayName из пакета localizedInfoDictionary , возврат к CFBundleName и infoDictionary . По какой-то причине это не дает локализованного имени, хотя я и сказал localizedInfoDictionary .

     let infoDict = (bundle.localizedInfoDictionary ?? bundle.infoDictionary)
    let localizedName = infoDict?["CFBundleDisplayName"] ?? infoDict?["CFBundleName"]
      

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

1. Спасибо за ваш ответ. Это сделало свое дело. Однако я обнаружил, что первый вариант получения имени действительно .app указывал на конец имени. Я знаю, что это не так сложно удалить.