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

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.
package/index.ios.js CHANGED
@@ -1,59 +1,88 @@
1
1
  import { NativeEventEmitter, NativeModules } from 'react-native'
2
2
 
3
3
  const { RNScreenshotDetector } = NativeModules
4
+
5
+ console.log('[TEST] RNScreenshotDetector module loaded:', !!RNScreenshotDetector)
6
+ console.log('[TEST] Available methods:', Object.keys(RNScreenshotDetector || {}))
7
+
4
8
  const eventEmitter = new NativeEventEmitter(RNScreenshotDetector)
5
9
 
6
10
  const SCREENSHOT_EVENT = 'ScreenshotTaken'
7
11
  const SCREEN_RECORDING_EVENT = 'ScreenRecordingChanged'
8
12
 
9
13
  const subscribe = (cb) => {
10
- const sub = eventEmitter.addListener(SCREENSHOT_EVENT, (data) => {
11
- cb(data)
12
- })
13
- return () => {
14
- sub.remove()
15
- }
16
- }
17
-
18
- const subscribeToScreenRecording = (cb) => {
19
- if (RNScreenshotDetector.subscribeToScreenRecording) {
20
- RNScreenshotDetector.subscribeToScreenRecording()
14
+ console.log('[TEST] subscribe called - using NEW explicit method!')
15
+
16
+ // Use the more explicit method name internally
17
+ if (RNScreenshotDetector && RNScreenshotDetector.subscribeToScreenshotAndScreenRecording) {
18
+ console.log('[TEST] Calling subscribeToScreenshotAndScreenRecording')
19
+ RNScreenshotDetector.subscribeToScreenshotAndScreenRecording()
20
+ console.log('[TEST] SUCCESS: subscribeToScreenshotAndScreenRecording called')
21
+ } else {
22
+ console.log('[TEST] ERROR: subscribeToScreenshotAndScreenRecording not available!')
21
23
  }
22
24
 
23
- const sub = eventEmitter.addListener(SCREEN_RECORDING_EVENT, (data) => {
25
+ const sub = eventEmitter.addListener(SCREENSHOT_EVENT, (data) => {
26
+ console.log('[TEST] ScreenshotTaken event received:', data)
24
27
  cb(data)
25
28
  })
26
29
  return () => {
30
+ console.log('[TEST] Unsubscribing from screenshot events')
27
31
  sub.remove()
28
- if (RNScreenshotDetector.unsubscribeFromScreenRecording) {
29
- RNScreenshotDetector.unsubscribeFromScreenRecording()
32
+
33
+ // Use the more explicit method name internally
34
+ if (RNScreenshotDetector && RNScreenshotDetector.unsubscribeFromScreenshotAndScreenRecording) {
35
+ console.log('[TEST] Calling unsubscribeFromScreenshotAndScreenRecording')
36
+ RNScreenshotDetector.unsubscribeFromScreenshotAndScreenRecording()
37
+ console.log('[TEST] SUCCESS: unsubscribeFromScreenshotAndScreenRecording called')
38
+ } else {
39
+ console.log('[TEST] ERROR: unsubscribeFromScreenshotAndScreenRecording not available!')
30
40
  }
31
41
  }
32
42
  }
33
43
 
34
44
  const disableScreenshots = () => {
35
- if (RNScreenshotDetector.disableScreenshots) {
45
+ console.log('[TEST] disableScreenshots called')
46
+ if (RNScreenshotDetector && RNScreenshotDetector.disableScreenshots) {
47
+ console.log('[TEST] Calling native disableScreenshots')
36
48
  RNScreenshotDetector.disableScreenshots()
49
+ console.log('[TEST] SUCCESS: disableScreenshots called')
50
+ } else {
51
+ console.log('[TEST] ERROR: disableScreenshots not available!')
37
52
  }
38
53
  }
39
54
 
40
55
  const enableScreenshots = () => {
41
- if (RNScreenshotDetector.enableScreenshots) {
56
+ console.log('[TEST] enableScreenshots called')
57
+ if (RNScreenshotDetector && RNScreenshotDetector.enableScreenshots) {
58
+ console.log('[TEST] Calling native enableScreenshots')
42
59
  RNScreenshotDetector.enableScreenshots()
60
+ console.log('[TEST] SUCCESS: enableScreenshots called')
61
+ } else {
62
+ console.log('[TEST] ERROR: enableScreenshots not available!')
43
63
  }
44
64
  }
45
65
 
46
66
  const isScreenRecording = async () => {
47
- if (RNScreenshotDetector.isScreenRecording) {
48
- return RNScreenshotDetector.isScreenRecording()
67
+ console.log('[TEST] isScreenRecording called')
68
+ if (RNScreenshotDetector && RNScreenshotDetector.isScreenRecording) {
69
+ try {
70
+ const result = await RNScreenshotDetector.isScreenRecording()
71
+ console.log('[TEST] isScreenRecording result:', result)
72
+ return result
73
+ } catch (error) {
74
+ console.log('[TEST] ERROR in isScreenRecording:', error)
75
+ return false
76
+ }
49
77
  } else {
78
+ console.log('[TEST] ERROR: isScreenRecording not available!')
50
79
  return false
51
80
  }
52
81
  }
53
82
 
83
+ // Main API - only expose what's actually used externally
54
84
  const ScreenshotDetector = {
55
85
  subscribe,
56
- subscribeToScreenRecording,
57
86
  disableScreenshots,
58
87
  enableScreenshots,
59
88
  isScreenRecording,
@@ -12,98 +12,138 @@
12
12
  {
13
13
  id screenshotObserver;
14
14
  id screenRecordingObserver;
15
- UIView *securityOverlay;
16
15
  BOOL isProtectionEnabled;
17
16
  }
18
17
 
19
18
  RCT_EXPORT_MODULE();
20
19
 
21
20
  - (NSArray<NSString *> *)supportedEvents {
21
+ NSLog(@"[TEST] supportedEvents called");
22
22
  return @[@"ScreenshotTaken", @"ScreenRecordingChanged"];
23
23
  }
24
24
 
25
25
  - (void)startObserving {
26
+ NSLog(@"[TEST] startObserving called");
26
27
  NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];
27
- screenshotObserver = [[NSNotificationCenter defaultCenter]
28
- addObserverForName:UIApplicationUserDidTakeScreenshotNotification
29
- object:nil
30
- queue:mainQueue
31
- usingBlock:^(NSNotification *notification) {
32
- [self screenshotDetected:notification];
33
- }];
34
28
 
35
- screenRecordingObserver = [[NSNotificationCenter defaultCenter]
36
- addObserverForName:UIScreenCapturedDidChangeNotification
37
- object:nil
38
- queue:mainQueue
39
- usingBlock:^(NSNotification *notification) {
40
- [self screenRecordingChanged:notification];
41
- }];
29
+ if (screenshotObserver == nil) {
30
+ screenshotObserver = [[NSNotificationCenter defaultCenter]
31
+ addObserverForName:UIApplicationUserDidTakeScreenshotNotification
32
+ object:nil
33
+ queue:mainQueue
34
+ usingBlock:^(NSNotification *notification) {
35
+ [self screenshotDetected:notification];
36
+ }];
37
+ NSLog(@"[TEST] Screenshot observer registered successfully");
38
+ } else {
39
+ NSLog(@"[TEST] Screenshot observer already exists");
40
+ }
41
+
42
+ if (screenRecordingObserver == nil) {
43
+ screenRecordingObserver = [[NSNotificationCenter defaultCenter]
44
+ addObserverForName:UIScreenCapturedDidChangeNotification
45
+ object:nil
46
+ queue:mainQueue
47
+ usingBlock:^(NSNotification *notification) {
48
+ [self screenRecordingChanged:notification];
49
+ }];
50
+ NSLog(@"[TEST] Screen recording observer registered successfully");
51
+ } else {
52
+ NSLog(@"[TEST] Screen recording observer already exists");
53
+ }
42
54
  }
43
55
 
44
56
  - (void)stopObserving {
57
+ NSLog(@"[TEST] stopObserving called");
45
58
  if (screenshotObserver != nil) {
46
59
  [[NSNotificationCenter defaultCenter] removeObserver:screenshotObserver];
47
60
  screenshotObserver = nil;
61
+ NSLog(@"[TEST] Screenshot observer removed successfully");
48
62
  }
49
63
 
50
64
  if (screenRecordingObserver != nil) {
51
65
  [[NSNotificationCenter defaultCenter] removeObserver:screenRecordingObserver];
52
66
  screenRecordingObserver = nil;
67
+ NSLog(@"[TEST] Screen recording observer removed successfully");
53
68
  }
54
69
  }
55
70
 
56
71
  - (void)screenshotDetected:(NSNotification *)notification {
72
+ NSLog(@"[TEST] 🚨 SCREENSHOT DETECTED! 🚨");
57
73
  if (screenshotObserver != nil) {
74
+ NSLog(@"[TEST] Sending ScreenshotTaken event to JavaScript");
58
75
  [self sendEventWithName:@"ScreenshotTaken" body:@{}];
76
+ NSLog(@"[TEST] ScreenshotTaken event sent successfully");
77
+ } else {
78
+ NSLog(@"[TEST] ERROR: Screenshot observer is nil, not sending event");
59
79
  }
60
80
  }
61
81
 
62
82
  - (void)screenRecordingChanged:(NSNotification *)notification {
83
+ BOOL isRecording = [UIScreen mainScreen].isCaptured;
84
+ NSLog(@"[TEST] Screen recording changed: %@", isRecording ? @"STARTED" : @"STOPPED");
85
+
63
86
  if (screenRecordingObserver != nil) {
64
- BOOL isRecording = [UIScreen mainScreen].isCaptured;
65
-
87
+ NSLog(@"[TEST] Sending ScreenRecordingChanged event to JavaScript");
66
88
  [self sendEventWithName:@"ScreenRecordingChanged" body:@{@"isRecording": @(isRecording)}];
89
+ NSLog(@"[TEST] ScreenRecordingChanged event sent successfully");
90
+ } else {
91
+ NSLog(@"[TEST] ERROR: Screen recording observer is nil, not sending event");
67
92
  }
68
93
  }
69
94
 
70
95
  RCT_EXPORT_METHOD(disableScreenshots) {
96
+ NSLog(@"[TEST] disableScreenshots called");
71
97
  dispatch_async(dispatch_get_main_queue(), ^{
72
98
  isProtectionEnabled = YES;
99
+ NSLog(@"[TEST] Protection enabled, calling enableTrueScreenshotPrevention");
73
100
  [self enableTrueScreenshotPrevention];
101
+ NSLog(@"[TEST] disableScreenshots completed");
74
102
  });
75
103
  }
76
104
 
77
105
  RCT_EXPORT_METHOD(enableScreenshots) {
106
+ NSLog(@"[TEST] enableScreenshots called");
78
107
  dispatch_async(dispatch_get_main_queue(), ^{
79
108
  isProtectionEnabled = NO;
109
+ NSLog(@"[TEST] Protection disabled, calling disableTrueScreenshotPrevention");
80
110
  [self disableTrueScreenshotPrevention];
111
+ NSLog(@"[TEST] enableScreenshots completed");
81
112
  });
82
113
  }
83
114
 
84
115
  RCT_EXPORT_METHOD(isScreenRecording:(RCTPromiseResolveBlock)resolve
85
116
  rejecter:(RCTPromiseRejectBlock)reject) {
86
117
  BOOL isRecording = [UIScreen mainScreen].isCaptured;
118
+ NSLog(@"[TEST] isScreenRecording called, result: %@", isRecording ? @"YES" : @"NO");
87
119
  resolve(@(isRecording));
88
120
  }
89
121
 
90
- RCT_EXPORT_METHOD(subscribeToScreenRecording) {
122
+ // Clear and explicit method names
123
+ RCT_EXPORT_METHOD(subscribeToScreenshotAndScreenRecording) {
124
+ NSLog(@"[TEST] subscribeToScreenshotAndScreenRecording called - NEW EXPLICIT METHOD!");
91
125
  [self startObserving];
126
+ NSLog(@"[TEST] subscribeToScreenshotAndScreenRecording completed");
92
127
  }
93
128
 
94
- RCT_EXPORT_METHOD(unsubscribeFromScreenRecording) {
129
+ RCT_EXPORT_METHOD(unsubscribeFromScreenshotAndScreenRecording) {
130
+ NSLog(@"[TEST] unsubscribeFromScreenshotAndScreenRecording called");
95
131
  [self stopObserving];
132
+ NSLog(@"[TEST] unsubscribeFromScreenshotAndScreenRecording completed");
96
133
  }
97
134
 
98
135
  // Screenshot Prevention using Secure Text Field
99
136
  - (void)enableTrueScreenshotPrevention {
137
+ NSLog(@"[TEST] enableTrueScreenshotPrevention called");
100
138
  if (self.secureTextField == nil) {
139
+ NSLog(@"[TEST] Creating new secureTextField");
101
140
  self.secureTextField = [[UITextField alloc] init];
102
141
  self.secureTextField.userInteractionEnabled = NO;
103
142
  self.secureTextField.secureTextEntry = YES;
104
143
 
105
144
  UIWindow *keyWindow = [self getKeyWindow];
106
145
  if (keyWindow != nil) {
146
+ NSLog(@"[TEST] Key window found, setting up secure text field");
107
147
  [keyWindow makeKeyAndVisible];
108
148
 
109
149
  // Make the app window a sublayer of the secure text field
@@ -113,29 +153,46 @@ RCT_EXPORT_METHOD(unsubscribeFromScreenRecording) {
113
153
  NSArray *sublayers = self.secureTextField.layer.sublayers;
114
154
  if (sublayers.count > 0) {
115
155
  [sublayers.firstObject addSublayer:keyWindow.layer];
156
+ NSLog(@"[TEST] ✅ Secure text field configured successfully - Screenshot prevention ACTIVE!");
157
+ } else {
158
+ NSLog(@"[TEST] ❌ No sublayers found in secure text field");
116
159
  }
160
+ } else {
161
+ NSLog(@"[TEST] ❌ Key window not found!");
117
162
  }
118
163
  } else {
164
+ NSLog(@"[TEST] Secure text field already exists, enabling secureTextEntry");
119
165
  self.secureTextField.secureTextEntry = YES;
166
+ NSLog(@"[TEST] ✅ Secure text field re-enabled - Screenshot prevention ACTIVE!");
120
167
  }
121
168
  }
122
169
 
123
170
  - (void)disableTrueScreenshotPrevention {
171
+ NSLog(@"[TEST] disableTrueScreenshotPrevention called");
124
172
  if (self.secureTextField != nil) {
173
+ NSLog(@"[TEST] Disabling secureTextEntry");
125
174
  self.secureTextField.secureTextEntry = NO;
175
+ NSLog(@"[TEST] ✅ Screenshot prevention DISABLED");
176
+ } else {
177
+ NSLog(@"[TEST] Secure text field is nil");
126
178
  }
127
179
  }
128
180
 
129
181
  - (UIWindow *)getKeyWindow {
182
+ NSLog(@"[TEST] getKeyWindow called");
130
183
  UIWindow *keyWindow = nil;
131
184
 
132
185
  NSSet<UIScene *> *connectedScenes = [UIApplication sharedApplication].connectedScenes;
186
+ NSLog(@"[TEST] Connected scenes count: %lu", (unsigned long)connectedScenes.count);
187
+
133
188
  for (UIScene *scene in connectedScenes) {
134
189
  if ([scene isKindOfClass:[UIWindowScene class]]) {
135
190
  UIWindowScene *windowScene = (UIWindowScene *)scene;
191
+ NSLog(@"[TEST] Found window scene with %lu windows", (unsigned long)windowScene.windows.count);
136
192
  for (UIWindow *window in windowScene.windows) {
137
193
  if (window.isKeyWindow) {
138
194
  keyWindow = window;
195
+ NSLog(@"[TEST] ✅ Found key window using UIScene method");
139
196
  break;
140
197
  }
141
198
  }
@@ -144,21 +201,14 @@ RCT_EXPORT_METHOD(unsubscribeFromScreenRecording) {
144
201
  }
145
202
 
146
203
  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
- }
204
+ NSLog(@"[TEST] Key window not found using UIScene method!");
156
205
  }
157
206
 
158
207
  return keyWindow;
159
208
  }
160
209
 
161
210
  - (void)dealloc {
211
+ NSLog(@"[TEST] dealloc called");
162
212
  [self stopObserving];
163
213
  [self disableTrueScreenshotPrevention];
164
214
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exodus/react-native-screenshot-detector",
3
- "version": "1.2.0",
3
+ "version": "1.2.1",
4
4
  "description": "detect when the user takes a screenshot",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\" && exit 1"