Detecting screen recording settings on macOS Catalina

后端 未结 7 1564
清歌不尽
清歌不尽 2020-11-30 23:01

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 disable

7条回答
  •  天涯浪人
    2020-11-30 23:38

    All of the solutions presented here have a flaw in one way or another. The root of the problem is that there's no correlation between your permission to know about a window (via the name in the window list), your permission to know about the process owner of the window (such as WindowServer and Dock). Your permission to view the pixels on screen is a combination of two sparse sets of information.

    Here is a heuristic that covers all the cases as of macOS 10.15.1:

    BOOL canRecordScreen = YES;
    if (@available(macOS 10.15, *)) {
        canRecordScreen = NO;
        NSRunningApplication *runningApplication = NSRunningApplication.currentApplication;
        NSNumber *ourProcessIdentifier = [NSNumber numberWithInteger:runningApplication.processIdentifier];
    
        CFArrayRef windowList = CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly, kCGNullWindowID);
        NSUInteger numberOfWindows = CFArrayGetCount(windowList);
        for (int index = 0; index < numberOfWindows; index++) {
            // get information for each window
            NSDictionary *windowInfo = (NSDictionary *)CFArrayGetValueAtIndex(windowList, index);
            NSString *windowName = windowInfo[(id)kCGWindowName];
            NSNumber *processIdentifier = windowInfo[(id)kCGWindowOwnerPID];
    
            // don't check windows owned by this process
            if (! [processIdentifier isEqual:ourProcessIdentifier]) {
                // get process information for each window
                pid_t pid = processIdentifier.intValue;
                NSRunningApplication *windowRunningApplication = [NSRunningApplication runningApplicationWithProcessIdentifier:pid];
                if (! windowRunningApplication) {
                    // ignore processes we don't have access to, such as WindowServer, which manages the windows named "Menubar" and "Backstop Menubar"
                }
                else {
                    NSString *windowExecutableName = windowRunningApplication.executableURL.lastPathComponent;
                    if (windowName) {
                        if ([windowExecutableName isEqual:@"Dock"]) {
                            // ignore the Dock, which provides the desktop picture
                        }
                        else {
                            canRecordScreen = YES;
                            break;
                        }
                    }
                }
            }
        }
        CFRelease(windowList);
    }
    

    If canRecordScreen is not set, you'll need to put up some kind of dialog that warns the user that they'll only be able to see the menubar, desktop picture, and the app's own windows. Here's how we presented it in our app xScope.

    And yes, I'm still bitter that these protections were introduced with little regard to usability.

提交回复
热议问题