1// Copyright 2018-present 650 Industries. All rights reserved. 2 3#import <EXScreenCapture/EXScreenCaptureModule.h> 4 5#import <ExpoModulesCore/EXEventEmitterService.h> 6 7static NSString * const onScreenshotEventName = @"onScreenshot"; 8 9@interface EXScreenCaptureModule () 10 11@property (nonatomic, weak) EXModuleRegistry *moduleRegistry; 12@property (nonatomic, assign) BOOL isListening; 13@property (nonatomic, assign) BOOL isBeingObserved; 14@property (nonatomic, weak) id<EXEventEmitterService> eventEmitter; 15 16@end 17 18@implementation EXScreenCaptureModule { 19 UIView *_blockView; 20} 21 22EX_EXPORT_MODULE(ExpoScreenCapture); 23 24# pragma mark - EXModuleRegistryConsumer 25 26- (void)setModuleRegistry:(EXModuleRegistry *)moduleRegistry 27{ 28 _moduleRegistry = moduleRegistry; 29 _eventEmitter = [moduleRegistry getModuleImplementingProtocol:@protocol(EXEventEmitterService)]; 30} 31 32- (instancetype)init { 33 if (self = [super init]) { 34 CGFloat boundLength = MAX([[UIScreen mainScreen] bounds].size.width, [[UIScreen mainScreen] bounds].size.height); 35 _blockView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, boundLength, boundLength)]; 36 _blockView.backgroundColor = UIColor.blackColor; 37 } 38 return self; 39} 40 41# pragma mark - Exported methods 42 43EX_EXPORT_METHOD_AS(preventScreenCapture, 44 preventScreenCaptureWithResolver:(EXPromiseResolveBlock)resolve 45 reject:(EXPromiseRejectBlock)reject) 46{ 47 if (@available(iOS 11.0, *) ) { 48 // If already recording, block it 49 dispatch_async(dispatch_get_main_queue(), ^{ 50 [self preventScreenRecording]; 51 }); 52 53 // Avoid setting duplicate observers 54 [[NSNotificationCenter defaultCenter] removeObserver:self name:UIScreenCapturedDidChangeNotification object:nil]; 55 56 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(preventScreenRecording) name:UIScreenCapturedDidChangeNotification object:nil]; 57 } 58 59 resolve([NSNull null]); 60} 61 62EX_EXPORT_METHOD_AS(allowScreenCapture, 63 allowScreenCaptureWithResolver:(EXPromiseResolveBlock)resolve 64 rejecter:(EXPromiseRejectBlock)reject) 65{ 66 if (@available(iOS 11.0, *)) { 67 [[NSNotificationCenter defaultCenter] removeObserver:self name:UIScreenCapturedDidChangeNotification object:nil]; 68 } 69 70 resolve([NSNull null]); 71} 72 73- (void)preventScreenRecording { 74 if (@available(iOS 11.0, *)) { 75 BOOL isCaptured = [[UIScreen mainScreen] isCaptured]; 76 77 if (isCaptured) { 78 [UIApplication.sharedApplication.keyWindow.subviews.firstObject addSubview:_blockView]; 79 } else { 80 [_blockView removeFromSuperview]; 81 } 82 } 83} 84 85# pragma mark - EXEventEmitter 86 87- (NSArray<NSString *> *)supportedEvents 88{ 89 return @[onScreenshotEventName]; 90} 91 92- (void)startObserving 93{ 94 [self setIsBeingObserved:YES]; 95} 96 97- (void)stopObserving 98{ 99 [self setIsBeingObserved:NO]; 100} 101 102- (void)setIsBeingObserved:(BOOL)isBeingObserved 103{ 104 _isBeingObserved = isBeingObserved; 105 BOOL shouldListen = _isBeingObserved; 106 if (shouldListen && !_isListening) { 107 // Avoid setting duplicate observers 108 [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationUserDidTakeScreenshotNotification object:nil]; 109 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(listenForScreenCapture) name:UIApplicationUserDidTakeScreenshotNotification object:nil]; 110 _isListening = YES; 111 } else if (!shouldListen && _isListening) { 112 [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationUserDidTakeScreenshotNotification object:nil]; 113 _isListening = NO; 114 } 115} 116 117- (void)listenForScreenCapture 118{ 119 [_eventEmitter sendEventWithName:onScreenshotEventName body:nil]; 120} 121 122@end 123