react-native-privacy-guard-kit 0.1.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.
- package/LICENSE +20 -0
- package/PrivacyGuardKit.podspec +27 -0
- package/README.md +320 -0
- package/android/CMakeLists.txt +47 -0
- package/android/build.gradle +64 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/java/com/privacyguardkit/PrivacyGuardKitPackage.kt +17 -0
- package/android/src/main/java/com/privacyguardkit/Privacyguardkitmodule .kt +208 -0
- package/android/src/main/java/com/privacyguardkit/Screenshotobserver.kt +66 -0
- package/android/src/main/java/com/privacyguardkit/Secureview.kt +104 -0
- package/android/src/main/java/com/privacyguardkit/Secureviewmanager.kt +27 -0
- package/android/src/main/jni/react/renderer/components/PrivacyGuardKitViewSpec/RNSecureViewComponentDescriptor.h +25 -0
- package/ios/PrivacyGuardKit-Umbrella.h +14 -0
- package/ios/PrivacyGuardKit.m +38 -0
- package/ios/PrivacyGuardKit.swift +221 -0
- package/ios/RNSecureViewComponentView.h +16 -0
- package/ios/RNSecureViewComponentView.mm +84 -0
- package/ios/RNSecureViewManager.mm +48 -0
- package/lib/module/Hooks.js +119 -0
- package/lib/module/Hooks.js.map +1 -0
- package/lib/module/NativePrivacyGuardKit.js +12 -0
- package/lib/module/NativePrivacyGuardKit.js.map +1 -0
- package/lib/module/PrivacyGuardProvider.js +99 -0
- package/lib/module/PrivacyGuardProvider.js.map +1 -0
- package/lib/module/PrivacyGuardkitApi.js +104 -0
- package/lib/module/PrivacyGuardkitApi.js.map +1 -0
- package/lib/module/SecureView.js +24 -0
- package/lib/module/SecureView.js.map +1 -0
- package/lib/module/index.js +16 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/specs/RNSecureViewNativeComponent.ts +19 -0
- package/lib/module/types.js +2 -0
- package/lib/module/types.js.map +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/Hooks.d.ts +29 -0
- package/lib/typescript/src/Hooks.d.ts.map +1 -0
- package/lib/typescript/src/NativePrivacyGuardKit.d.ts +4 -0
- package/lib/typescript/src/NativePrivacyGuardKit.d.ts.map +1 -0
- package/lib/typescript/src/PrivacyGuardProvider.d.ts +30 -0
- package/lib/typescript/src/PrivacyGuardProvider.d.ts.map +1 -0
- package/lib/typescript/src/PrivacyGuardkitApi.d.ts +45 -0
- package/lib/typescript/src/PrivacyGuardkitApi.d.ts.map +1 -0
- package/lib/typescript/src/SecureView.d.ts +10 -0
- package/lib/typescript/src/SecureView.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +6 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/specs/RNSecureViewNativeComponent.d.ts +11 -0
- package/lib/typescript/src/specs/RNSecureViewNativeComponent.d.ts.map +1 -0
- package/lib/typescript/src/types.d.ts +29 -0
- package/lib/typescript/src/types.d.ts.map +1 -0
- package/package.json +174 -0
- package/src/Hooks.ts +138 -0
- package/src/NativePrivacyGuardKit.ts +13 -0
- package/src/PrivacyGuardProvider.tsx +134 -0
- package/src/PrivacyGuardkitApi.ts +123 -0
- package/src/SecureView.tsx +29 -0
- package/src/index.tsx +37 -0
- package/src/specs/RNSecureViewNativeComponent.ts +19 -0
- package/src/types.ts +34 -0
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
package com.privacyguardkit
|
|
2
|
+
|
|
3
|
+
import android.app.Activity
|
|
4
|
+
import android.content.ClipboardManager
|
|
5
|
+
import android.content.Context
|
|
6
|
+
import android.os.Build
|
|
7
|
+
import android.view.WindowManager
|
|
8
|
+
import com.facebook.react.bridge.Promise
|
|
9
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
10
|
+
import com.facebook.react.bridge.ReactContextBaseJavaModule
|
|
11
|
+
import com.facebook.react.bridge.ReactMethod
|
|
12
|
+
import com.facebook.react.bridge.WritableMap
|
|
13
|
+
import com.facebook.react.modules.core.DeviceEventManagerModule
|
|
14
|
+
|
|
15
|
+
class PrivacyGuardKitModule(
|
|
16
|
+
private val reactContext: ReactApplicationContext
|
|
17
|
+
) : ReactContextBaseJavaModule(reactContext) {
|
|
18
|
+
|
|
19
|
+
companion object {
|
|
20
|
+
const val MODULE_NAME = "PrivacyGuardKit"
|
|
21
|
+
const val EVENT_SCREENSHOT_TAKEN = "onScreenshotTaken"
|
|
22
|
+
const val EVENT_SCREEN_RECORDING_STARTED = "onScreenRecordingStarted"
|
|
23
|
+
const val EVENT_SCREEN_RECORDING_STOPPED = "onScreenRecordingStopped"
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
private var isScreenCaptureDisabled = false
|
|
27
|
+
private var isAppSwitcherProtected = false
|
|
28
|
+
private var screenshotObserver: ScreenshotObserver? = null
|
|
29
|
+
|
|
30
|
+
// Helper — safely get the current Activity from the stored context
|
|
31
|
+
private val activity: Activity?
|
|
32
|
+
get() = reactContext.currentActivity
|
|
33
|
+
|
|
34
|
+
override fun getName(): String = MODULE_NAME
|
|
35
|
+
|
|
36
|
+
// ─────────────────────────────────────────────
|
|
37
|
+
// SCREEN CAPTURE
|
|
38
|
+
// ─────────────────────────────────────────────
|
|
39
|
+
|
|
40
|
+
@ReactMethod
|
|
41
|
+
fun disableScreenCapture(promise: Promise) {
|
|
42
|
+
val act = activity
|
|
43
|
+
if (act == null) {
|
|
44
|
+
promise.reject("NO_ACTIVITY", "No current activity available")
|
|
45
|
+
return
|
|
46
|
+
}
|
|
47
|
+
try {
|
|
48
|
+
act.runOnUiThread {
|
|
49
|
+
act.window?.addFlags(WindowManager.LayoutParams.FLAG_SECURE)
|
|
50
|
+
isScreenCaptureDisabled = true
|
|
51
|
+
}
|
|
52
|
+
promise.resolve(true)
|
|
53
|
+
} catch (e: Exception) {
|
|
54
|
+
promise.reject("DISABLE_CAPTURE_ERROR", e.message, e)
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
@ReactMethod
|
|
59
|
+
fun enableScreenCapture(promise: Promise) {
|
|
60
|
+
val act = activity
|
|
61
|
+
if (act == null) {
|
|
62
|
+
promise.reject("NO_ACTIVITY", "No current activity available")
|
|
63
|
+
return
|
|
64
|
+
}
|
|
65
|
+
try {
|
|
66
|
+
act.runOnUiThread {
|
|
67
|
+
act.window?.clearFlags(WindowManager.LayoutParams.FLAG_SECURE)
|
|
68
|
+
isScreenCaptureDisabled = false
|
|
69
|
+
}
|
|
70
|
+
promise.resolve(true)
|
|
71
|
+
} catch (e: Exception) {
|
|
72
|
+
promise.reject("ENABLE_CAPTURE_ERROR", e.message, e)
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
@ReactMethod
|
|
77
|
+
fun isScreenCaptureDisabled(promise: Promise) {
|
|
78
|
+
promise.resolve(isScreenCaptureDisabled)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// ─────────────────────────────────────────────
|
|
82
|
+
// SCREEN RECORDING DETECTION
|
|
83
|
+
// ─────────────────────────────────────────────
|
|
84
|
+
|
|
85
|
+
@ReactMethod
|
|
86
|
+
fun isScreenBeingRecorded(promise: Promise) {
|
|
87
|
+
// Android does not expose a direct public API for this.
|
|
88
|
+
// FLAG_SECURE prevents recording content from being visible.
|
|
89
|
+
// Full detection requires a foreground service with MediaProjection.
|
|
90
|
+
promise.resolve(false)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// ─────────────────────────────────────────────
|
|
94
|
+
// APP SWITCHER PROTECTION
|
|
95
|
+
// FLAG_SECURE covers app-switcher thumbnails on Android
|
|
96
|
+
// ─────────────────────────────────────────────
|
|
97
|
+
|
|
98
|
+
@ReactMethod
|
|
99
|
+
fun enableAppSwitcherProtection(promise: Promise) {
|
|
100
|
+
val act = activity
|
|
101
|
+
if (act == null) {
|
|
102
|
+
promise.reject("NO_ACTIVITY", "No current activity available")
|
|
103
|
+
return
|
|
104
|
+
}
|
|
105
|
+
try {
|
|
106
|
+
act.runOnUiThread {
|
|
107
|
+
act.window?.addFlags(WindowManager.LayoutParams.FLAG_SECURE)
|
|
108
|
+
isAppSwitcherProtected = true
|
|
109
|
+
}
|
|
110
|
+
promise.resolve(true)
|
|
111
|
+
} catch (e: Exception) {
|
|
112
|
+
promise.reject("APP_SWITCHER_ERROR", e.message, e)
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
@ReactMethod
|
|
117
|
+
fun disableAppSwitcherProtection(promise: Promise) {
|
|
118
|
+
val act = activity
|
|
119
|
+
if (act == null) {
|
|
120
|
+
promise.reject("NO_ACTIVITY", "No current activity available")
|
|
121
|
+
return
|
|
122
|
+
}
|
|
123
|
+
try {
|
|
124
|
+
act.runOnUiThread {
|
|
125
|
+
// Only clear the flag if screen capture protection is also off
|
|
126
|
+
if (!isScreenCaptureDisabled) {
|
|
127
|
+
act.window?.clearFlags(WindowManager.LayoutParams.FLAG_SECURE)
|
|
128
|
+
}
|
|
129
|
+
isAppSwitcherProtected = false
|
|
130
|
+
}
|
|
131
|
+
promise.resolve(true)
|
|
132
|
+
} catch (e: Exception) {
|
|
133
|
+
promise.reject("APP_SWITCHER_DISABLE_ERROR", e.message, e)
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// ─────────────────────────────────────────────
|
|
138
|
+
// SCREENSHOT EVENT LISTENER
|
|
139
|
+
// ─────────────────────────────────────────────
|
|
140
|
+
|
|
141
|
+
@ReactMethod
|
|
142
|
+
fun startScreenshotListener(promise: Promise) {
|
|
143
|
+
try {
|
|
144
|
+
screenshotObserver = ScreenshotObserver(reactContext) {
|
|
145
|
+
sendEvent(EVENT_SCREENSHOT_TAKEN, null)
|
|
146
|
+
}
|
|
147
|
+
screenshotObserver?.start()
|
|
148
|
+
promise.resolve(true)
|
|
149
|
+
} catch (e: Exception) {
|
|
150
|
+
promise.reject("SCREENSHOT_LISTENER_ERROR", e.message, e)
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
@ReactMethod
|
|
155
|
+
fun stopScreenshotListener(promise: Promise) {
|
|
156
|
+
try {
|
|
157
|
+
screenshotObserver?.stop()
|
|
158
|
+
screenshotObserver = null
|
|
159
|
+
promise.resolve(true)
|
|
160
|
+
} catch (e: Exception) {
|
|
161
|
+
promise.reject("SCREENSHOT_LISTENER_STOP_ERROR", e.message, e)
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// ─────────────────────────────────────────────
|
|
166
|
+
// CLIPBOARD PROTECTION
|
|
167
|
+
// ─────────────────────────────────────────────
|
|
168
|
+
|
|
169
|
+
@ReactMethod
|
|
170
|
+
fun clearClipboard(promise: Promise) {
|
|
171
|
+
try {
|
|
172
|
+
val clipboard = reactContext
|
|
173
|
+
.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
|
174
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
|
175
|
+
clipboard.clearPrimaryClip()
|
|
176
|
+
} else {
|
|
177
|
+
@Suppress("DEPRECATION")
|
|
178
|
+
clipboard.text = ""
|
|
179
|
+
}
|
|
180
|
+
promise.resolve(true)
|
|
181
|
+
} catch (e: Exception) {
|
|
182
|
+
promise.reject("CLIPBOARD_CLEAR_ERROR", e.message, e)
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// ─────────────────────────────────────────────
|
|
187
|
+
// EVENT EMITTER SUPPORT
|
|
188
|
+
// Required stubs for RN's NativeEventEmitter
|
|
189
|
+
// ─────────────────────────────────────────────
|
|
190
|
+
|
|
191
|
+
@ReactMethod
|
|
192
|
+
fun addListener(eventName: String) { /* Required by RN */ }
|
|
193
|
+
|
|
194
|
+
@ReactMethod
|
|
195
|
+
fun removeListeners(count: Int) { /* Required by RN */ }
|
|
196
|
+
|
|
197
|
+
private fun sendEvent(eventName: String, params: WritableMap?) {
|
|
198
|
+
reactContext
|
|
199
|
+
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
|
|
200
|
+
.emit(eventName, params)
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
override fun invalidate() {
|
|
204
|
+
super.invalidate()
|
|
205
|
+
screenshotObserver?.stop()
|
|
206
|
+
screenshotObserver = null
|
|
207
|
+
}
|
|
208
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
package com.privacyguardkit
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import android.database.ContentObserver
|
|
5
|
+
import android.net.Uri
|
|
6
|
+
import android.os.Handler
|
|
7
|
+
import android.os.Looper
|
|
8
|
+
import android.provider.MediaStore
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Watches the MediaStore for new image entries in the Screenshots folder.
|
|
12
|
+
* Fires [onScreenshotTaken] when a new screenshot is detected.
|
|
13
|
+
*/
|
|
14
|
+
class ScreenshotObserver(
|
|
15
|
+
private val context: Context,
|
|
16
|
+
private val onScreenshotTaken: () -> Unit
|
|
17
|
+
) {
|
|
18
|
+
private var contentObserver: ContentObserver? = null
|
|
19
|
+
|
|
20
|
+
fun start() {
|
|
21
|
+
val handler = Handler(Looper.getMainLooper())
|
|
22
|
+
|
|
23
|
+
contentObserver = object : ContentObserver(handler) {
|
|
24
|
+
override fun onChange(selfChange: Boolean, uri: Uri?) {
|
|
25
|
+
super.onChange(selfChange, uri)
|
|
26
|
+
uri ?: return
|
|
27
|
+
if (isScreenshot(uri)) {
|
|
28
|
+
onScreenshotTaken()
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
context.contentResolver.registerContentObserver(
|
|
34
|
+
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
|
|
35
|
+
true,
|
|
36
|
+
contentObserver!!
|
|
37
|
+
)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
fun stop() {
|
|
41
|
+
contentObserver?.let {
|
|
42
|
+
context.contentResolver.unregisterContentObserver(it)
|
|
43
|
+
}
|
|
44
|
+
contentObserver = null
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
private fun isScreenshot(uri: Uri): Boolean {
|
|
48
|
+
return try {
|
|
49
|
+
val cursor = context.contentResolver.query(
|
|
50
|
+
uri,
|
|
51
|
+
arrayOf(MediaStore.Images.Media.DATA),
|
|
52
|
+
null, null, null
|
|
53
|
+
)
|
|
54
|
+
cursor?.use {
|
|
55
|
+
if (it.moveToFirst()) {
|
|
56
|
+
val path = it.getString(
|
|
57
|
+
it.getColumnIndexOrThrow(MediaStore.Images.Media.DATA)
|
|
58
|
+
)
|
|
59
|
+
path?.lowercase()?.contains("screenshot") == true
|
|
60
|
+
} else false
|
|
61
|
+
} ?: false
|
|
62
|
+
} catch (e: Exception) {
|
|
63
|
+
false
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
package com.privacyguardkit
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import android.view.ActionMode
|
|
5
|
+
import android.view.Menu
|
|
6
|
+
import android.view.MenuItem
|
|
7
|
+
import android.view.View
|
|
8
|
+
import android.view.ViewGroup
|
|
9
|
+
import android.widget.EditText
|
|
10
|
+
import android.widget.TextView
|
|
11
|
+
import com.facebook.react.views.view.ReactViewGroup
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* A Fabric-compatible ReactViewGroup that disables copy/paste
|
|
15
|
+
* for all TextView and EditText children recursively.
|
|
16
|
+
*
|
|
17
|
+
* Extends ReactViewGroup (not plain ViewGroup) so Fabric's
|
|
18
|
+
* SurfaceMountingManager can correctly cast it via IViewGroupManager.
|
|
19
|
+
*/
|
|
20
|
+
class SecureView(context: Context) : ReactViewGroup(context) {
|
|
21
|
+
|
|
22
|
+
private var isCopyPasteDisabled = false
|
|
23
|
+
|
|
24
|
+
fun disableCopyPaste() {
|
|
25
|
+
isCopyPasteDisabled = true
|
|
26
|
+
applyToChildren(this)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
fun enableCopyPaste() {
|
|
30
|
+
isCopyPasteDisabled = false
|
|
31
|
+
restoreChildren(this)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Called by Fabric's SurfaceMountingManager when a child is mounted.
|
|
36
|
+
* Signature must be (child: View) — non-nullable — to match ViewGroup.
|
|
37
|
+
*/
|
|
38
|
+
override fun onViewAdded(child: View) {
|
|
39
|
+
super.onViewAdded(child)
|
|
40
|
+
if (isCopyPasteDisabled) {
|
|
41
|
+
applyToView(child)
|
|
42
|
+
// Also recurse into the child if it's already a group
|
|
43
|
+
if (child is ViewGroup) applyToChildren(child)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// ── Recursive helpers ─────────────────────────────────────
|
|
48
|
+
|
|
49
|
+
private fun applyToChildren(group: ViewGroup) {
|
|
50
|
+
for (i in 0 until group.childCount) {
|
|
51
|
+
val child = group.getChildAt(i)
|
|
52
|
+
applyToView(child)
|
|
53
|
+
if (child is ViewGroup) applyToChildren(child)
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
private fun restoreChildren(group: ViewGroup) {
|
|
58
|
+
for (i in 0 until group.childCount) {
|
|
59
|
+
val child = group.getChildAt(i)
|
|
60
|
+
restoreView(child)
|
|
61
|
+
if (child is ViewGroup) restoreChildren(child)
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
private fun applyToView(view: View) {
|
|
66
|
+
when (view) {
|
|
67
|
+
is EditText -> {
|
|
68
|
+
view.isLongClickable = false
|
|
69
|
+
view.setTextIsSelectable(false)
|
|
70
|
+
view.customSelectionActionModeCallback = BlockActionMode()
|
|
71
|
+
view.customInsertionActionModeCallback = BlockActionMode()
|
|
72
|
+
}
|
|
73
|
+
is TextView -> {
|
|
74
|
+
view.isLongClickable = false
|
|
75
|
+
view.setTextIsSelectable(false)
|
|
76
|
+
view.customSelectionActionModeCallback = BlockActionMode()
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
private fun restoreView(view: View) {
|
|
82
|
+
when (view) {
|
|
83
|
+
is EditText -> {
|
|
84
|
+
view.isLongClickable = true
|
|
85
|
+
view.setTextIsSelectable(true)
|
|
86
|
+
view.customSelectionActionModeCallback = null
|
|
87
|
+
view.customInsertionActionModeCallback = null
|
|
88
|
+
}
|
|
89
|
+
is TextView -> {
|
|
90
|
+
view.isLongClickable = true
|
|
91
|
+
view.setTextIsSelectable(true)
|
|
92
|
+
view.customSelectionActionModeCallback = null
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Blocks the copy/paste/cut context menu from appearing
|
|
99
|
+
private class BlockActionMode : ActionMode.Callback {
|
|
100
|
+
override fun onCreateActionMode(mode: ActionMode?, menu: Menu?): Boolean = false
|
|
101
|
+
override fun onPrepareActionMode(mode: ActionMode?, menu: Menu?): Boolean = false
|
|
102
|
+
override fun onActionItemClicked(mode: ActionMode?, item: MenuItem?): Boolean = false
|
|
103
|
+
override fun onDestroyActionMode(mode: ActionMode?) = Unit
|
|
104
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
package com.privacyguardkit
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.uimanager.ThemedReactContext
|
|
4
|
+
import com.facebook.react.uimanager.ViewGroupManager
|
|
5
|
+
import com.facebook.react.uimanager.annotations.ReactProp
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* ViewGroupManager (not SimpleViewManager) is required for:
|
|
9
|
+
* 1. New Architecture (Fabric) — Fabric casts view managers to
|
|
10
|
+
* IViewGroupManager when the view has children. SimpleViewManager
|
|
11
|
+
* does NOT implement IViewGroupManager, causing the cast crash.
|
|
12
|
+
* 2. SecureView extends ReactViewGroup (a ViewGroup), so it must
|
|
13
|
+
* be managed by a ViewGroupManager anyway.
|
|
14
|
+
*/
|
|
15
|
+
class SecureViewManager : ViewGroupManager<SecureView>() {
|
|
16
|
+
|
|
17
|
+
override fun getName(): String = "RNSecureView"
|
|
18
|
+
|
|
19
|
+
override fun createViewInstance(reactContext: ThemedReactContext): SecureView {
|
|
20
|
+
return SecureView(reactContext)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
@ReactProp(name = "disableCopyPaste", defaultBoolean = false)
|
|
24
|
+
fun setDisableCopyPaste(view: SecureView, disable: Boolean) {
|
|
25
|
+
if (disable) view.disableCopyPaste() else view.enableCopyPaste()
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// android/src/main/jni/react/renderer/components/PrivacyGuardKitViewSpec/
|
|
2
|
+
// RNSecureViewComponentDescriptor.h
|
|
3
|
+
//
|
|
4
|
+
// This file is AUTO-GENERATED by React Native codegen.
|
|
5
|
+
// You should NOT edit it manually — re-run codegen to regenerate.
|
|
6
|
+
// It is provided here for reference only.
|
|
7
|
+
//
|
|
8
|
+
// If autolinking.cpp still cannot find RNSecureViewComponentDescriptor,
|
|
9
|
+
// ensure your build.gradle has:
|
|
10
|
+
// react {
|
|
11
|
+
// libraryName = "PrivacyGuardKitViewSpec"
|
|
12
|
+
// jsRootDir = file("../src/specs")
|
|
13
|
+
// }
|
|
14
|
+
// and run: cd android && ./gradlew generateCodegenArtifactsFromSchema
|
|
15
|
+
|
|
16
|
+
#pragma once
|
|
17
|
+
#include <react/renderer/components/PrivacyGuardKitViewSpec/ShadowNodes.h>
|
|
18
|
+
#include <react/renderer/core/ConcreteComponentDescriptor.h>
|
|
19
|
+
|
|
20
|
+
namespace facebook::react {
|
|
21
|
+
|
|
22
|
+
using RNSecureViewComponentDescriptor =
|
|
23
|
+
ConcreteComponentDescriptor<RNSecureViewShadowNode>;
|
|
24
|
+
|
|
25
|
+
} // namespace facebook::react
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// PrivacyGuardKit-Umbrella.h
|
|
2
|
+
// Public umbrella header for the PrivacyGuardKit framework.
|
|
3
|
+
// CocoaPods generates a module map that imports this file,
|
|
4
|
+
// which is how Swift sees ObjC symbols — no bridging header needed.
|
|
5
|
+
//
|
|
6
|
+
// RULES:
|
|
7
|
+
// - Only list headers that are safe for Swift to import
|
|
8
|
+
// - Do NOT include C++ or Fabric headers here (they break Swift)
|
|
9
|
+
// - The file name must be: <PodName>-Umbrella.h OR listed in s.public_header_files
|
|
10
|
+
|
|
11
|
+
#import <React/RCTBridgeModule.h>
|
|
12
|
+
#import <React/RCTEventEmitter.h>
|
|
13
|
+
#import <React/RCTViewManager.h>
|
|
14
|
+
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// PrivacyGuardKit.m
|
|
2
|
+
// RCT_EXTERN_MODULE and RCT_EXTERN_METHOD must be inside
|
|
3
|
+
// an @interface/@implementation block — the macros expand to
|
|
4
|
+
// ObjC method declarations which require a class context.
|
|
5
|
+
|
|
6
|
+
#import <React/RCTBridgeModule.h>
|
|
7
|
+
#import <React/RCTEventEmitter.h>
|
|
8
|
+
|
|
9
|
+
@interface RCT_EXTERN_MODULE(PrivacyGuardKit, RCTEventEmitter)
|
|
10
|
+
|
|
11
|
+
RCT_EXTERN_METHOD(disableScreenCapture:(RCTPromiseResolveBlock)resolve
|
|
12
|
+
reject:(RCTPromiseRejectBlock)reject)
|
|
13
|
+
|
|
14
|
+
RCT_EXTERN_METHOD(enableScreenCapture:(RCTPromiseResolveBlock)resolve
|
|
15
|
+
reject:(RCTPromiseRejectBlock)reject)
|
|
16
|
+
|
|
17
|
+
RCT_EXTERN_METHOD(isScreenCaptureDisabled:(RCTPromiseResolveBlock)resolve
|
|
18
|
+
reject:(RCTPromiseRejectBlock)reject)
|
|
19
|
+
|
|
20
|
+
RCT_EXTERN_METHOD(isScreenBeingRecorded:(RCTPromiseResolveBlock)resolve
|
|
21
|
+
reject:(RCTPromiseRejectBlock)reject)
|
|
22
|
+
|
|
23
|
+
RCT_EXTERN_METHOD(startScreenshotListener:(RCTPromiseResolveBlock)resolve
|
|
24
|
+
reject:(RCTPromiseRejectBlock)reject)
|
|
25
|
+
|
|
26
|
+
RCT_EXTERN_METHOD(stopScreenshotListener:(RCTPromiseResolveBlock)resolve
|
|
27
|
+
reject:(RCTPromiseRejectBlock)reject)
|
|
28
|
+
|
|
29
|
+
RCT_EXTERN_METHOD(enableAppSwitcherProtection:(RCTPromiseResolveBlock)resolve
|
|
30
|
+
reject:(RCTPromiseRejectBlock)reject)
|
|
31
|
+
|
|
32
|
+
RCT_EXTERN_METHOD(disableAppSwitcherProtection:(RCTPromiseResolveBlock)resolve
|
|
33
|
+
reject:(RCTPromiseRejectBlock)reject)
|
|
34
|
+
|
|
35
|
+
RCT_EXTERN_METHOD(clearClipboard:(RCTPromiseResolveBlock)resolve
|
|
36
|
+
reject:(RCTPromiseRejectBlock)reject)
|
|
37
|
+
|
|
38
|
+
@end
|