I'm building a macOS app and trying to confirm whether there's a way for me to remotely wake a Mac so my app can do a small amount of work (using APNs silent notifications or any other technique).
Here's what I want to happen:
- User runs my app on their Mac
- User puts the Mac to sleep (Apple menu > Sleep)
- 30 minutes later, my server sends a push notification (content-available: 1, apns-push-type: background, apns-priority: 5) via APNs to the Mac
- Note: Power Nap and Wake for Network Access are enabled
- The Mac dark-wakes, delivers the notification to my app via
application(_:didReceiveRemoteNotification:), my app gets ~30 seconds to open a WebSocket, do some work, and return - Mac goes back to sleep
So far, I've been able to send silent push notifications to a sleeping Mac, but my app only gets to take action on them after the Mac has been awoken manually. I've tried both silent pushes (content-available: 1, priority 5) and alert pushes (priority 10) with the same result.
After trying every option I can find, I don't believe notifications can wake a sleeping Mac and allow my third-party app to process data, but I really want to be wrong. Can anyone confirm whether or not this is possible?
After trying every option I can find, I don't believe notifications can wake a sleeping Mac and allow my third-party app to process data, but I really want to be wrong. Can anyone confirm whether or not this is possible?
I'll cover a few details below but the short summary is that, no, I don't think this will really work, at least not in a way that's reliably tied to the notification itself.
Getting into some specifics, let me start with some background context:
Wake for Network Access
This particular setting actually controls a ethernet hardware level feature called "Wake-on-LAN" (WoL). How this actually works is that the ethernet controller itself passively monitors the bus watching for a very particular packet (the "magic packet"), waking the machine up if it ever receives it.
The critical point to that is that this ISN'T a generic "wake me up for any traffic" mechanism. It has very specific contents (notably, the device MAC address) and generally only originates from with the local network, not from a remote host. It certainly couldn't be used by APNS to wake the device up, at least not in the general case.
Power Nap
...and that's why Power Nap exists. It lets the machine wake up periodically to take care of maintenance tasks which including push notifications. However, the timing of that does mean that there can be significant latency between when you send the push and when it reaches the device.
However, even IF the push reaches the device, I'm not sure this will work:
The Mac dark-wakes, delivers the notification to my app via application(_:didReceiveRemoteNotification:)
Dark wake has always been an odd edge case for macOS. Historically, macOS didn't implement app suspension (it does to some extent to day, but it's still not widely "used"), which mean sleep/wake are largely "system wide" events. That is, as soon as the system "wakes up", your app is "running", at least in theory. However, the system doesn't actually want apps "doing stuff" during Dark Wake- partly for power reasons, but mostly because of the risk that apps could unintentionally alter the interface state (for example, changing the foreground app) because they thought the user was interacting with the system.
Preventing those kinds of issues are what causes this:
So far, I've been able to send silent push notifications to a sleeping Mac, but my app only gets to take action on them after the Mac has been awoken manually.
The push reached your app during dark wake, but the system had disabled normal event delivery to minimize the disruptions dark wake would have otherwise created. Note that this assume your app is an AppKit app. If your MacCatalyst (and possibly SwiftUI), then your would was already suspended and never woke up at all.
Now, what might work is a Notification Service Extension, as our API contract requires the NSE to run before presentation and the easiest place to run it is when receive the notification, even if we don't plan on immediately presenting it. However, that won't run your main app, so there are limits to what that enables.
__
Kevin Elliott
DTS Engineer, CoreOS/Hardware