Oct 9

小记:iOS客户端文本截屏保护

Lrdcq , 2019/10/09 01:18 , 程序 , 閱讀(303) , Via 本站原創
用安卓手机的时候注意到不少内容app可以阻止用户截屏,通过为当前windows设置FLAG_SECURE或者一些其他的trick手段,用户就无法截屏了。
iOS目前还没有提供类似的功能,不过注意到系统有提供类似的组件:UITextField在设置为secureTextEntry即密码模式后,整个UITextField的文本区在截屏时是完全截不进去的,估计是考虑到点点点也能暴露用户密码位数的缘故。
当然目前iOS大部分应用做的方法是监听UIApplicationUserDidTakeScreenshotNotification事件,在用户截屏后给出安全提示,不过毕竟不是最好的方法。

因此注意到一些传统app有做,针对敏感文本信息,有做闪烁截屏保护。

实现路径与效果

简单来说,就是通过不停的交错闪烁间隔的文字来让用户看到完整的信息。而截屏的时候只能截取到不完整的信息,防止误传敏感信息(本来这个方案就是防君子不防小人的)。

实际看起来效果如下:
(iPhone SE 拍摄视频 模拟器)
點擊在新視窗中瀏覽此圖片
(Android mi note 3拍摄照片 模拟器+真机)
點擊在新視窗中瀏覽此圖片

代码很简单:
@implementation LRDScreenShotSafeLabel {
    CADisplayLink *_timer;
    BOOL _timerSwitch;
}

- (CADisplayLink *)displayLink {
    if (!_timer) {
        _timer = [CADisplayLink displayLinkWithTarget:self selector:@selector(updateDisplayLabel)];
        _timer.paused = YES;
        [_timer addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
    }
    return _timer;
}

- (void)willMoveToWindow:(nullable UIWindow *)newWindow {
    if (newWindow) {
        self.displayLink.paused = NO;
    } else {
        self.displayLink.paused = YES;
    }
}

- (void)updateDisplayLabel {
    _timerSwitch = !_timerSwitch;
    NSRange range;
    NSMutableAttributedString *displayStr = [NSMutableAttributedString new];
    NSDictionary *lightDic = @{NSForegroundColorAttributeName: self.safeForegroundColor ?: [UIColor blackColor]};
    NSDictionary *darkDic = @{NSForegroundColorAttributeName: self.safeBackgroundColor ?: [UIColor whiteColor]};
    NSUInteger count = 0;
    for (int i = 0; i < self.text.length ; i += range.length, count++ ) {
        range = [self.text rangeOfComposedCharacterSequenceAtIndex:i];
        [displayStr appendAttributedString: [[NSAttributedString alloc] initWithString:[self.text substringWithRange:range] attributes:((count + (_timerSwitch ? 1 : 0)) % 2) ? lightDic : darkDic]];
    }
    self.attributedText = displayStr;
}

@end

首先代码角度:

1. 通过CADisplayLink来构成闪烁timmer,保证文字尽可能快/同步的刷新,别无他选

2. 文字截取的时候务必使用rangeOfComposedCharacterSequenceAtIndex而不是substringToIndex保证异常字符可以正确截取,否则有炸的风险。

3. 虽然上面的代码不完整,self.attributedText设置之后,需要重新拷贝设置一次textColor,textAlignment,lineBreakMode之类的属性,attributedText设置会重置相关内容。

4. 最好钩一下当前类的setAttributedText方法避免错误使用。同时这里利用到特性,UILabel展示的是setText和setAttributedText两者最后一次设置的内容。

同时从如上实现效果来看。首先主观判断效果还是可行,上面拍摄的倒是因为刷新率问题看起来有明暗:

1. 目前文字设置的black,但是闪烁起来看起来就是灰色的了,因此该方案必然无法实现大红大绿(rgb到上下极限值)的视觉颜色,需要一定妥协。

2. 因为是CADisplayLink,因此屏幕掉帧,特别是无规律掉帧的时候看起来就能看出来闪烁了。不过实际看多半是在页面切换/前后台切换等场景,页面本身写得靠谱问题不大。

3. 如果之后屏幕刷新率普遍提升到120hz,这个方案可行问题会小不少

其他讨论:

1. 除了交错闪烁(均匀屏蔽掉50%)内容,是否有别的处理方法?目前判断如果不进行均匀的闪烁,或者闪烁背景不是容器背景色的话,闪烁感会非常明显。测试了一个随意区域隐藏的闪烁逻辑,效果明显不理想:
點擊在新視窗中瀏覽此圖片

2. 图片可以使用该方法么?原理上可以,但是闪烁颗粒得落到像素级别。区域级别或者其他交错方式在图片上都会有明显的交错纹理。另外图片变淡就比文字变淡处理起来麻烦多了。
关键词:oc , ios
logo