ユーザーがこのAPIを有効にしたかどうかを検出する信頼できる方法は何ですか?
CGWindowListCreateImage
は、画面記録APIが無効になっていても、有効なオブジェクトを返します。可能な組み合わせは複数あり(kCGWindowListOptionIncludingWindow
、kCGWindowListOptionOnScreenBelowWindow
)、一部のみが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;
}
}
最も好ましい答えは正確ではありません、彼は状態を共有するようないくつかの意味を省きました。
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;
}