Search code examples
macoscocoascreen-recordingmacos-catalina

Detecting screen recording settings on macOS Catalina


What's is a reliable way to detect if user has enabled this API?

CGWindowListCreateImage returns a valid object even if screen recording API is disabled. There are multiple combinations possible (kCGWindowListOptionIncludingWindow, kCGWindowListOptionOnScreenBelowWindow) and only some will return NULL.

- (CGImageRef)createScreenshotImage
{
    NSWindow *window = [[self view] window];
    NSRect rect = [window frame];

    rect.origin.y = NSHeight([[window screen] frame]) - NSMaxY([window frame]);
    CGImageRef screenshot = CGWindowListCreateImage(
                                                    rect,
                                                    kCGWindowListOptionIncludingWindow,
                                                    //kCGWindowListOptionOnScreenBelowWindow,
                                                    0,//(CGWindowID)[window windowNumber],
                                                    kCGWindowImageBoundsIgnoreFraming);//kCGWindowImageDefault
    return screenshot;
}

The only reliable way is through CGDisplayStreamCreate which is risky as Apple always changes privacy settings every year.

   - (BOOL)canRecordScreen
    {
        if (@available(macOS 10.15, *)) {
            CGDisplayStreamRef stream = CGDisplayStreamCreate(CGMainDisplayID(), 1, 1, kCVPixelFormatType_32BGRA, nil, ^(CGDisplayStreamFrameStatus status, uint64_t displayTime, IOSurfaceRef frameSurface, CGDisplayStreamUpdateRef updateRef) {
                ;
            });
            BOOL canRecord = stream != NULL;
            if (stream) { 
              CFRelease(stream); 
            }
            return canRecord;
        } else {
            return YES;
        }
    }

Solution

  • Apple provides direct low level api to check for access and grant access. No need to use tricky workarounds.

    /* Checks whether the current process already has screen capture access */
    @available(macOS 10.15, *)
    public func CGPreflightScreenCaptureAccess() -> Bool
    

    Use the above functions to check for screen capture access.

    if access is not given use the below function to prompt for access

    /* Requests event listening access if absent, potentially prompting */
    @available(macOS 10.15, *)
    public func CGRequestScreenCaptureAccess() -> Bool
    

    Screenshot taken from documentation