-
화면 캡쳐 및 녹화 방지iOS 2021. 8. 28. 09:54
안녕하세요. 그린입니다🟢
이번 포스팅에서는 화면 캡쳐 및 녹화 방지에 대해 포스팅해보겠습니다🧑🏻💻
제공하는 앱에서 화면 캡쳐와 녹화를 원천적으로 차단할 수 있을까요?
우선, 가능은 합니다. 단 우리의 코드만으론 할 수 없습니다.
무슨 소리인지 감이 안오시죠?
간략히 말해보자면, iOS에서 화면 캡쳐를 하는것은 OS의 영역입니다.
이에, 방지 기능이 구현된 라이브러리나 어떠한 솔루션을 사용하지 않는다면 코드만으론 방지를 할 수 없습니다.
그럼 어떤식으로 캡쳐와 녹화를 방지할 수 있을까요?
원천적으로 기능이 되지 않게는 할 수 없으니 사용자에게 캡쳐와 녹화가 시작 될때 얼럿을 노출시켜주면 됩니다.
그러면 사용자도 의도를 인지할것입니다.
만약 더 나아가 얼럿만으로는 안되고 캡쳐나 녹화를 이후에 무슨 일이 생겼을때 어떤 사용자가 그랬는지 정보가 필요하다면
서버와 연동하여 사용자ID, 캡쳐시각, 캡쳐정보 같은 데이터들을 캡쳐나 녹화가 일어날때 로깅할 수 있습니다.
그러면 추후 일이 발생한다면 해당 자료를 사용하면 되겠죠?
자 그럼 이제 본격적으로 캡쳐/녹화 방지를 구현해보도록 하죠!
해당 기능을 특정한 뷰컨에서만 해줄 수도 있겠지만 저는 전역적으로 캡쳐 및 녹화를 방지하고자
SceneDelgate에서 다뤄주었습니다👍
import UIKit import SwiftUI class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? ... func sceneWillEnterForeground(_ scene: UIScene) { // Called as the scene transitions from the background to the foreground. // Use this method to undo the changes made on entering the background. NotificationCenter.default.addObserver(self, selector: #selector(alertPreventScreenCapture(notification:)), name: UIApplication.userDidTakeScreenshotNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(alertPreventScreenCapture(notification:)), name: UIScreen.capturedDidChangeNotification, object: nil) } ... @objc func alertPreventScreenCapture(notification:Notification) -> Void { let alert = UIAlertController(title: "주의", message: "캡쳐 혹은 녹화를 하면 안되요!!", preferredStyle: .alert) alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil)) self.window?.rootViewController!.present(alert, animated: true, completion: nil) } }
정말 코드가 간단하죠?
우선 뷰를 다루는 씬딜리게이트에서 씬이 포그라운드로 들어갈때 전역적으로 해당 기능을 동작할 수 있게 심어줍니다.
노티피케이션센터를 통해 옵저버를 추가하고 캡쳐나 녹화가 일어날때 셀렉터 메서드를 호출합니다.
- 화면 캡쳐 감지
화면 캡쳐를 감지할수 있는 메서드는 UIApplication의 userDidTakeScreenshotNotifiacion입니다.
- 녹화 감지
화면 녹화를 감지할 수 있는 메서드는 UIScreen.captureDidChangeNotification입니다.
이 둘의 사용을 구분하면 좋습니다!
다시 셀럭터 메서드가 호출이되면 얼럿을 생성하고 띄워줍니다.
자 그럼 구동되는 움짤을 보시죠!
어떤 느낌인지 아시겠죠?
이렇게 간단하게 화면 캡쳐 및 녹화를 감지해서 얼럿으로 알려줄 수 있습니다.
근데 더 나아가서, 화면 녹화가 시작될떄 아예 화면을 안보이게도 할 수 있겠죠?
import UIKit import SwiftUI class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? ... func sceneWillEnterForeground(_ scene: UIScene) { // Called as the scene transitions from the background to the foreground. // Use this method to undo the changes made on entering the background. NotificationCenter.default.addObserver(self, selector: #selector(alertPreventScreenCapture(notification:)), name: UIApplication.userDidTakeScreenshotNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(alertPreventScreenCapture(notification:)), name: UIScreen.capturedDidChangeNotification, object: nil) } ... @objc func alertPreventScreenCapture(notification:Notification) -> Void { let alert = UIAlertController(title: "주의", message: "캡쳐 혹은 녹화를 하면 안되요!", preferredStyle: .alert) alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil)) DispatchQueue.main.async { [self] in if var rootController = self.window?.rootViewController { while let currentController = rootController.presentedViewController { rootController = currentController } rootController.present(alert, animated: true, completion: nil) } hideScreen() } } fileprivate func hideScreen() { if UIScreen.main.isCaptured { window?.isHidden = true } else { window?.isHidden = false } } }
이렇게 화면을 숨기는 함수를 만들어주고 화면 녹화가 일어날때 숨겨주고 끝나면 다시 보여주게 해줍니다.
그럼 셀렉터 메서드에서 해당 메서드와 얼럿을 띄워주는 메서드를 비동기로 처리해준다면 원하는 결과를 보여줄 수 있어요!
음.. 움짤로 한번에 간단히 보여드리고 싶은데 Xcode 시뮬레이터 화면 녹화기능은 감지를 안하고
아이폰 기기로 녹화를 진행하고 끝내면 다 영상에 안담겨서😭
아쉽지만 화면이 보이지 않게 되는것만 보여드릴께요ㅠㅠ...
실제로 저 코드로 돌려보면 화면 녹화를 중단하면 다시 얼럿이 나타나는걸 볼 수 있어요!
그런데 해당 코드에서는 치명적인 단점이 있어요!
바로 비동기로 메인에서 작동하기에 돌아왔을때 얼럿이 여러개가 생길 수 있어요.
제일제일 간단한 방법으로 바꿔보죠!
import UIKit import SwiftUI class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? ... func sceneWillEnterForeground(_ scene: UIScene) { // Called as the scene transitions from the background to the foreground. // Use this method to undo the changes made on entering the background. NotificationCenter.default.addObserver(self, selector: #selector(alertPreventScreenCapture(notification:)), name: UIApplication.userDidTakeScreenshotNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(alertPreventScreenCapture(notification:)), name: UIScreen.capturedDidChangeNotification, object: nil) } ... @objc func alertPreventScreenCapture(notification:Notification) -> Void { let alert = UIAlertController(title: "주의", message: "캡쳐 혹은 녹화를 하면 안되요!", preferredStyle: .alert) alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil)) hideScreen() self.window?.rootViewController!.present(alert, animated: true, completion: nil) } fileprivate func hideScreen() { if UIScreen.main.isCaptured { window?.isHidden = true } else { window?.isHidden = false } } }
자 이렇게 한다면 비동기고 뭐고 복잡할 필요없이 원하는 동작의 구현이 가능합니다!
물론 녹화를 중단하고 오면 얼럿도 한번만 노출되요👍
간단하죠? 이렇게 캡쳐와 녹화를 원천적으로 차단하진 않고 방지할 수 있는 방법에 대해 학습해보았습니다.
상용앱이라면 개인정보등 고객의 민감한 정보를 이용할 수도 있기에 보안 강화를 위해 필수는 아니지만
옵션으로 좋은 방법이라고 생각합니다💁🏻
더 궁금하시면 아래 실습 프로젝트를 클론 받거나 코드를 살펴보시면 더 이해가 빠르실 겁니다🥳
[실습 프로젝트]
https://github.com/GREENOVER/preventScreenCapture_Record
[참고자료]
https://hackernoon.com/how-to-disable-screenshots-and-recording-in-ios-apps-8l2e3tmb'iOS' 카테고리의 다른 글
App Tracking Transparency (0) 2021.10.16 Access Photo Library & Delete Asset (0) 2021.10.03 Multiple Firebase Environments (0) 2021.08.21 DI & Swinject (0) 2021.08.03 Test Doubles - fake, stub, mock (0) 2021.07.22