I have a macOS app that embeds a helper app in its bundle. That helper app is started by the main app, and from then on it runs independently.
I noticed that after updating the main app from the Mac App Store, while the helper app is running, it is not auto-restarted, unlike the main app.
What is the correct way to handle this?
The main app's bundle looks like this:
Main.app
- Contents
- MacOS
- Main
- Helper.app
Actually, there are two helper apps, one is the menu bar app (the main app configures it), and another one is the background service app refreshing data for the main app, the menu bar, and the system widgets where the app is available too.
The main app launches them with NSWorkspace.open(_ url: URL.
My expectation is that when I press the "Update" button on the Mac App Store, the helper apps will be relaunched since they were updated with its parent bundle's app.
Got it. Basically, no, the system doesn't do that. The system terminates "related apps" for the same reason it terminates your primary app, which is that it's the easiest way to minimize the potential for odd bugs/failures/issue*. However, the problem with relaunching secondary processes post-update is that it doesn't know how/why/what that process actually "does", so launching it could simply create more problems. So, again, it takes the easy/safe way out and does nothing.
*Yes, nothing actually REQUIRES an app to not be running when it's updated. Yes, it is possible to delete an actively running process/app. What can I say, Unix can be weird.
Looking at your specific helpers:
one is the menu bar app (the main app configures it),
Is the main app the only thing launching it, or is it set up as a login item? If it's set up as a login item and not being relaunched, then there are two more points I'd add here:
-
Please file a bug on the fact it's not being relaunched and then post the bug number back here. Relaunching it seems reasonable (though I could argue both sides of that...) and, while I'm not sure we'll fix it (see #2), bugs are always a good idea.
-
Assuming you (and your users) want this to be running "all the time" then I'd suggest moving to a SMAppService and agent(plistName:). The launchd plist gives you a lot more configurability, including the ability to have launchd relaunch you if/when your process stops running. See the manpage for "launchd.plist" for more details on that.
Login Items vs LaunchAgents
As some background here, you may be wondering why the system has two different names/mechanisms for what are basically "the same thing". Basically, this is a case of two completely unrelated mechanisms that were designed for very different problems, which have slowly evolved together. More specifically:
-Login Items were a user level feature that came from MacOS classic. The user told us what he wanted to launch and we'd launch that app for them. Eventually, app started adding themselves to the plist (so user didn't have to) and SMLoginItemSetEnabled was then added so sandboxed apps could provide that kind of functionality.
-LaunchAgents came later (10.4) and are the launchd architecture for managing processes that are tied to the "user session". Things like the Finder and the Dock are actually managed as LaunchAgents by launchd. The reason they relaunch when you terminate them is because that's what they're plist file told launchd to do. If you're curious, you can find their plist in "/System/Library/LaunchAgents/".
Eventually, launchd also took over launching Login Items and then, most recently, we created a common API for both of them in SMAppService. In any case, the main thing to understand here is that since SMAppService was introduced, a Login Item is basically just a less configurable variant of a LaunchAgent. If it does what you need, feel free to use it.
__
Kevin Elliott
DTS Engineer, CoreOS/Hardware