Encapsulating and spawning another application and injecting parameters

211 Views Asked by At

My issue is I have a child .app that I'd like to run after injecting some parameters. What want to do is run the app as the parent app (launching it sync and propagate focus/activation events to the child app).

The goal for me is to create an 'parent app' that launches another app, for example OtherApp.app. It should appear as if 'parent app' is OtherApp.app (i.e. not show up as a seperate application in the dock but the windows of OtherApp.app should be contained by 'parent app'). The reason I want to do this is so I can pass some initialization variables to OtherApp.app without modifying the .app itself.


Approaches I have taken

  1. First approach is the simplest. Simply using system(@"VAR=VALUE /Applications/OtherApp.app"). However the issue with this is that the 'parent app' will instantly exit and OtherApp.app will open as a seperate application in the Dock.

  2. Second approach: I've tried to do is use NSWorkspace with NSRunningApplication however that is not synchronous, the issue with this is that the 'parent app' will again instantly die:

    #import <Cocoa/Cocoa.h>
    
    int main(int argc, const char * argv[]) {
        NSRunningApplication* childApp = [[NSWorkspace sharedWorkspace]
                                          openURL:[NSURL fileURLWithPath:@"/Applications/OtherApp.app"]
                                          options:NSWorkspaceLaunchDefault|NSWorkspaceLaunchWithoutAddingToRecents
                                          configuration:@{
                                              NSWorkspaceLaunchConfigurationEnvironment: @{
                                                      @"VAR": @"VALUE"
                                              }
                                          } error:NULL];
    }
    
  3. Third approach is using Launch Services. However this is what my question is asking— I can't find any undeprecated API that lets me pass environment variables or "Launch Services Keys" (e.g. LSUIElement) nor can I find a way that lets me pass environment variables. This also instantly exits (I'm not to familiar with Launch Services' internals, perhaps someone can enlighten me?)

    #import <Cocoa/Cocoa.h>
    
    int main(int argc, const char * argv[]) {
        LSLaunchURLSpec launchSpec;
        launchSpec.appURL = CFBridgingRetain([NSURL fileURLWithPath:@"/Applications/OtherApp.app"]);
        launchSpec.asyncRefCon = NULL;
        launchSpec.launchFlags = kLSLaunchDefaults;
        launchSpec.passThruParams = NULL;
        // Where can I specify environment vars or args?
        return LSOpenFromURLSpec(&launchSpec, NULL);
    }
    

Possible solutions

  1. Create an NSApplication that communicates with OtherApp.app so 'parent app' doesn't exit immediately. Problems here are that, again, now they are two apps in the dock and also keeping focus in sync seems like it would be a more complex task.
  2. Figure out how to pass environment variables to LS (Launch Services) APIs along with somehow being able to control the focus of the spawned app.
  3. Somehow access the bundle and dynamically load the NSApplicationMain of the OtherApp.app though I typically can't use NSBundle with an executable (it throws an error saying so).

Right now #2 feels like the best bet though any assistance on alternative solutions would be greatly appreciated.

0

There are 0 best solutions below