iOSでスクリーンショットを制限する方法について

# iOSでスクリーンショットを制限する方法について

### 結論
- iOSでスクリーンショット禁止は今のところ可能（iOS17時点）
- ただ、アップデートで使えなくなる可能性がある
- ストア審査でリジェクトされる可能性がある
- なので、iOSでスクショ禁止は対応しない方が良いかも
---

### なんでスクショ禁止にしたいか？
- クーポンコードなどをスクショして悪用するケースを防ぎたい
- 著作権を守るため（ex.漫画、映画など）
---

### スクショを禁止にする方法
- DRM（Digital Rights Management）を使用する
   - Appleに依頼が必要（割愛）
   - [参考記事](https://qiita.com/TeruhiroMatsukawa/items/823f16b76fccea0ec9b9)
- UITextFieldの.isSecureTextEntryプロパティを活用する
   - 今回はここ 


#### スクショ防止ではないけど…
- NotificationCenterの下2つを活用する
   - userDidTakeScreenshotNotification （スクリーンショット）
   - capturedDidChangeNotification （スクリーンレコーディング）


### NotificationCenterでダメな理由
- user**Did**TakeScreenshotNotificationとcaptured**Did**ChangeNotificationなので、スクショ（レコーディング）撮られた後に呼ばれる
- レコーディングはある程度防げそうだが、スクショは不可
---
### UITextFieldの.isSecureTextEntryでスクショを防ぐ方法
- UITextFieldの[.isSecureTextEntry](https://developer.apple.com/documentation/uikit/uitextinputtraits/1624427-issecuretextentry)プロパティをtrueにすると入力中の情報が録画されない
- UITextFieldのSubViewの一つ、UITextLayoutCanvasViewが画面録画を回避するUIViewになっているのでこの子でカスタムビューを作成し、その中に撮られたくないViewを入れる

##### SecureField(カスタムTextField)
``` swift
class SecureField : UITextField {

    override init(frame: CGRect) {
        super.init(frame: .zero)
        self.isSecureTextEntry = true
        self.translatesAutoresizingMaskIntoConstraints = false
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    weak var secureContainer: UIView? {
        let secureView = self.subviews.filter({ subview in
            type(of: subview).description().contains("CanvasView")
        }).first
        secureView?.translatesAutoresizingMaskIntoConstraints = false
        secureView?.isUserInteractionEnabled = true //To enable child view's userInteraction in iOS 13
        return secureView
    }
    
    override var canBecomeFirstResponder: Bool {false}
    override func becomeFirstResponder() -> Bool {false}
}
```


##### ViewController
```swift
    private func setupSecurePhoto() {
        imageView.image = UIImage(named: "kawa_taki")
        imageView.contentMode = .scaleAspectFit
        
        guard let secureView = SecureField().secureContainer else {
            return
        }
        secureView.addSubview(imageView)
        imageView.pinEdges()
        photoContainerView.addSubview(secureView)
        secureView.pinEdges()
    }
```

### 数年前は他にも方法があった（今は使えない）
- UIViewのextensionにisSecureTextEntryをtrueにしたUITextFieldをaddSubViewしてあげる方法
   - iOS17で使えなくなった…
   - [参考記事](https://stackoverflow.com/questions/18680028/prevent-screen-capture-in-an-ios-app/67054892#67054892)

```swift
extension UIView {
    func makeSecure() {
        DispatchQueue.main.async {
            let field = UITextField()
            field.isSecureTextEntry = true
            self.addSubview(field)
            field.translatesAutoresizingMaskIntoConstraints = false
            field.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true
            field.centerXAnchor.constraint(equalTo: self.centerXAnchor).isActive = true
            self.layer.superlayer?.addSublayer(field.layer)
            field.layer.sublayers?.first?.addSublayer(self.layer)
        }
    }
}
```

- 今回の方法もいつか使えなくなる可能性がある
---
### そもそもAppleの対応は？
- DRMとかはあるけど、そもそもiPhoneを外部カメラで録画されたら防げないよね？とのこと
- [AppleForlam](https://forums.developer.apple.com/forums/thread/123725)
---
### 他のアプリの対応は？
- Netflix、PrimeVideo、U-NextはDRMを使用してるっぽい
- 漫画アプリなどの静止画コンテンツは警告を出す （スクショ後に）
   - アカウント停止や、 法的措置
   - スクリーンショットの回数を保存しておいて何回以上でBANとかありそう
---
### まとめ
- スクショ禁止は今はできるけど今後は無理になるかもしれない
- そもそも完全に防ぐのは無理（外部デバイスで撮れる）
- 他のアプリのような対応が正しいのかも（DRMや警告）

---

### 参考資料
- https://qiita.com/chitomo12/items/101555bb230eabbf1b3c
- https://medium.com/@lakshimi.cg/screenshot-prevention-in-ios-f059dc82b046
- https://github.com/mittsu333/SecureScreen