@exodus/react-native-screenshot-detector 1.1.1 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -31,6 +31,6 @@ repositories {
31
31
  }
32
32
 
33
33
  dependencies {
34
- compile 'com.facebook.react:react-native:+'
34
+ implementation 'com.facebook.react:react-native:+'
35
35
  }
36
36
 
package/index.ios.js CHANGED
@@ -4,12 +4,59 @@ const { RNScreenshotDetector } = NativeModules
4
4
  const eventEmitter = new NativeEventEmitter(RNScreenshotDetector)
5
5
 
6
6
  const SCREENSHOT_EVENT = 'ScreenshotTaken'
7
+ const SCREEN_RECORDING_EVENT = 'ScreenRecordingChanged'
7
8
 
8
9
  const subscribe = (cb) => {
9
- const sub = eventEmitter.addListener(SCREENSHOT_EVENT, cb, {})
10
- return () => sub.remove()
10
+ const sub = eventEmitter.addListener(SCREENSHOT_EVENT, (data) => {
11
+ cb(data)
12
+ })
13
+ return () => {
14
+ sub.remove()
15
+ }
11
16
  }
12
17
 
13
- export default {
18
+ const subscribeToScreenRecording = (cb) => {
19
+ if (RNScreenshotDetector.subscribeToScreenRecording) {
20
+ RNScreenshotDetector.subscribeToScreenRecording()
21
+ }
22
+
23
+ const sub = eventEmitter.addListener(SCREEN_RECORDING_EVENT, (data) => {
24
+ cb(data)
25
+ })
26
+ return () => {
27
+ sub.remove()
28
+ if (RNScreenshotDetector.unsubscribeFromScreenRecording) {
29
+ RNScreenshotDetector.unsubscribeFromScreenRecording()
30
+ }
31
+ }
32
+ }
33
+
34
+ const disableScreenshots = () => {
35
+ if (RNScreenshotDetector.disableScreenshots) {
36
+ RNScreenshotDetector.disableScreenshots()
37
+ }
38
+ }
39
+
40
+ const enableScreenshots = () => {
41
+ if (RNScreenshotDetector.enableScreenshots) {
42
+ RNScreenshotDetector.enableScreenshots()
43
+ }
44
+ }
45
+
46
+ const isScreenRecording = async () => {
47
+ if (RNScreenshotDetector.isScreenRecording) {
48
+ return RNScreenshotDetector.isScreenRecording()
49
+ } else {
50
+ return false
51
+ }
52
+ }
53
+
54
+ const ScreenshotDetector = {
14
55
  subscribe,
56
+ subscribeToScreenRecording,
57
+ disableScreenshots,
58
+ enableScreenshots,
59
+ isScreenRecording,
15
60
  }
61
+
62
+ export default ScreenshotDetector
@@ -9,6 +9,9 @@
9
9
 
10
10
  @interface RNScreenshotDetector : RCTEventEmitter <RCTBridgeModule>
11
11
 
12
+ @property (nonatomic, strong) UITextField *secureTextField;
13
+
12
14
  - (void)screenshotDetected:(NSNotification*)notification;
15
+ - (void)screenRecordingChanged:(NSNotification*)notification;
13
16
 
14
17
  @end
@@ -6,40 +6,161 @@
6
6
 
7
7
  #import "RNScreenshotDetector.h"
8
8
  #import <React/RCTBridge.h>
9
+ #import <UIKit/UIKit.h>
9
10
 
10
11
  @implementation RNScreenshotDetector
11
12
  {
12
- id observer;
13
+ id screenshotObserver;
14
+ id screenRecordingObserver;
15
+ UIView *securityOverlay;
16
+ BOOL isProtectionEnabled;
13
17
  }
14
18
 
15
19
  RCT_EXPORT_MODULE();
16
20
 
17
-
18
21
  - (NSArray<NSString *> *)supportedEvents {
19
- return @[@"ScreenshotTaken"];
22
+ return @[@"ScreenshotTaken", @"ScreenRecordingChanged"];
20
23
  }
21
24
 
22
25
  - (void)startObserving {
23
- // Now set up handler to detect if user takes a screenshot
24
26
  NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];
25
- observer = [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationUserDidTakeScreenshotNotification
26
- object:nil
27
- queue:mainQueue
28
- usingBlock:^(NSNotification *notification) {
29
- [self screenshotDetected:notification];
30
- }];
27
+ screenshotObserver = [[NSNotificationCenter defaultCenter]
28
+ addObserverForName:UIApplicationUserDidTakeScreenshotNotification
29
+ object:nil
30
+ queue:mainQueue
31
+ usingBlock:^(NSNotification *notification) {
32
+ [self screenshotDetected:notification];
33
+ }];
34
+
35
+ screenRecordingObserver = [[NSNotificationCenter defaultCenter]
36
+ addObserverForName:UIScreenCapturedDidChangeNotification
37
+ object:nil
38
+ queue:mainQueue
39
+ usingBlock:^(NSNotification *notification) {
40
+ [self screenRecordingChanged:notification];
41
+ }];
31
42
  }
32
43
 
33
44
  - (void)stopObserving {
34
- if (observer != nil) {
35
- [[NSNotificationCenter defaultCenter] removeObserver:observer];
45
+ if (screenshotObserver != nil) {
46
+ [[NSNotificationCenter defaultCenter] removeObserver:screenshotObserver];
47
+ screenshotObserver = nil;
48
+ }
49
+
50
+ if (screenRecordingObserver != nil) {
51
+ [[NSNotificationCenter defaultCenter] removeObserver:screenRecordingObserver];
52
+ screenRecordingObserver = nil;
36
53
  }
37
54
  }
38
55
 
39
56
  - (void)screenshotDetected:(NSNotification *)notification {
40
- if (observer != nil) {
57
+ if (screenshotObserver != nil) {
41
58
  [self sendEventWithName:@"ScreenshotTaken" body:@{}];
42
59
  }
43
60
  }
44
61
 
45
- @end
62
+ - (void)screenRecordingChanged:(NSNotification *)notification {
63
+ if (screenRecordingObserver != nil) {
64
+ BOOL isRecording = [UIScreen mainScreen].isCaptured;
65
+
66
+ [self sendEventWithName:@"ScreenRecordingChanged" body:@{@"isRecording": @(isRecording)}];
67
+ }
68
+ }
69
+
70
+ RCT_EXPORT_METHOD(disableScreenshots) {
71
+ dispatch_async(dispatch_get_main_queue(), ^{
72
+ isProtectionEnabled = YES;
73
+ [self enableTrueScreenshotPrevention];
74
+ });
75
+ }
76
+
77
+ RCT_EXPORT_METHOD(enableScreenshots) {
78
+ dispatch_async(dispatch_get_main_queue(), ^{
79
+ isProtectionEnabled = NO;
80
+ [self disableTrueScreenshotPrevention];
81
+ });
82
+ }
83
+
84
+ RCT_EXPORT_METHOD(isScreenRecording:(RCTPromiseResolveBlock)resolve
85
+ rejecter:(RCTPromiseRejectBlock)reject) {
86
+ BOOL isRecording = [UIScreen mainScreen].isCaptured;
87
+ resolve(@(isRecording));
88
+ }
89
+
90
+ RCT_EXPORT_METHOD(subscribeToScreenRecording) {
91
+ [self startObserving];
92
+ }
93
+
94
+ RCT_EXPORT_METHOD(unsubscribeFromScreenRecording) {
95
+ [self stopObserving];
96
+ }
97
+
98
+ // Screenshot Prevention using Secure Text Field
99
+ - (void)enableTrueScreenshotPrevention {
100
+ if (self.secureTextField == nil) {
101
+ self.secureTextField = [[UITextField alloc] init];
102
+ self.secureTextField.userInteractionEnabled = NO;
103
+ self.secureTextField.secureTextEntry = YES;
104
+
105
+ UIWindow *keyWindow = [self getKeyWindow];
106
+ if (keyWindow != nil) {
107
+ [keyWindow makeKeyAndVisible];
108
+
109
+ // Make the app window a sublayer of the secure text field
110
+ [keyWindow.layer.superlayer addSublayer:self.secureTextField.layer];
111
+
112
+ // Add the window layer as a sublayer of the secure text field's first sublayer
113
+ NSArray *sublayers = self.secureTextField.layer.sublayers;
114
+ if (sublayers.count > 0) {
115
+ [sublayers.firstObject addSublayer:keyWindow.layer];
116
+ }
117
+ }
118
+ } else {
119
+ self.secureTextField.secureTextEntry = YES;
120
+ }
121
+ }
122
+
123
+ - (void)disableTrueScreenshotPrevention {
124
+ if (self.secureTextField != nil) {
125
+ self.secureTextField.secureTextEntry = NO;
126
+ }
127
+ }
128
+
129
+ - (UIWindow *)getKeyWindow {
130
+ UIWindow *keyWindow = nil;
131
+
132
+ NSSet<UIScene *> *connectedScenes = [UIApplication sharedApplication].connectedScenes;
133
+ for (UIScene *scene in connectedScenes) {
134
+ if ([scene isKindOfClass:[UIWindowScene class]]) {
135
+ UIWindowScene *windowScene = (UIWindowScene *)scene;
136
+ for (UIWindow *window in windowScene.windows) {
137
+ if (window.isKeyWindow) {
138
+ keyWindow = window;
139
+ break;
140
+ }
141
+ }
142
+ if (keyWindow) break;
143
+ }
144
+ }
145
+
146
+ if (keyWindow == nil) {
147
+ keyWindow = [UIApplication sharedApplication].keyWindow;
148
+ if (keyWindow == nil) {
149
+ for (UIWindow *window in [UIApplication sharedApplication].windows) {
150
+ if (window.isKeyWindow) {
151
+ keyWindow = window;
152
+ break;
153
+ }
154
+ }
155
+ }
156
+ }
157
+
158
+ return keyWindow;
159
+ }
160
+
161
+ - (void)dealloc {
162
+ [self stopObserving];
163
+ [self disableTrueScreenshotPrevention];
164
+ }
165
+
166
+ @end
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exodus/react-native-screenshot-detector",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
4
4
  "description": "detect when the user takes a screenshot",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\" && exit 1"