web-dev-qa-db-ja.com

macOS Catalinaでの画面記録設定の検出

ユーザーがこのAPIを有効にしたかどうかを検出する信頼できる方法は何ですか?

CGWindowListCreateImageは、画面記録APIが無効になっていても、有効なオブジェクトを返します。可能な組み合わせは複数あり(kCGWindowListOptionIncludingWindowkCGWindowListOptionOnScreenBelowWindow)、一部のみが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が毎年プライバシー設定を常に変更するため、危険です。

   - (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;
        }
    }
19
Marek H

最も好ましい答えは正確ではありません、彼は状態を共有するようないくつかの意味を省きました。

wWDCで答えを見つけることができます( https://developer.Apple.com/videos/play/wwdc2019/701/?time=1007

以下に、WWDCからの抜粋をいくつか示します。ウィンドウ名と共有状態は、ユーザーがアプリを画面記録用に事前承認していない限り使用できません。これは、一部のアプリがウィンドウ名にアカウント名や、より可能性の高いWebページのURLなどの機密データを入れるためです。

- (BOOL)ScreeningRecordPermissionCheck {
    if (@available(macOS 10.15, *)) {
        CFArrayRef windowList = CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly, kCGNullWindowID);
        NSUInteger numberOfWindows = CFArrayGetCount(windowList);
        NSUInteger numberOfWindowsWithInfoGet = 0;
        for (int idx = 0; idx < numberOfWindows; idx++) {

            NSDictionary *windowInfo = (NSDictionary *)CFArrayGetValueAtIndex(windowList, idx);
            NSString *windowName = windowInfo[(id)kCGWindowName];
            NSNumber* sharingType = windowInfo[(id)kCGWindowSharingState];

            if (windowName || kCGWindowSharingNone != sharingType.intValue) {
                numberOfWindowsWithInfoGet++;
            } else {
                NSNumber* pid = windowInfo[(id)kCGWindowOwnerPID];
                NSString* appName = windowInfo[(id)kCGWindowOwnerName];
                NSLog(@"windowInfo get Fail pid:%lu appName:%@", pid.integerValue, appName);
            }
        }
        CFRelease(windowList);
        if (numberOfWindows == numberOfWindowsWithInfoGet) {
            return YES;
        } else {
            return NO;
        }
    }
    return YES;
}
0
lunch-box-run