Расширение Xcode + вспомогательное приложение Mac + аргументы запуска?

Примечание. Похоже, здесь существует аналогичный вопрос: Запустить вспомогательное приложение с аргументами запуска в песочнице, но я привожу более подробный пример с исходным кодом ниже.

Краткое предисловие:

Я хотел бы написать расширение редактора исходного кода Xcode (новое в Xcode 8), которое при запуске запускает сопутствующее приложение Mac, которое я пишу, и передает приложению Mac строки исходного файла, который пользователь просматривал, когда они запускали расширение .

Затем вспомогательное приложение Mac предоставит пользователю интерфейс для выполнения функций редактирования. Когда пользователь завершает свои изменения, он нажимает какую-то кнопку «Сохранить» или «Зафиксировать», и затем изменения распространяются обратно в расширение Xcode, а затем обратно в исходный исходный файл.

Что у меня есть на данный момент:

Я создал простое приложение Mac для своего вспомогательного приложения Mac. Все, что он делает в настоящее время, в его реализации applicationDidFinishLaunching(...) в его делегате приложения пытается построить строку переданных аргументов запуска и отобразить эту строку как тело сообщения предупреждения. См. ниже (обратите внимание, я пытался использовать как ProcessInfo.processInfo.arguments, так и CommandLine.arguments):

func applicationDidFinishLaunching(_ aNotification: Notification) {  

    let args = ProcessInfo.processInfo.arguments  

    var argString = ""  
    for arg in args {  
        argString += ", \(arg)"  
    }  

    let alert = NSAlert()  
    alert.addButton(withTitle: "OK")  
    alert.messageText = argString  
    alert.runModal()  

}  

Я создал довольно стандартное расширение Xcode, которое при вызове с помощью функции execute(with...) запускает вспомогательное приложение для Mac. Я пытался запустить вспомогательное приложение несколькими способами, в том числе:

Используя launchApplication NSWorkSpace(at: options: configuration:) :

class SourceEditorCommand: NSObject, XCSourceEditorCommand {  

    func perform(with invocation: XCSourceEditorCommandInvocation, completionHandler: @escaping (Error?) -> Void ) -> Void {  

        defer {  
            completionHandler(nil)  
        }  

        guard let url = NSWorkspace.shared().urlForApplication(withBundleIdentifier: "com.something.TestMacApp") else {  
            print("Couldn't find URL")  
            return  
        }  

        let options: NSWorkspaceLaunchOptions = NSWorkspaceLaunchOptions()  

        var configuration: [String: Any] = [String: Any]()  
        configuration["foo"] = "bar"  
        configuration[NSWorkspaceLaunchConfigurationArguments] = ["foobar"]  
        configuration[NSWorkspaceLaunchConfigurationEnvironment] = ["innerFoo" : "innerBar"]  

        do {  
            try NSWorkspace.shared().launchApplication(at: url, options: options, configuration: configuration)  
        } catch {  
            print("Failed")  
        }  

    }  

}  

Использование пользовательского экземпляра процесса для запуска команды bash с попыткой "открыть" и "разветвить":

class SourceEditorCommand: NSObject, XCSourceEditorCommand {  

    func perform(with invocation: XCSourceEditorCommandInvocation, completionHandler: @escaping (Error?) -> Void ) -> Void {  

        defer {  
            completionHandler(nil)  
        }  

        runCommand(command: "open -b com.something.TestMacApp --args --foo=\"bar\"")  

    }  

    func runCommand(command: String) {  
        let task = Process()  
        task.launchPath = "/bin/sh"  
        task.arguments = ["-c", command]  
        task.launch()  
    }  

}  

Проблема

Я заархивировал / экспортировал вспомогательное приложение Mac и поместил его в папку «Приложения». Когда я создаю и запускаю расширение Xcode и тестирую его, вспомогательное приложение Mac успешно запускается, но оно никогда не получает настраиваемые аргументы запуска в applicationDidFinishLaunching(...).

Я читал в нескольких местах, в том числе документацию по постоянным ключам для параметров конфигурации NSWorkSpace здесь: https://developer.apple.com/reference/appkit/nsworkspacelaunchconfigurationarguments, что «Эта константа недоступна для изолированных приложений».

Когда я запускаю тот же bash из терминала:

open -b com.something.TestMacApp --args --foo="bar"

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

  1. Вместо вспомогательного приложения Mac, если можно сделать так, чтобы само расширение Xcode имело интерфейс, то это решило бы проблему прямо здесь. Однако я не верю, что это возможно.

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

Как бы то ни было, я в первую очередь iOS-разработчик.

Спасибо за любую помощь,

  • Адам Эйсфельд

person Adam Eisfeld    schedule 30.10.2016    source источник
comment
Удалось ли вам закончить это (двусторонняя связь между приложением и расширением)? Я пытаюсь добиться чего-то подобного — upwork.com/jobs/_~0121fceaab6de2ebcd   -  person Crulex    schedule 30.06.2017


Ответы (1)


Во-первых, вы делаете это неправильно. Правильный (как и в том, что Apple говорит использовать) способ запуска приложения-контейнера состоит в том, чтобы сделать следующее:

  1. В Info.plist приложения-контейнера поместите что-то похожее на следующее (измените com.cannasoftware.RoboDocument на соответствующее имя приложения и robodocument007 на строки, соответствующие вашему продукту):

    введите описание изображения здесь

  2. В коде вашего плагина используйте следующее для запуска приложения:

    let customurl = NSURL.init(string: "robodocument007://")
    NSWorkspace.shared().open(customurl as! URL)
    
  3. Используйте стандартное взаимодействие между процессами для обмена сообщениями между вашим приложением и плагином (DistributedNotificationCenter работает здесь достаточно хорошо).

Это не так просто и не так тривиально, как использование аргументов запуска, но я думаю, вы будете довольны результатами.

person Lloyd Sargent    schedule 31.10.2016
comment
Хотя я согласен с тем, что мне следует использовать URL-схемы для запуска моего приложения, особенно потому, что это позволит другим приложениям делать это также стандартизированным способом, суть вопроса заключается в передаче какого-либо вида данных запуска или запуска в приложение, когда это открывает. Использование DistributedNotificationCenter может быть одним из решений этой проблемы, однако прошлой ночью я обнаружил, что могу использовать группы приложений и общие пользовательские настройки по умолчанию для предоставления соответствующей информации запускаемому приложению, что вполне подходит для моих нужд. Я опубликую ответ, демонстрирующий это, когда я вернусь домой с работы. - person Adam Eisfeld; 31.10.2016
comment
@AdamEisfeld, мне было бы интересно увидеть ваше решение с группами приложений! Не могли бы вы опубликовать это? - person Mark A. Donohoe; 14.03.2018
comment
Я предполагаю, что все прошло не так хорошо, как он думал. Иногда, несмотря на то, что вы можете хотеть, следование запрещенной документации Apple работает намного лучше и с меньшими трудностями. - person Lloyd Sargent; 18.03.2018