Yes, you are correct about the non-admin user. In our case, I think it's either rare or the non-admin user shouldn't be able to update the app in the first place, so I think that's a fair restriction.
We have looked into Sparkle, yes. It was one of the first things we suggested, but we had a few showstoppers: we have a cross-platform core in the app, and it takes care of the downloading, so we only need to apply the downloaded package and not manage the whole flow.
That said, I DID study the heck out of it when you mentioned the executable, and that's where I saw the separate Installer app and it all began to make sense.
I will indeed file an enhancement request - and thank you so much for the guidance.
Post
Replies
Boosts
Views
Activity
OMG you're totally right.
Updating an app doesn't need root privileges at all, it just needs something external.
I moved all of the "terminate + replace + relaunch" code in a separate SwiftUI app that I added as an "auxiliary executable" into the bundle, then just referenced that via Bundle.main, sent along the paths as process arguments, and it does its thing very quickly!
I still need to check to see if the daemon is intact after a replacement, I'll post what I find.
Yea, seems to work from the daemon:
// launch new app
if relaunch {
let configuration = NSWorkspace.OpenConfiguration()
configuration.allowsRunningApplicationSubstitution = false
configuration.createsNewApplicationInstance = true
NSWorkspace.shared.openApplication(at: appURL, configuration: configuration) { app, error in
...
I know, right? I believe we may be taking advantage of a RunLoop queuing?
After we send the message to terminate the old app, we use an AsyncSequence to KVO a change to isTerminated on the NSRunningApplication. Once that happens, we call NSWorkspace.shared.openApplication on the new app. It works.
My guess is that the termination message doesn't get to the daemon right away, it's queued up in its RunLoop until the terminate/launch procedure finishes?
The daemon doesn't terminate itself explicity. Due to the way it's set up, we assumed when the parent app terminates, the daemon will terminate as well. However, this isn't exactly clear, as the daemon also launches the new app after it's confirmed that the old app has terminated... a Catch-22 of sorts?
I've been building this on my development machine, but have discovered VirtualBuddy, so I will try it.
Indeed it is, with the value being Contents/Resources/<daemon name>.
Would I be on the right path in suspecting that because the daemon's binary or wrapper or something else changed that the authorization for it becomes invalid?
Swift concurrency can tighten up this code:
var body: some Scene
{
DocumentGroup(newDocument: { Document() }) { _ in
ContentView()
.onAppear {
Task { @MainActor in NSApplication.shared.windows.last?.toggleFullScreen(nil) }
}
}
}