Xcode Extension + Helper Mac App + Launch Arguments?

A short preface:


I would like to write an Xcode Source Editor Extension (new in Xcode 8) that, when triggered, launches a companion Mac application I am writing, and passes the Mac application the lines of the source file the user was viewing when they triggered the extension.


The helper Mac application would then provide the user with an interface for performing it's editing features. When the user is done with their changes, they press some sort of a "Save" or "Commit" button, and the changes are then propogated back to the Xcode extension, and then back to the original source file itself.


What I have so far:


I have created a bare-bones Mac application for my helper mac app. All it does currently is, in it's applicationDidFinishLaunching(...) implementation in it's Application Delegate, attempts to build a string of the passed in launch arguments, and display that string as the message body of an alert. See below (note I've tried using both ProcessInfo.processInfo.arguments as well as 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()

}


I have created a fairly boiler-plate Xcode extension that, when invoked via the perform(with ...) function, launches my companion Mac helper app. I have tried launching the helper app several ways, including:


Using NSWorkSpace's launchApplication(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")
        }

    }

}


Using a custom Process instance to run a bash command, trying both "open" and "fork":


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()
    }

}


The Problem

I have archived / exported the helper Mac app and put it in the Applications folder. When I build and run the Xcode extension and test it out, the helper Mac app successfuly launches, but it never gets the custom launch arguments in applicationDidFinishLaunching(...).


I have read in several places, including the documentation for the constant keys for NSWorkSpace's configuration options here: https://developer.apple.com/reference/appkit/nsworkspacelaunchconfigurationarguments that "This constant is not available to sandboxed apps."

When I run the same bash from Terminal:

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

The helper app successfuly reads in the passed --args and displays them in the alert.My fear is this simply isn't possible due to App Sandboxing, but I'm hoping there is another solution that I'm missing. Some other alternative approaches that would also work if they're possible:


1. Instead of a helper Mac application, if it is possible to make the Xcode extension itself have an interface, then that would solve the problem right there. However I don't believe this is possible.


2. I could also perhaps launch the helper Mac app, and then communicate with it after it is launched, although again I think perhaps the sandboxing issue may come into play.


For what its worth, I am primarily an iOS developer.


Thanks for any help,

- Adam Eisfeld

Xcode Extension + Helper Mac App + Launch Arguments?
 
 
Q