在macOS Catalina上检测屏幕录制设置 [英] Detecting screen recording settings on macOS Catalina

查看:377
本文介绍了在macOS Catalina上检测屏幕录制设置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

检测用户是否已启用此API的可靠方法是什么?

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

CGWindowListCreateImage也会返回有效对象.可能有多种组合(kCGWindowListOptionIncludingWindowkCGWindowListOptionOnScreenBelowWindow),只有一些组合会返回NULL.

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;
}

唯一可靠的方法是通过CGDisplayStreamCreate,这是有风险的,因为Apple每年都会更改隐私设置.

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;
        }
    }

推荐答案

此处介绍的所有解决方案都以一种或另一种方式存在缺陷.问题的根源在于,您了解窗口的权限(通过窗口列表中的名称)与您了解窗口的进程所有者(例如WindowServer和Dock)之间没有关联.您查看屏幕上像素的权限是两组稀疏信息的组合.

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.

以下是一种启发式方法,涵盖了macOS 10.15.1以来的所有情况:

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);
}

如果未设置canRecordScreen,则需要设置某种对话框,警告用户他们只能看到菜单栏,桌面图片和应用程序自己的窗口.这是我们的应用程序我们如何呈现 href ="https://xscopeapp.com" rel ="noreferrer"> xScope .

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.

这篇关于在macOS Catalina上检测屏幕录制设置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆