开发者

restart my app after an auto-update?

开发者 https://www.devze.com 2023-01-26 15:23 出处:网络
In OS X how can I automatically re-start my app after pulling down an updated version? I\'ve looked around some and launchd seems to be the likely way to do this, but I can\'t seem to get my开发者_JA

In OS X how can I automatically re-start my app after pulling down an updated version?

I've looked around some and launchd seems to be the likely way to do this, but I can't seem to get my开发者_JAVA百科 head around it. I can't seem to find any good resources talking about this specifically either.

I could also create a script or separate process to do this, but that seems clunky at best, I'm expecting there is a better solution out there.


Separate process is good solution, look at Sparkle framework (most of apps use it for autoupdating), they also use for this standalone app - https://github.com/andymatuschak/Sparkle/blob/master/relaunch.m


Just expanding on Julia's answer, since I had to restart my App for another reason than updating, I looked into how Sparkle does it -

Latest version(as of 11/2011) of Sparkle has a project target called finish_installation.app that is included in the Resources dir of the Sparkle framework. Sparkle, running as part of the host App, copies finish_application to the application_support directory and uses launched to run its binary executable like this, passing in the host process id and relaunch path:

NSString *relaunchToolPath = [NSString stringWithFormat:@"%@/finish_installation.app/Contents/MacOS/finish_installation", tempDir];
[NSTask launchedTaskWithLaunchPath: relaunchToolPath arguments:[NSArray arrayWithObjects:pathToRelaunch, [NSString stringWithFormat:@"%d", [[NSProcessInfo processInfo] processIdentifier]], tempDir, relaunch ? @"1" : @"0", nil]];
[NSApp terminate:self];

Seems like with this function, when the parent process quits(?), finish_application's parent becomes launched.

finish_installation waits for the passed in process id to disappear, also has an initial check to see if it's parent is launched (pid=1)

if(getppid() == 1)...
if (GetProcessForPID(parentprocessid, &psn) == procNotFound)...

then launches app with:

[[NSWorkspace sharedWorkspace] openFile: appPath];

Last interesting tidbit: If installation takes a long time, finish_installation changes itself to a foreground process so the user can see that some app is running:

ProcessSerialNumber     psn = { 0, kCurrentProcess };
TransformProcessType( &psn, kProcessTransformToForegroundApplication );


Source Blog

- (void) restartOurselves
    {
       //$N = argv[N]
       NSString *killArg1AndOpenArg2Script = @"kill -9 $1 \n open \"$2\"";

       //NSTask needs its arguments to be strings
       NSString *ourPID = [NSString stringWithFormat:@"%d",
                      [[NSProcessInfo processInfo] processIdentifier]];

       //this will be the path to the .app bundle,
       //not the executable inside it; exactly what `open` wants
       NSString * pathToUs = [[NSBundle mainBundle] bundlePath];

       NSArray *shArgs = [NSArray arrayWithObjects:@"-c", // -c tells sh to execute the next argument, passing it the remaining arguments.
                    killArg1AndOpenArg2Script,
                    @"", //$0 path to script (ignored)
                    ourPID, //$1 in restartScript
                    pathToUs, //$2 in the restartScript
                    nil];
       NSTask *restartTask = [NSTask launchedTaskWithLaunchPath:@"/bin/sh" arguments:shArgs];
       [restartTask waitUntilExit]; //wait for killArg1AndOpenArg2Script to finish
       NSLog(@"*** ERROR: %@ should have been terminated, but we are still running", pathToUs);
       assert(!"We should not be running!");
    }
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号