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
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 andOtherApp.app
will open as a seperate application in the Dock.Second approach: I've tried to do is use
NSWorkspace
withNSRunningApplication
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]; }
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
- Create an
NSApplication
that communicates withOtherApp.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. - 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. - Somehow access the bundle and dynamically load the
NSApplicationMain
of theOtherApp.app
though I typically can't useNSBundle
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.