Reputation: 37238
I am running a .app and I need to "restart" it so to speak. Basically I need to tell it to close, then after closing, it should launch the path i tell (which is to itself) with some command line arguments. Is this possible with cocoa? Im getting stuck at the part where my app is closing then closed, then I cant get it back.
My code is in js-ctypes, but here is the objc pseudo code:
default_center = [NSDistributedNotificationCenter defaultCenter];
shared_workspace = [NSWorkspace sharedWorkspace];
notification_center = [[NSWorkspace sharedWorkspace] notificationCenter];
[notification_center addObserver:selector:name:object: ***, ***, NSWorkspaceDidLaunchApplicationNotification, NIL]
And in my observr when it responds with completion of quit it has code to launch. But as my app is closed it never gets to the observer responder. Here
Thanks
Upvotes: 0
Views: 222
Reputation: 345
You didn't mention any reason that you cannot launch a second instance of your app from the first instance, rather than the chicken & egg approach of trying to restart after you've quit... I have this code in my AppWillTerminate function where I have a situation like yours:
[[NSWorkspace sharedWorkspace] launchApplicationAtURL:appUrl options:NSWorkspaceLaunchNewInstance configuration:nil error:&error];
( To get the AppWillTerminate to be called in the first place, I had to disableSuddenTermination before calling [app quit] )
There's also some flag in the app's plist file like "allow multiple instance" or something.
Also, KNOW THIS: if your app is sandboxed, this will not work UNLESS it is code signed with an AppleStore given id, or with a Developer ID Application id. Also, it won't work on X.7 no matter what, when sandboxed.
METHOD TWO,
is to create a "Helper App". Your KillerApp goes through the Quit process, and right before it dies, it launches "HelperApp", which is a tiny command line tool which waits for KillerApp to really die, then relaunches it.
In XCode, the code for the HelperApp, a "Command line tool", is like this:
#import <Cocoa/Cocoa.h>
int main( int argc , char *argv[] ) {
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
pid_t parentPID = atoi(argv[2]);
ProcessSerialNumber psn;
while ( GetProcessForPID(parentPID, &psn) != procNotFound )
sleep(1);
NSString* appPath = [NSString stringWithCString:argv[1] encoding:NSUTF8StringEncoding];
BOOL success = [[NSWorkspace sharedWorkspace] openFile:[appPath stringByExpandingTildeInPath]];
if ( ! success )
NSLog(@"Error: could not relaunch application at %@", appPath);
[pool drain];
return (success) ? 0 : 1;
}
As you can see, you call the HelperApp with a couple parameters from your KillerApp... And in the case where you don't need to be sandboxed, that's about it.
If you DO need sandboxing, then it gets more complicated, of course. You need to create a "privileged helper tool", and thank goodness there is sample code for it.
"SMJobBless" is the Apple sample code project which outlines how to do this, but it's kind of weird-- it doesn't actually DO anything. Thankfully, somebody took that project and created "SMJobBlessXPC" from it, which really does finish the job, ( and when you get it working, your KillerApp can actually communicate with your HelperApp ). The downside is that you need to exactly maintain the plist files of the two apps in terms of code signing.
Upvotes: 1