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 already recording, block it 48 dispatch_async(dispatch_get_main_queue(), ^{ 49 [self preventScreenRecording]; 50 }); 51 52 // Avoid setting duplicate observers 53 [[NSNotificationCenter defaultCenter] removeObserver:self name:UIScreenCapturedDidChangeNotification object:nil]; 54 55 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(preventScreenRecording) name:UIScreenCapturedDidChangeNotification object:nil]; 56 57 resolve([NSNull null]); 58} 59 60EX_EXPORT_METHOD_AS(allowScreenCapture, 61 allowScreenCaptureWithResolver:(EXPromiseResolveBlock)resolve 62 rejecter:(EXPromiseRejectBlock)reject) 63{ 64 [[NSNotificationCenter defaultCenter] removeObserver:self name:UIScreenCapturedDidChangeNotification object:nil]; 65 66 resolve([NSNull null]); 67} 68 69- (void)preventScreenRecording { 70 BOOL isCaptured = [[UIScreen mainScreen] isCaptured]; 71 72 if (isCaptured) { 73 [UIApplication.sharedApplication.keyWindow.subviews.firstObject addSubview:_blockView]; 74 } else { 75 [_blockView removeFromSuperview]; 76 } 77} 78 79# pragma mark - EXEventEmitter 80 81- (NSArray<NSString *> *)supportedEvents 82{ 83 return @[onScreenshotEventName]; 84} 85 86- (void)startObserving 87{ 88 [self setIsBeingObserved:YES]; 89} 90 91- (void)stopObserving 92{ 93 [self setIsBeingObserved:NO]; 94} 95 96- (void)setIsBeingObserved:(BOOL)isBeingObserved 97{ 98 _isBeingObserved = isBeingObserved; 99 BOOL shouldListen = _isBeingObserved; 100 if (shouldListen && !_isListening) { 101 // Avoid setting duplicate observers 102 [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationUserDidTakeScreenshotNotification object:nil]; 103 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(listenForScreenCapture) name:UIApplicationUserDidTakeScreenshotNotification object:nil]; 104 _isListening = YES; 105 } else if (!shouldListen && _isListening) { 106 [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationUserDidTakeScreenshotNotification object:nil]; 107 _isListening = NO; 108 } 109} 110 111- (void)listenForScreenCapture 112{ 113 [_eventEmitter sendEventWithName:onScreenshotEventName body:nil]; 114} 115 116@end 117