自动更新后重启我的应用程序?

时间:2010-11-24 19:32:16

标签: cocoa macos launchd application-restart

在OS X中,如何在下载更新版本后自动重新启动我的应用程序?

我环顾了一些并且启动似乎可能是这样做的方式,但我似乎无法理解它。我似乎无法找到任何有关此问题的好资源。

我还可以创建一个脚本或单独的进程来执行此操作,但这看起来很笨拙,我期待有更好的解决方案。

3 个答案:

答案 0 :(得分:3)

单独的流程是一个很好的解决方案,看看Sparkle框架(大多数应用程序使用它进行自动更新),它们也用于这个独立的应用程序 - https://github.com/andymatuschak/Sparkle/blob/master/relaunch.m

答案 1 :(得分:2)

只是扩展朱莉娅的答案,因为我不得不重新启动我的应用程序而不是更新,我研究了Sparkle是如何做到的 -

Sparkle的最新版本(截至2011年11月)有一个名为finish_installation.app的项目目标,它包含在Sparkle框架的Resources目录中。 Sparkle作为主机App的一部分运行,将finish_application复制到application_support目录,并使用launch来运行这样的二进制可执行文件,传入主机进程ID并重新启动路径:

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];

看起来像这个函数,当父进程退出(?)时,finish_application的父进程就会启动。

finish_installation等待传入的进程id消失,同时进行初始检查以查看它的父进程是否已启动(pid = 1)

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

然后启动应用程序:

[[NSWorkspace sharedWorkspace] openFile: appPath];

最后一个有趣的消息:如果安装需要很长时间,则finish_installation会将自身更改为前台进程,以便用户可以看到某些应用正在运行:

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

答案 2 :(得分:0)

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!");
    }