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