• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: Quit helper app when main app terminates
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Quit helper app when main app terminates


  • Subject: Re: Quit helper app when main app terminates
  • From: Jerry Krinock <email@hidden>
  • Date: Thu, 12 Jul 2012 13:11:24 -0700

Thanks for all the ideas.

I thought maybe someone would suggest opening up some snazzy inter application communication channel and making the helper exit when it broke (indicating that the main app had terminated).  But since that was not offered, I used a combination of the suggestions and some code I had lying around.  It's all done in the helper…

(1) Register for NSWorkspaceDidTerminateApplicationNotification
(2) In case the main app terminates before that notification gets going, during launch, check that the main app is still running.

This might even work in a sandboxed helper, although, Yay! I'm not sandboxed in this particular case.

On 2012 Jul 12, at 12:50, Sean McBride wrote:

> Although rare, it is possible to have more than one app with the same bundle id running at the same time.

Yes, in case someone launches two instances of my app and quits one, I'd have two helpers running.  But I think that's OK because all the helper does is listen for and forward myapp:// url events, and the system will only send such url event to one of them.

Jerry


The following code assumes that the MyApp-Helper.app is actually a .app with a run loop, etc., and it is packaged in the main app in Contents/<Something>/


@implementation MyHelperAppDelegate

/* Other methods go here */

- (NSString*)mainAppBundleIdentifier {
    NSString* bundlePath = [[NSBundle mainBundle] bundlePath] ;
    // bundlePath = /Applications/MyApp.app/Contents/Helpers/MyApp-Helper.app"
    bundlePath = [bundlePath stringByDeletingLastPathComponent] ;
    // bundlePath = /Applications/MyApp.app/Contents/Helpers/"
    bundlePath = [bundlePath stringByDeletingLastPathComponent] ;
    // bundlePath = /Applications/MyApp.app/Contents/"
    bundlePath = [bundlePath stringByDeletingLastPathComponent] ;
    // bundlePath = /Applications/MyApp.app/"

    NSBundle* bundle = [NSBundle bundleWithPath:bundlePath] ;
    return [bundle bundleIdentifier] ;
}

- (void)handleAppQuit:(NSNotification*)appTerminateNotification {
    NSString* osx_10_5_quitAppBundleIdentifier = [[appTerminateNotification userInfo] objectForKey:@"NSApplicationBundleIdentifier"] ;
    NSString* osx_10_6_quitAppBundleIdentifier = [[[appTerminateNotification userInfo] objectForKey:NSWorkspaceApplicationKey] bundleIdentifier] ;

    NSString *mainAppBundleIdentifier = [self mainAppBundleIdentifier] ;

    if (
        [osx_10_6_quitAppBundleIdentifier isEqualToString:mainAppBundleIdentifier]
        ||
        [osx_10_5_quitAppBundleIdentifier isEqualToString:mainAppBundleIdentifier]
         ) {
        [NSApp terminate:self] ;
    }
}

- (pid_t)pidOfThisUsersAppWithBundleIdentifier:(NSString*)bundleIdentifier {
    pid_t pid = 0 ; // not found

    if (bundleIdentifier) {
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
        // Running the main run loop is necessary for -runningApplications to
        // update.  The next line is actually necessary in tools which may be lacking
        // a running run loop, and it actually works.
        [[NSRunLoop mainRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.01]] ;
        NSArray* runningApps = [[NSWorkspace sharedWorkspace] runningApplications] ;
        for (NSRunningApplication* runningApp in runningApps) {
            if ([[runningApp bundleIdentifier] isEqualToString:bundleIdentifier]) {
                pid = [runningApp processIdentifier] ;
                break ;
            }
        }
#else
        NSArray* appDicts = [[NSWorkspace sharedWorkspace] launchedApplications] ;
        // Note that the above method returns only applications launched by the
        // current user, not other users.  (Not documented, determined by experiment
        // in Mac OS 10.5.5).  Also it returns only "applications", defined as
        // "things which can appear in the Dock that are not documents and are launched
        // by the Finder or Dock"
        // (See documentation of ProcessSerialNumber).
        for (NSDictionary* appDict in [appDicts objectEnumerator]) {
            if ([[appDict objectForKey:@"NSApplicationBundleIdentifier"] isEqualToString:bundleIdentifier]) {
                pid = [[appDict objectForKey:@"NSApplicationProcessIdentifier"] unsignedLongValue] ;
                break ;
            }
        }
#endif
    }

    return pid ;
}

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
    // Begin watching for main app to quit
    NSNotificationCenter* notificationCenter = [[NSWorkspace sharedWorkspace] notificationCenter] ;
    [notificationCenter addObserver:self
                           selector:@selector(handleAppQuit:)
                               name:NSWorkspaceDidTerminateApplicationNotification
                             object:nil] ;
    // Tested in Mac OS X 10.7: That notification is received whether the application
    // quits normally, crashes, or is terminated by a unix signal.

    // Make sure main app did not terminate before we got here
    pid_t pid = [self pidOfThisUsersAppWithBundleIdentifier:[self mainAppBundleIdentifier]] ;
    if (pid == 0) {
        // Main app must have terminated before we finished launching
        [NSApp terminate:self] ;
    }

    // Other code goes here
}

@end
_______________________________________________

Cocoa-dev mailing list (email@hidden)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:

This email sent to email@hidden


References: 
 >Quit helper app when main app terminates (From: Jerry Krinock <email@hidden>)
 >Re: Quit helper app when main app terminates (From: Robert Martin <email@hidden>)
 >Re: Quit helper app when main app terminates (From: Mark Munz <email@hidden>)

  • Prev by Date: Re: Quit helper app when main app terminates
  • Next by Date: Re: How to implement an object whose properties are really dictionary entries.
  • Previous by thread: Re: Quit helper app when main app terminates
  • Next by thread: Re: Quit helper app when main app terminates
  • Index(es):
    • Date
    • Thread