OS Xで、更新されたバージョンをプルダウンした後、アプリを自動的に再起動するにはどうすればよいですか?
私はいくつかを見回して、launchdがこれを行う可能性のある方法のようですが、私はそれを回避することができないようです。これについて具体的に話している良いリソースも見つからないようです。
これを行うためのスクリプトまたは別のプロセスを作成することもできますが、それはせいぜい不格好なようです。もっと良い解決策があると思います。
OS Xで、更新されたバージョンをプルダウンした後、アプリを自動的に再起動するにはどうすればよいですか?
私はいくつかを見回して、launchdがこれを行う可能性のある方法のようですが、私はそれを回避することができないようです。これについて具体的に話している良いリソースも見つからないようです。
これを行うためのスクリプトまたは別のプロセスを作成することもできますが、それはせいぜい不格好なようです。もっと良い解決策があると思います。
別のプロセスが良い解決策です。Sparkleフレームワークを見てください(ほとんどのアプリは自動更新に使用します)。このスタンドアロンアプリにも使用します-https ://github.com/andymatuschak/Sparkle/blob/master/relaunch.m
ジュリアの答えを拡張するだけで、更新以外の理由でアプリを再起動する必要があったので、Sparkleがどのようにそれを行うかを調べました-
Sparkleの最新バージョン(2011年11月現在)には、SparkleフレームワークのResourcesディレクトリに含まれているfinish_installation.appというプロジェクトターゲットがあります。ホストアプリの一部として実行されているSparkleは、finish_applicationをapplication_supportディレクトリにコピーし、launchedを使用して次のようなバイナリ実行可能ファイルを実行し、ホストプロセス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 );
- (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!");
}