블로그 이미지
devtang
Instagram : @taebr0 devtaehyeong@gmail.com

calendar

1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30

Notice

2024. 2. 7. 19:54 Mac OS Application

회사 제품이 원격 관련 제품이라 macOS에서 앱의 [화면 기록] 권한이 필요하다.

 

업무를 하다가 발생한 이슈인데, 좀 얼탱이 없어서 정리겸 작성한다.

14.3에서도 정상적으로 문제없이 돌아가던 권한 체크 방식이 macOS 14.4 beta 2에서 갑자기 말썽이라는 것이다.

 

Google Chrome Remote Desktop 으로 제어시에도 마찬가지로 Host단에서 허용을 안해주면 제어가 불가능하다

 

위의 사진과 같이 앱의 화면 기록 권한 (macOS 14부터는 화면 및 시스템 오디오 녹음으로 변경)이 있음에도 불구하고

시스템 OS에서 발생하는 팝업에서 허용을 눌러주지 않으면 제어가 불가능하다는 것이다.

 

우선 기존 화면 권한을 확인하는 로직은 대부분의 macOS개발자들이 아마 아래와 같이 사용했을것이다.

#import <AVFoundation/AVFoundation.h>

BOOL isScreenRecordingPermissionEnabled() {
    NSDictionary *options = @{(__bridge NSString *)kCGDisplayStreamShowCursor: @NO};
    CGDisplayStreamRef displayStream = CGDisplayStreamCreate(CGMainDisplayID(), 1, 1, kCVPixelFormatType_32BGRA, (__bridge CFDictionaryRef)options);
    
    CGDisplayStreamStart(displayStream);
    CGDisplayStreamStop(displayStream);
    
    BOOL isPermissionEnabled = (CGDisplayStreamIsActive(displayStream) == true);
    
    CGDisplayStreamRelease(displayStream);
    
    return isPermissionEnabled;
}

// 사용 예시
BOOL isPermissionEnabled = [self isScreenRecordingPermissionEnabled];
if (isPermissionEnabled) {
    NSLog(@"화면 기록 권한이 활성화되어 있습니다.");
} else {
    NSLog(@"화면 기록 권한이 비활성화되어 있습니다.");
}

(뤼튼에게 물어봐)

 

CGDisplayStream 계열의 API 를 사용하고 있다.

14.0 부터 deprecated 된대서 1차 싸함을 느꼈다.

 

 

후 .. 14.4 beta2 Release Note에 해당 api 관련해서 뭐 바뀐것도 없다고 생각했었는데 14.0 release note 보니까 

Screen Sharing 관련하여 CGDisplayStream APIs 사용시 추가적인 알림을 표시한다고 Release Note에 명시되어있더라

그럼 14부터 안되야지 왜 14.3까지는 되고 14.4 beta2 에서만 안되는지 이해가 안갔다.

 

https://developer.apple.com/documentation/macos-release-notes/macos-14-release-notes#ScreenSharing

 

macOS Sonoma 14 Release Notes | Apple Developer Documentation

Update your apps to use new features, and test your apps against API changes.

developer.apple.com

 

 

해당 이슈로 골치아픈게 나뿐만 아니라 분명 다른 나라에도 있을거라고 생각하고 해당 이슈 관련해서 좀 찾아봤는데

진짜로 있다요

https://support.jumpdesktop.com/hc/en-us/community/posts/23796182773133

https://forums.macrumors.com/threads/macos-14-4-beta-1-bug-fixes-changes-and-more.2417788/

 

macOS 14.4 Beta 1 - Bug fixes, changes, and more

Release Date ― January 29, 2024 Build Number ― 23E5180j Apple Silicon System Firmware Version ― 10151.100.738.0.1 T2 BridgeOS System Firmware Version ― Pending (BridgeOS: Pending) New Features & Changes New Emojis 🐦‍🔥🙂‍↕️🙂‍↔

forums.macrumors.com

 

닉네임 unlockman212 로 바꿔야할듯

 

일단 나부터 급하니 화면 권한 얻는 방법에대해서 엄청나게 찾아봤다.

 

https://developer.apple.com/videos/play/wwdc2019/701/?time=1007 

 

Advances in macOS Security - WWDC19 - Videos - Apple Developer

We are on a journey to continuously improve macOS security, with a particular focus on preventing malware and protecting user data. Join...

developer.apple.com

 

WWDC19 에서도 나왔던 얘긴데, 간략히 설명하자면 사용자가 화면 녹화용 앱을 사전 승인하지 않는 한 window name과 공유 상태를 알수 없다.

 

따라서 아래와 같이 권한을 확인하는 방법도 있다는걸 적어놓도록 하겠슴다

 

- (BOOL)ScreeningRecordPermissionCheck {
    if (@available(macOS 10.15, *)) {
    // CGWindowListCopyWindowInfo 함수를 사용하여 현재 화면에 표시되는 창에 대한 정보를 가져와서
	// kCGWindowListOptionOnScreenOnly 옵션을 사용하여 화면에만 표시되는 창에 대한 정보만 가져오도록 설정하고, kCGNullWindowID를 사용하여 모든 창을 대상
        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];

		// 현재 창의 이름(windowName)이 존재하거나 공유 상태(sharingType)가 kCGWindowSharingNone이 아닌 경우, numberOfWindowsWithInfoGet 변수를 증가
            if (windowName || kCGWindowSharingNone != sharingType.intValue) {
                numberOfWindowsWithInfoGet++;
            } else {
                NSNumber* pid = windowInfo[(id)kCGWindowOwnerPID];
                NSString* appName = windowInfo[(id)kCGWindowOwnerName];
            }
        }
        CFRelease(windowList);
        // 즉 모든 창 정보를 성공적으로 받은 경우에는 YES를 반환
        if (numberOfWindows == numberOfWindowsWithInfoGet) {
            return YES;
        } else {
            return NO;
        }
    }
    return YES;
}

 

 

추가적으로 CGRequestScreenCaptureAccess() 함수도 필요할 수 있으니 알아서 잘 조합해서 사용하면 될 거 같다.

 

 

*화면 권한 사용하는 프로그램 몇개 다운받아서 테스트해봤는데

Google Chrome Remote Desktop은 호스트 단에서 허용 안해주면 화면 안나오고 TeamViewer는 잘되네요. (2024/02/07)

posted by devtang