We are in the process of sandboxing our app for the Mac App Store. In a non-sandboxed version we rely on launchd plist to automatically restart the app after a crash. How do we retain this ability in a MacApp Store sandboxed version ?
Automatically restarting a Mac App Store sandboxed app
How do we retain this ability in a MacApp Store sandboxed version ?
There isn’t a direct affordance for this in a sandboxed app, I suspect because it’s a pretty unusal requirement. Why are you trying to do this?
ps You could probably make this work by using a Service Management login item — installed using the SMLoginItemSetEnabled(_:_:)
function — to monitor the state of your app and relaunch it if it’s not running. However, I’m not sure what App Review would make of that.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
The best solution to this would be one or more XPC Services. Here is Apple documentation on the topic.
The XPC services work like a normal method call, but the method runs in a separate process. If it crashes, you can restart. Technically speaking, your parent app could still crash, but trying to deal with that is a path of greatest resistance.
You might be able to use a helper app too, but that would involve essentially writing your own XPC architecture. I know XPC works in the Mac App Store. A helper app could add some security/privacy complications, especially for an app like you describe. I think XPC is the way to go.
Also, don't forget about alternative ways to accomplish the same thing. You have a cloud backup app. I suppose you want to ensure that it runs on a given schedule. Create a notification to warn the user that the backup hasn't run and schedule it for after the backup should have run. Then, when the backup completes, delete that notification. Repeat forever. Notifications are user-controllable and, therefore, not reliable. But this is still a good fallback idea.
Not sure why the request would be considered unusual.
Because, for historical reasons, the lifetime of the process running your Mac app is visible to the user. For example, it shows up in the Dock, in the app switcher, and so on. As a user it’s distracting to see these things when all you want to do is running a background service.
Most Mac apps that implement a background service do the heavy lifting in a Service Management login item. This login items is either a UI element (LSUIElement
) or a background-only app (LSBackgroundOnly
), and thus doesn’t show up in the Dock and so on. Use the former if you have limited UI, like a menu bar status item, and the latter if you have no UI.
Service Management login items are an expected feature of Mac App Store apps. Indeed, the SMLoginItemSetEnabled
was API was added specifically for that purpose. I don’t work for App Review, and thus can’t make definitive statements on their behalf, but my experience is that the only significant limitation is a UI one, per clause 2.4.5(iii) of the App Store Review Guidelines.
Unfortunately the system doesn’t relaunch a Service Management login item if it crashes. My advice on that front is to put the bulk of the code in another executable and have the Service Management login item launch that, and relaunch it if it crashes. That way your Service Management login item is super simple, and thus unlikely to crash.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
Even we too have similar kind of issue wherein we don't have a mechanism to relaunch background app which runs continuously in case of crash. We get user consent to run this background app and are using helper app installed via SMLoginItemSetEnabled API to launch background app on subsequent login.
But helper app is terminated once it successfully launches background app.
So @eskimo do you mean we can use the helper app to monitor the state of main app and relaunch it whenever crashes. Can we keep the helper app installed via SMLoginItemSetEnabled API running all the time?
Things have changed a bit in this space with the advent of SMAppService
. Is your app sandboxed? If so, is that because it ships in the Mac App Store? Or because it’s the right thing to do in general?
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
Yes our app is sandboxed and ships to Mac App Store. And yes we did check on SMAppService which support macOS 13 & above but to support older macOS we still use SMLoginItemSetEnabled API. But as we checked the problem still exists even with new SMAppService there's no mechanism to relaunch main app in case of crash..Is our assumption right?
But as we checked the problem still exists
OK.
To advise you further I need a better understanding of the specific problem you’re try to solve here. You wrote:
But helper app is terminated once it successfully launches background app.
AFAIK you have three apps:
-
Your main user visible app
-
Inside that a background app
-
And a helper app, installed as a Service Management login item
Is that right?
If so, why is the helper app terminating? Is it terminating itself? Or is the system terminating it?
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
Yes your understanding is correct.
Helper app it terminated once its launches the background as its job is done. But now we are thinking to keep it running and monitor the background app, relaunch it if crashed.
Now our query is can we keep the helper app running all the time?
Now our query is can we keep the helper app running all the time?
It depends on what you mean by “can”:
-
Are you allowed to? That’s not something I can give definitive answers on, it’s App Review’s call, but my understanding is that they allow apps to run in the background as long as you make the user aware of that behaviour.
-
Really? Well, in macOS 13 the user now has control over this via System Settings.
-
Is it technically possible? Yes. If the Service Management login item doesn’t terminate itself, it’ll keep running until the user logs out.
-
Really? Well, there is an edge case here, namely, it must not crash. If it crashes, the system won’t relaunch it and it’s not easy to relaunch correctly. Which brings me back to my comment earlier, that you should try to keep your Service Management login item as simple as possible and defer any potentially crashy work to some other process.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"