Articles index

Prevent App Nap Programmatically

August 22, 2018

By Jeff Johnson (Developer of StopTheMadness and Underpass)

App Nap is a technology introduced in Mac OS X 10.9 Mavericks. Under certain conditions, such as when an app is not visible on the screen, App Nap automatically puts the app into low power state in order to extend battery life. This can cause problems if the app is performing time-sensitive tasks, which may get delayed or interrupted. Unfortunately, App Nap was designed as opt-out rather than opt-in, which means that App Nap can affect an app even if the developer didn't expect or plan for it. You can see apps going in and out of App Nap by watching the Energy tab in Activity Monitor.

For apps that were compiled with the Mac OS X 10.8 SDK or earlier, the "Prevent App Nap" option appears in the Finder Get Info window, which allowed users to manually disable App Nap. For apps that are compiled with the Mac OS X 10.9 SDK or later, however, the Finder option no longer appears. Fortunately, the 10.9 SDK added API to prevent App Nap programmatically. The API is not difficult to use, but some app developers are unaware of its existence, so I just wanted to mention it here.

Below is some sample code to prevent App Nap while the app is running. This is for the sake of simple illustration; you could also choose to prevent App Nap only while your app is performing certain critical activities. Note that NSActivityUserInitiatedAllowingIdleSystemSleep still allows the Mac to go to sleep according to the user's Energy Saver System Preferences. If you need to prevent system sleep too, use NSActivityUserInitiated instead.

Yes, the code is Objective-C. Deal with it!

@implementation AppDelegate {
    id <NSObject> _activity;
}

-(void)applicationDidFinishLaunching:(NSNotification *)notification {
    NSActivityOptions options = NSActivityUserInitiatedAllowingIdleSystemSleep;
    NSString *reason = @"No napping on the job!";
    _activity = [[NSProcessInfo processInfo] beginActivityWithOptions:options reason:reason];
}

-(void)applicationWillTerminate:(NSNotification *)notification {
    [[NSProcessInfo processInfo] endActivity:_activity];
    _activity = nil;
}

@end

You'll want to make sure to keep a strong reference to the token returned by -[NSProcessInfo beginActivityWithOptions: reason:], because App Nap may resume again automatically when the token is deallocated.

Articles index