美文网首页
iOS 监听用户截屏并获取

iOS 监听用户截屏并获取

作者: 蒋伟_iOS | 来源:发表于2019-11-28 20:49 被阅读0次

    集团考勤最新的意见反馈需求,参照了京东的截屏反馈。
    重点就是如何监听到 用户触发了系统级的截屏,并获取到当前截屏图片。

    监听到用户截屏后,有两种处理方式:

    • 方式一:模拟用户的截屏动作,用layer 去绘制当前app的window 展示的内容,然后进行图像处理(比较复杂),获得UIImage
    • 方式二:在截屏后,去访问用户相册,拿到用户相册的最后一张图片,判断是不是截屏,然后采用。

    一、注册监听通知 -- userDidTakeScreenshot

    [[NSNotificationCenter defaultCenter] addObserver:self
    selector:@selector(userDidTakeScreenshot:)                                              
    name:UIApplicationUserDidTakeScreenshotNotification object:nil];
    

    二、监听用户截屏动作,并处理layer(方式一)

    -(void)userDidTakeScreenshot:(NSNotification *)notification
    {
        NSLog(@"检测到截屏");
        //人为截屏, 模拟用户截屏行为, 获取所截图片
        UIImage *image_ = [self imageWithScreenshot];
        //添加显示
        UIImageView *imgvPhoto = [[UIImageView alloc]initWithImage:image_];
        imgvPhoto.frame = CGRectMake(self.window.frame.size.width/2, self.window.frame.size.height/2, self.window.frame.size.width/2, self.window.frame.size.height/2);
        //添加边框
        CALayer * layer = [imgvPhoto layer];
        layer.borderColor = [
                             [UIColor whiteColor] CGColor];
        layer.borderWidth = 5.0f;
        //添加四个边阴影
        imgvPhoto.layer.shadowColor = [UIColor blackColor].CGColor;
        imgvPhoto.layer.shadowOffset = CGSizeMake(0, 0);
        imgvPhoto.layer.shadowOpacity = 0.5;
        imgvPhoto.layer.shadowRadius = 10.0;
        //添加两个边阴影
        imgvPhoto.layer.shadowColor = [UIColor blackColor].CGColor;
        imgvPhoto.layer.shadowOffset = CGSizeMake(4, 4);
        imgvPhoto.layer.shadowOpacity = 0.5;
        imgvPhoto.layer.shadowRadius = 2.0;
        [self.window addSubview:imgvPhoto];
    }
    

    三、处理截屏图像(方式一)

    - (UIImage *)imageWithScreenshot
    {
        NSData *imageData = [self dataWithScreenshotInPNGFormat];
        return [UIImage imageWithData:imageData];
    }
    
    - (NSData *)dataWithScreenshotInPNGFormat
    {
        CGSize imageSize = CGSizeZero;
        UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
        if (UIInterfaceOrientationIsPortrait(orientation))
            imageSize = [UIScreen mainScreen].bounds.size;
        else
            imageSize = CGSizeMake([UIScreen mainScreen].bounds.size.height, [UIScreen mainScreen].bounds.size.width);
    
        UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0);
        CGContextRef context = UIGraphicsGetCurrentContext();
        for (UIWindow *window in [[UIApplication sharedApplication] windows])
        {
            CGContextSaveGState(context);
            CGContextTranslateCTM(context, window.center.x, window.center.y);
            CGContextConcatCTM(context, window.transform);
            CGContextTranslateCTM(context, -window.bounds.size.width * window.layer.anchorPoint.x, -window.bounds.size.height * window.layer.anchorPoint.y);
            if (orientation == UIInterfaceOrientationLandscapeLeft)
            {
                CGContextRotateCTM(context, M_PI_2);
                CGContextTranslateCTM(context, 0, -imageSize.width);
            }
            else if (orientation == UIInterfaceOrientationLandscapeRight)
            {
                CGContextRotateCTM(context, -M_PI_2);
                CGContextTranslateCTM(context, -imageSize.height, 0);
            } else if (orientation == UIInterfaceOrientationPortraitUpsideDown) {
                CGContextRotateCTM(context, M_PI);
                CGContextTranslateCTM(context, -imageSize.width, -imageSize.height);
            }
            if ([window respondsToSelector:@selector(drawViewHierarchyInRect:afterScreenUpdates:)])
            {
                [window drawViewHierarchyInRect:window.bounds afterScreenUpdates:YES];
            }
            else
            {
                [window.layer renderInContext:context];
            }
            CGContextRestoreGState(context);
        }
    
        UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
    
        return UIImagePNGRepresentation(image);
    }
    
    

    四、方式二:获取用户最后一张图片

    static NSTimeInterval const latestAssetFetchInterval = 10;
    
    @interface AJUserPhotoFetchManager ()
    
    @property (nonatomic, strong, nullable) NSDate *lastAssetcreationDate;
    @end
    
    static NSString * const kLastAssetcreationDateKey = @"kLastAssetcreationDateKey";
    @implementation AJUserPhotoFetchManager
    
    #pragma mark - 单例方法
    static AJUserPhotoFetchManager *sharedInstance;
    + (id)allocWithZone:(struct _NSZone *)zone
    {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            sharedInstance = [super allocWithZone:zone];
            sharedInstance.lastAssetcreationDate = [[NSUserDefaults standardUserDefaults] objectForKey:kLastAssetcreationDateKey];
        });
        
        return sharedInstance;
    }
    
    + (AJUserPhotoFetchManager *)sharedUserPhotoFetchManager
    {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            sharedInstance = [[AJUserPhotoFetchManager alloc]init];
            sharedInstance.lastAssetcreationDate = [[NSUserDefaults standardUserDefaults] objectForKey:kLastAssetcreationDateKey];
        });
        return sharedInstance;
    }
    
    
    /** 点击“+”号的时候获取相册列表,获取最新保存的一张图片。
      * 根据图片保存时间,与当前时间戳进行计算,获得间隔时间。从而判断是否是需求的时间间隔。(时间间隔自定义)
     */
    - (void)fetchLatestPhotoInTimeIntervalWithCompletion:(void (^)(UIImage *result, NSDictionary *info))completion{
        // 此处不能主动获取权限,在用户同意的情况下可以去获取
        PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus];
        if (status == PHAuthorizationStatusAuthorized) {
            
    //        AJUserPhotoFetchManager *sharedUserPhotoFetchManager = [AJUserPhotoFetchManager sharedUserPhotoFetchManager];
            PHAsset *latestAsset = [self fetchLatestPhotoAsset];
            NSDate *nowDate = [NSDate date];
            NSTimeInterval timeInterval = [nowDate timeIntervalSinceDate:latestAsset.creationDate];// 创建时间距离的时间间隔
            if (timeInterval > latestAssetFetchInterval) { // 超出时间了
                return;
            }
            // 对一张图片10s内两次获取,虽然是同一张图片,系统回调的图片结果地址不一致。 
            // 阅读了相关博客也不建议用回调的info里面字段作判断, 所以这里采用的图片的时间戳
            if (self.lastAssetcreationDate && [self.lastAssetcreationDate compare:latestAsset.creationDate] != NSOrderedAscending) { // 上次已经获取过了
                return;
            }
            
            PHImageRequestOptions *options = [[PHImageRequestOptions alloc] init];
            options.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;
            
            [[PHImageManager defaultManager] requestImageForAsset:latestAsset targetSize:UIScreen.mainScreen.bounds.size contentMode:PHImageContentModeAspectFit options:options resultHandler:^(UIImage *result, NSDictionary *info) {
                self.lastAssetcreationDate = latestAsset.creationDate;
                [[NSUserDefaults standardUserDefaults] setObject:latestAsset.creationDate forKey:kLastAssetcreationDateKey];
                completion(result, info);
            }];
        }
    }
    
    - (PHAsset *)fetchLatestPhotoAsset{
    
        PHFetchOptions *options = [[PHFetchOptions alloc]init];
        if (@available(iOS 9.0, *)) {
            options.fetchLimit = 1;
        }
        options.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:NO]];
        PHFetchResult *assetsFetchResults = [PHAsset fetchAssetsWithOptions:options];
        return assetsFetchResults.firstObject;
    }
    
    + (void)requestAuthorization:(void (^)(PHAuthorizationStatus))handler{
        [PHPhotoLibrary requestAuthorization:handler];
    }
    

    相关文章

      网友评论

          本文标题:iOS 监听用户截屏并获取

          本文链接:https://www.haomeiwen.com/subject/bnliwctx.html