c++objective-ccmacosrelaunch

How can a Mac GUI app relaunch itself without using Sparkle?


I'm adding a feature to a Mac program to delete its preferences .plist file, and then relaunch with what are effectively "factory settings". However, the customer for this is leery of using external frameworks like Sparkle. I've looked online for sample code, but much of it seems over-complicated (e.g. adding a category to NSApplication). Also, some of it simply won't work in Lion or later, when you can't use some APIs to launch a GUI process from a non-GUI process.

So is there a simple way to have a Mac GUI app relaunch itself?


Solution

  • For Mountain Lion at least, a slightly fancy version of fork/exec works fine:

    void    RelaunchCurrentApp()
    {
        // Get the path to the current running app executable
        NSBundle* mainBundle = [NSBundle mainBundle];
        NSString* executablePath = [mainBundle executablePath];
        const char* execPtr = [executablePath UTF8String];
    
    #if ATEXIT_HANDLING_NEEDED
        // Get the pid of the parent process
        pid_t originalParentPid = getpid();
    
        // Fork a child process
        pid_t pid = fork();
        if (pid != 0) // Parent process - exit so atexit() is called
        {
            exit(0);
        }
    
        // Now in the child process
    
        // Wait for the parent to die. When it does, the parent pid changes.
        while (getppid() == originalParentPid)
        {
            usleep(250 * 1000); // Wait .25 second
        }
    #endif
    
        // Do the relaunch
        execl(execPtr, execPtr, NULL);
    }
    

    I ran into one gotcha, which is that the relaunched app can wind up in the background. Doing this early in the execution fixes that problem:

    [[NSApplication sharedApplication] activateIgnoringOtherApps : YES];