Post

iOS禁止截屏

参考:

1、不允许截屏:使用iOS系统自带的UITextFieldisSecureTextEntry属性实现不允许截屏
2、用户截屏后获取截屏通知:UIApplication.userDidTakeScreenshotNotification

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
class MyViewController: UIViewController {
        var isLImitMessage: Bool {
           didSet {
                changeScreenshot()
           }
        }
        
        override func viewDidLoad() {
            super.viewDidLoad()
            let btn = UIButton(type: cu)
            btn.setTitle("修改截屏状态", for: .normal)
            btn.setTitleColor(.black, for: .normal)
            btn.titleLabel?.numberOfLines = 0
            btn.frame = CGRectMake(10, 100, 100, 48)
            btn.backgroundColor = btnColor
            btn.addTarget(self, action: #selector(btnClick), for: .touchUpInside)
            self.view.addSubview(btn)
       }

        @objc func btnClick() {
          self.isLImitMessage = !self.isLImitMessage
        }


        var secureTextField: UITextField? = nil
        var secureView: UIView? = nil
        func changeScreenshot() {
            if (isLImitMessage) {
                if secureTextField != nil {
                    // 已经设置过了就不再继续设置
                    return
                }
                if secureTextField == nil {
                    let v = UITextField()
                    secureTextField = v
                    for subView in v.subviews {
                        let fullClassName = NSStringFromClass(type(of: subView))
                        if fullClassName.contains("TextLayoutCanvasView") {
                            secureView = subView
                            break
                        }
                    }
                }
                guard let secureView = secureView else {
                    return
                }
                let previousLayer = secureView.layer
                secureView.setValue(self.view.layer, forKey: "layer")
                secureTextField?.isSecureTextEntry = false
                secureTextField?.isSecureTextEntry = true
                secureView.setValue(previousLayer, forKey: "layer")
            } else {
                if secureTextField == nil {
                    // 已经设置过了就不再继续设置
                    return
                }
                if let previousLayer = secureView?.layer {
                    secureView?.setValue(self.view.layer, forKey: "layer")
                    secureTextField?.isSecureTextEntry = true
                    secureTextField?.isSecureTextEntry = false
                    secureView?.setValue(previousLayer, forKey: "layer")
                }
                if secureView != nil {
                    secureView = nil
                }
                if secureTextField != nil {
                    secureTextField = nil
                }
            }
        }

Telegram的实现方式

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
31
32
33
34
    // 调用的地方
    setLayerDisableScreenshots(self.layer, self.isSecret)
    // 实现的地方
    void setLayerDisableScreenshots(CALayer * _Nonnull layer, bool disableScreenshots) {
        static UITextField *textField = nil;
        static UIView *secureView = nil;
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            textField = [[UITextField alloc] init];
            for (UIView *subview in textField.subviews) {
                if ([NSStringFromClass([subview class]) containsString:@"TextLayoutCanvasView"]) {
                    secureView = subview;
                    break;
                }
            }
        });
        if (secureView == nil) {
            return;
        }
        
        CALayer *previousLayer = secureView.layer;
        [secureView setValue:layer forKey:@"layer"];
        if (disableScreenshots) {
            textField.secureTextEntry = false;
            textField.secureTextEntry = true;
        } else {
            textField.secureTextEntry = true;
            textField.secureTextEntry = false;
        }
        [secureView setValue:previousLayer forKey:@"layer"];
        
        [layer setAssociatedObject:@(disableScreenshots) forKey:layerDisableScreenshotsKey associationPolicy:NSObjectAssociationPolicyRetain];
    }
}
This post is licensed under CC BY 4.0 by the author.