@datadog/mobile-react-native-session-replay 2.7.0 → 2.8.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/DatadogSDKReactNativeSessionReplay.podspec +11 -8
- package/android/build.gradle +9 -1
- package/android/gradle.properties +1 -0
- package/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/views/DdPrivacyView.kt +59 -0
- package/android/src/main/res/values/ids.xml +12 -0
- package/android/src/newarch/kotlin/com/datadog/reactnative/sessionreplay/views/DdPrivacyViewManager.kt +50 -0
- package/android/src/oldarch/kotlin/com/datadog/reactnative/sessionreplay/views/DdPrivacyViewManager.kt +43 -0
- package/android/src/rn76/kotlin/com/datadog/reactnative/sessionreplay/utils/ReactViewBackgroundDrawableUtils.kt +1 -1
- package/android/src/{main → rnpost74}/kotlin/com/datadog/reactnative/sessionreplay/DdSDKReactNativeSessionReplayPackage.kt +9 -2
- package/android/src/rnpre74/kotlin/com/datadog/reactnative/sessionreplay/DdSDKReactNativeSessionReplayPackage.kt +31 -0
- package/ios/Sources/DdPrivacyOverrider.swift +71 -0
- package/ios/Sources/DdPrivacyViewFabric.mm +54 -0
- package/ios/Sources/DdPrivacyViewPaper.m +58 -0
- package/ios/Sources/RCTFabricWrapper.mm +1 -2
- package/ios/Sources/RCTTextViewRecorder.swift +20 -5
- package/lib/commonjs/components/SessionReplayView/HideView.js +34 -0
- package/lib/commonjs/components/SessionReplayView/HideView.js.map +1 -0
- package/lib/commonjs/components/SessionReplayView/MaskAllView.js +44 -0
- package/lib/commonjs/components/SessionReplayView/MaskAllView.js.map +1 -0
- package/lib/commonjs/components/SessionReplayView/MaskNoneView.js +41 -0
- package/lib/commonjs/components/SessionReplayView/MaskNoneView.js.map +1 -0
- package/lib/commonjs/components/SessionReplayView/PrivacyView.js +46 -0
- package/lib/commonjs/components/SessionReplayView/PrivacyView.js.map +1 -0
- package/lib/commonjs/components/SessionReplayView/index.js +40 -0
- package/lib/commonjs/components/SessionReplayView/index.js.map +1 -0
- package/lib/commonjs/index.js +7 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/specs/DdPrivacyView.js +19 -0
- package/lib/commonjs/specs/DdPrivacyView.js.map +1 -0
- package/lib/commonjs/specs/DdPrivacyViewNativeComponent.js +17 -0
- package/lib/commonjs/specs/DdPrivacyViewNativeComponent.js.map +1 -0
- package/lib/commonjs/specs/DdPrivacyViewPaper.js +16 -0
- package/lib/commonjs/specs/DdPrivacyViewPaper.js.map +1 -0
- package/lib/commonjs/types/DdPrivacyView.js +6 -0
- package/lib/commonjs/types/DdPrivacyView.js.map +1 -0
- package/lib/module/components/SessionReplayView/HideView.js +28 -0
- package/lib/module/components/SessionReplayView/HideView.js.map +1 -0
- package/lib/module/components/SessionReplayView/MaskAllView.js +37 -0
- package/lib/module/components/SessionReplayView/MaskAllView.js.map +1 -0
- package/lib/module/components/SessionReplayView/MaskNoneView.js +35 -0
- package/lib/module/components/SessionReplayView/MaskNoneView.js.map +1 -0
- package/lib/module/components/SessionReplayView/PrivacyView.js +39 -0
- package/lib/module/components/SessionReplayView/PrivacyView.js.map +1 -0
- package/lib/module/components/SessionReplayView/index.js +35 -0
- package/lib/module/components/SessionReplayView/index.js.map +1 -0
- package/lib/module/index.js +2 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/specs/DdPrivacyView.js +12 -0
- package/lib/module/specs/DdPrivacyView.js.map +1 -0
- package/lib/module/specs/DdPrivacyViewNativeComponent.js +11 -0
- package/lib/module/specs/DdPrivacyViewNativeComponent.js.map +1 -0
- package/lib/module/specs/DdPrivacyViewPaper.js +10 -0
- package/lib/module/specs/DdPrivacyViewPaper.js.map +1 -0
- package/lib/module/types/DdPrivacyView.js +2 -0
- package/lib/module/types/DdPrivacyView.js.map +1 -0
- package/lib/typescript/components/SessionReplayView/HideView.d.ts +11 -0
- package/lib/typescript/components/SessionReplayView/HideView.d.ts.map +1 -0
- package/lib/typescript/components/SessionReplayView/MaskAllView.d.ts +23 -0
- package/lib/typescript/components/SessionReplayView/MaskAllView.d.ts.map +1 -0
- package/lib/typescript/components/SessionReplayView/MaskNoneView.d.ts +14 -0
- package/lib/typescript/components/SessionReplayView/MaskNoneView.d.ts.map +1 -0
- package/lib/typescript/components/SessionReplayView/PrivacyView.d.ts +36 -0
- package/lib/typescript/components/SessionReplayView/PrivacyView.d.ts.map +1 -0
- package/lib/typescript/components/SessionReplayView/index.d.ts +28 -0
- package/lib/typescript/components/SessionReplayView/index.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +2 -0
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/specs/DdPrivacyView.d.ts +3 -0
- package/lib/typescript/specs/DdPrivacyView.d.ts.map +1 -0
- package/lib/typescript/specs/DdPrivacyViewNativeComponent.d.ts +10 -0
- package/lib/typescript/specs/DdPrivacyViewNativeComponent.d.ts.map +1 -0
- package/lib/typescript/specs/DdPrivacyViewPaper.d.ts +4 -0
- package/lib/typescript/specs/DdPrivacyViewPaper.d.ts.map +1 -0
- package/lib/typescript/types/DdPrivacyView.d.ts +8 -0
- package/lib/typescript/types/DdPrivacyView.d.ts.map +1 -0
- package/package.json +3 -3
- package/src/components/SessionReplayView/HideView.tsx +25 -0
- package/src/components/SessionReplayView/MaskAllView.tsx +53 -0
- package/src/components/SessionReplayView/MaskNoneView.tsx +40 -0
- package/src/components/SessionReplayView/PrivacyView.tsx +67 -0
- package/src/components/SessionReplayView/index.ts +34 -0
- package/src/index.ts +3 -0
- package/src/specs/DdPrivacyView.ts +17 -0
- package/src/specs/DdPrivacyViewNativeComponent.ts +19 -0
- package/src/specs/DdPrivacyViewPaper.ts +15 -0
- package/src/types/DdPrivacyView.ts +14 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
require "json"
|
|
2
2
|
|
|
3
3
|
package = JSON.parse(File.read(File.join(__dir__, "package.json")))
|
|
4
|
+
folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32'
|
|
4
5
|
|
|
5
6
|
Pod::Spec.new do |s|
|
|
6
7
|
s.name = "DatadogSDKReactNativeSessionReplay"
|
|
@@ -13,13 +14,12 @@ Pod::Spec.new do |s|
|
|
|
13
14
|
s.platforms = { :ios => "12.0", :tvos => "12.0" }
|
|
14
15
|
s.source = { :git => "https://github.com/DataDog/dd-sdk-reactnative.git", :tag => "#{s.version}" }
|
|
15
16
|
|
|
16
|
-
|
|
17
17
|
s.source_files = "ios/Sources/*.{h,m,mm,swift}"
|
|
18
|
-
|
|
18
|
+
|
|
19
19
|
s.dependency "React-Core"
|
|
20
20
|
|
|
21
21
|
# /!\ Remember to keep the version in sync with DatadogSDKReactNative.podspec
|
|
22
|
-
s.dependency 'DatadogSessionReplay', '~> 2.
|
|
22
|
+
s.dependency 'DatadogSessionReplay', '~> 2.27.0'
|
|
23
23
|
s.dependency 'DatadogSDKReactNative'
|
|
24
24
|
|
|
25
25
|
s.test_spec 'Tests' do |test_spec|
|
|
@@ -28,16 +28,19 @@ Pod::Spec.new do |s|
|
|
|
28
28
|
test_spec.platforms = { :ios => "13.4", :tvos => "13.4" }
|
|
29
29
|
end
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
# This guard prevents installing the dependencies when we run `pod install` in the old architecture.
|
|
33
|
-
# The `install_modules_dependencies` function is only available from RN 0.71, the new architecture is not
|
|
34
|
-
# supported on earlier RN versions.
|
|
35
31
|
if ENV['RCT_NEW_ARCH_ENABLED'] == '1' then
|
|
32
|
+
s.compiler_flags = folly_compiler_flags + " -DRCT_NEW_ARCH_ENABLED=1"
|
|
33
|
+
|
|
36
34
|
s.pod_target_xcconfig = {
|
|
37
35
|
"DEFINES_MODULE" => "YES",
|
|
38
|
-
"
|
|
36
|
+
"CLANG_CXX_LANGUAGE_STANDARD" => "c++17"
|
|
39
37
|
}
|
|
38
|
+
end
|
|
40
39
|
|
|
40
|
+
if respond_to?(:install_modules_dependencies, true)
|
|
41
41
|
install_modules_dependencies(s)
|
|
42
|
+
# else
|
|
43
|
+
# s.dependency "React-Core"
|
|
42
44
|
end
|
|
45
|
+
|
|
43
46
|
end
|
package/android/build.gradle
CHANGED
|
@@ -120,7 +120,7 @@ android {
|
|
|
120
120
|
}
|
|
121
121
|
|
|
122
122
|
defaultConfig {
|
|
123
|
-
minSdkVersion
|
|
123
|
+
minSdkVersion getExtOrIntegerDefault('minSdkVersion')
|
|
124
124
|
targetSdkVersion getExtOrIntegerDefault('targetSdkVersion')
|
|
125
125
|
versionCode 1
|
|
126
126
|
versionName "1.0"
|
|
@@ -146,6 +146,14 @@ android {
|
|
|
146
146
|
} else {
|
|
147
147
|
java.srcDirs += ['src/rnlegacy/kotlin']
|
|
148
148
|
}
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
if (reactNativeMinorVersion >= 74) {
|
|
152
|
+
java.srcDirs += ['src/rnpost74/kotlin']
|
|
153
|
+
} else {
|
|
154
|
+
java.srcDirs += ['src/rnpre74/kotlin']
|
|
155
|
+
}
|
|
156
|
+
|
|
149
157
|
}
|
|
150
158
|
test {
|
|
151
159
|
java.srcDir("src/test/kotlin")
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
DatadogSDKReactNativeSessionReplay_kotlinVersion=1.8.21
|
|
2
2
|
DatadogSDKReactNativeSessionReplay_compileSdkVersion=33
|
|
3
|
+
DatadogSDKReactNativeSessionReplay_minSdkVersion=21
|
|
3
4
|
DatadogSDKReactNativeSessionReplay_buildToolsVersion=33.0.0
|
|
4
5
|
DatadogSDKReactNativeSessionReplay_targetSdkVersion=33
|
|
5
6
|
android.useAndroidX=true
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
|
|
3
|
+
* This product includes software developed at Datadog (https://www.datadoghq.com/).
|
|
4
|
+
* Copyright 2016-Present Datadog, Inc.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
package com.datadog.reactnative.sessionreplay.views
|
|
8
|
+
|
|
9
|
+
import android.content.Context
|
|
10
|
+
import com.datadog.reactnative.sessionreplay.R
|
|
11
|
+
import com.facebook.react.views.view.ReactViewGroup
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Native React Native UI element that inherits from ReactViewGroup and exposes extra properties.
|
|
15
|
+
*/
|
|
16
|
+
class DdPrivacyView(context: Context) : ReactViewGroup(context) {
|
|
17
|
+
/**
|
|
18
|
+
* Defines the way text and input should be masked.
|
|
19
|
+
*/
|
|
20
|
+
var textAndInputPrivacy: String? = null
|
|
21
|
+
set(value) {
|
|
22
|
+
field = value
|
|
23
|
+
this.setTag(R.id.datadog_text_and_input_privacy, value)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Defines the way images should be masked.
|
|
28
|
+
*/
|
|
29
|
+
var imagePrivacy: String? = null
|
|
30
|
+
set(value) {
|
|
31
|
+
field = value
|
|
32
|
+
this.setTag(R.id.datadog_image_privacy, value)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Defines the way user touches should be masked.
|
|
37
|
+
*/
|
|
38
|
+
var touchPrivacy: String? = null
|
|
39
|
+
set(value) {
|
|
40
|
+
field = value
|
|
41
|
+
this.setTag(R.id.datadog_touch_privacy, value)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Defines the way certain parts of the UI can be set to hidden.
|
|
46
|
+
*/
|
|
47
|
+
var hide: Boolean = false
|
|
48
|
+
set(value) {
|
|
49
|
+
field = value
|
|
50
|
+
this.setTag(R.id.datadog_hidden, value)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
init {
|
|
54
|
+
this.setTag(R.id.datadog_hidden, this.hide)
|
|
55
|
+
this.setTag(R.id.datadog_image_privacy, this.imagePrivacy)
|
|
56
|
+
this.setTag(R.id.datadog_text_and_input_privacy, this.textAndInputPrivacy)
|
|
57
|
+
this.setTag(R.id.datadog_touch_privacy, this.touchPrivacy)
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?><!--
|
|
2
|
+
~ Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
|
|
3
|
+
~ This product includes software developed at Datadog (https://www.datadoghq.com/).
|
|
4
|
+
~ Copyright 2016-Present Datadog, Inc.
|
|
5
|
+
-->
|
|
6
|
+
|
|
7
|
+
<resources>
|
|
8
|
+
<item name="datadog_hidden" type="id"/>
|
|
9
|
+
<item name="datadog_image_privacy" type="id"/>
|
|
10
|
+
<item name="datadog_text_and_input_privacy" type="id"/>
|
|
11
|
+
<item name="datadog_touch_privacy" type="id"/>
|
|
12
|
+
</resources>
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
|
|
3
|
+
* This product includes software developed at Datadog (https://www.datadoghq.com/).
|
|
4
|
+
* Copyright 2016-Present Datadog, Inc.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
package com.datadog.reactnative.sessionreplay.views
|
|
8
|
+
|
|
9
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
10
|
+
import com.facebook.react.uimanager.ThemedReactContext
|
|
11
|
+
import com.facebook.react.uimanager.ViewGroupManager
|
|
12
|
+
import com.facebook.react.uimanager.ViewManagerDelegate
|
|
13
|
+
import com.facebook.react.uimanager.annotations.ReactProp
|
|
14
|
+
import com.facebook.react.viewmanagers.DdPrivacyViewManagerDelegate
|
|
15
|
+
import com.facebook.react.viewmanagers.DdPrivacyViewManagerInterface
|
|
16
|
+
|
|
17
|
+
class DdPrivacyViewManager(context: ReactApplicationContext) : ViewGroupManager<DdPrivacyView>(),
|
|
18
|
+
DdPrivacyViewManagerInterface<DdPrivacyView> {
|
|
19
|
+
companion object {
|
|
20
|
+
const val REACT_CLASS = "DdPrivacyView"
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
private val delegate: DdPrivacyViewManagerDelegate<DdPrivacyView, DdPrivacyViewManager> = DdPrivacyViewManagerDelegate(this)
|
|
24
|
+
|
|
25
|
+
override fun getDelegate(): ViewManagerDelegate<DdPrivacyView> = delegate
|
|
26
|
+
|
|
27
|
+
override fun getName(): String = REACT_CLASS
|
|
28
|
+
|
|
29
|
+
override fun createViewInstance(context: ThemedReactContext): DdPrivacyView = DdPrivacyView(context)
|
|
30
|
+
|
|
31
|
+
@ReactProp(name = "hide")
|
|
32
|
+
override fun setHide(view: DdPrivacyView?, value: Boolean) {
|
|
33
|
+
view?.let { view.hide = value }
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
@ReactProp(name = "textAndInputPrivacy")
|
|
37
|
+
override fun setTextAndInputPrivacy(view: DdPrivacyView?, value: String?) {
|
|
38
|
+
view?.let { view.textAndInputPrivacy = value }
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
@ReactProp(name = "imagePrivacy")
|
|
42
|
+
override fun setImagePrivacy(view: DdPrivacyView?, value: String?) {
|
|
43
|
+
view?.let { view.imagePrivacy = value }
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
@ReactProp(name = "touchPrivacy")
|
|
47
|
+
override fun setTouchPrivacy(view: DdPrivacyView?, value: String?) {
|
|
48
|
+
view?.let { view.touchPrivacy = value }
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
|
|
3
|
+
* This product includes software developed at Datadog (https://www.datadoghq.com/).
|
|
4
|
+
* Copyright 2016-Present Datadog, Inc.
|
|
5
|
+
*/
|
|
6
|
+
package com.datadog.reactnative.sessionreplay.views
|
|
7
|
+
|
|
8
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
9
|
+
import com.facebook.react.uimanager.ThemedReactContext
|
|
10
|
+
import com.facebook.react.uimanager.ViewGroupManager
|
|
11
|
+
import com.facebook.react.uimanager.annotations.ReactProp
|
|
12
|
+
|
|
13
|
+
class DdPrivacyViewManager(context: ReactApplicationContext) : ViewGroupManager<DdPrivacyView>() {
|
|
14
|
+
companion object {
|
|
15
|
+
const val REACT_CLASS = "DdPrivacyView"
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
override fun getName(): String = REACT_CLASS
|
|
19
|
+
|
|
20
|
+
override fun createViewInstance(context: ThemedReactContext): DdPrivacyView {
|
|
21
|
+
return DdPrivacyView(context)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
@ReactProp(name = "hide")
|
|
25
|
+
fun setHide(view: DdPrivacyView?, value: Boolean) {
|
|
26
|
+
view?.let { view.hide = value }
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
@ReactProp(name = "textAndInputPrivacy")
|
|
30
|
+
fun setTextAndInputPrivacy(view: DdPrivacyView?, value: String?) {
|
|
31
|
+
view?.let { view.textAndInputPrivacy = value }
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
@ReactProp(name = "imagePrivacy")
|
|
35
|
+
fun setImagePrivacy(view: DdPrivacyView?, value: String?) {
|
|
36
|
+
view?.let { view.imagePrivacy = value }
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
@ReactProp(name = "touchPrivacy")
|
|
40
|
+
fun setTouchPrivacy(view: DdPrivacyView?, value: String?) {
|
|
41
|
+
view?.let { view.touchPrivacy = value }
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -42,7 +42,7 @@ internal class ReactViewBackgroundDrawableUtils : DrawableUtils() {
|
|
|
42
42
|
|
|
43
43
|
@OptIn(UnstableReactNativeAPI::class)
|
|
44
44
|
override fun getReactBackgroundFromDrawable(drawable: Drawable?): Drawable? {
|
|
45
|
-
return when(drawable) {
|
|
45
|
+
return when (drawable) {
|
|
46
46
|
is CSSBackgroundDrawable -> drawable
|
|
47
47
|
is InsetDrawable -> getReactBackgroundFromDrawable(drawable.drawable)
|
|
48
48
|
is LayerDrawable -> getDrawableFromLayerDrawable(drawable)
|
|
@@ -6,16 +6,22 @@
|
|
|
6
6
|
|
|
7
7
|
package com.datadog.reactnative.sessionreplay
|
|
8
8
|
|
|
9
|
-
import com.
|
|
9
|
+
import com.datadog.reactnative.sessionreplay.views.DdPrivacyViewManager
|
|
10
|
+
import com.facebook.react.BaseReactPackage
|
|
10
11
|
import com.facebook.react.bridge.NativeModule
|
|
11
12
|
import com.facebook.react.bridge.ReactApplicationContext
|
|
12
13
|
import com.facebook.react.module.model.ReactModuleInfo
|
|
13
14
|
import com.facebook.react.module.model.ReactModuleInfoProvider
|
|
15
|
+
import com.facebook.react.uimanager.ViewManager
|
|
14
16
|
|
|
15
17
|
/**
|
|
16
18
|
* Package of native dd-sdk-reactnative native modules.
|
|
17
19
|
*/
|
|
18
|
-
class DdSDKReactNativeSessionReplayPackage :
|
|
20
|
+
class DdSDKReactNativeSessionReplayPackage : BaseReactPackage() {
|
|
21
|
+
override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
|
|
22
|
+
return listOf(DdPrivacyViewManager(reactContext))
|
|
23
|
+
}
|
|
24
|
+
|
|
19
25
|
override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? {
|
|
20
26
|
return when (name) {
|
|
21
27
|
DdSessionReplayImplementation.NAME -> DdSessionReplay(reactContext)
|
|
@@ -43,4 +49,5 @@ class DdSDKReactNativeSessionReplayPackage : TurboReactPackage() {
|
|
|
43
49
|
moduleInfos
|
|
44
50
|
}
|
|
45
51
|
}
|
|
52
|
+
|
|
46
53
|
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
|
|
3
|
+
* This product includes software developed at Datadog (https://www.datadoghq.com/).
|
|
4
|
+
* Copyright 2016-Present Datadog, Inc.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
package com.datadog.reactnative.sessionreplay
|
|
8
|
+
|
|
9
|
+
import com.datadog.reactnative.sessionreplay.views.DdPrivacyViewManager
|
|
10
|
+
import com.facebook.react.ReactPackage
|
|
11
|
+
import com.facebook.react.bridge.NativeModule
|
|
12
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
13
|
+
import com.facebook.react.uimanager.ViewManager
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Package of native dd-sdk-reactnative native modules.
|
|
17
|
+
*/
|
|
18
|
+
class DdSDKReactNativeSessionReplayPackage : ReactPackage {
|
|
19
|
+
|
|
20
|
+
override fun createViewManagers(
|
|
21
|
+
reactContext: ReactApplicationContext
|
|
22
|
+
): List<ViewManager<*, *>> {
|
|
23
|
+
return listOf(DdPrivacyViewManager(reactContext))
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
override fun createNativeModules(
|
|
27
|
+
reactContext: ReactApplicationContext
|
|
28
|
+
): List<NativeModule> {
|
|
29
|
+
return listOf(DdSessionReplay(reactContext))
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import ObjectiveC
|
|
2
|
+
import UIKit
|
|
3
|
+
@_spi(objc) import DatadogSessionReplay
|
|
4
|
+
|
|
5
|
+
@objc public class DdPrivacyOverrider: NSObject {
|
|
6
|
+
@objc public static func setOverrides(
|
|
7
|
+
for view: UIView,
|
|
8
|
+
textPrivacy: NSString?,
|
|
9
|
+
imagePrivacy: NSString?,
|
|
10
|
+
touchPrivacy: NSString?,
|
|
11
|
+
hide: Bool
|
|
12
|
+
) {
|
|
13
|
+
let wrapper = objc_SessionReplayPrivacyOverrides(view: view)
|
|
14
|
+
|
|
15
|
+
if let raw = textPrivacy as String?,
|
|
16
|
+
let val = mapTextPrivacy(raw)
|
|
17
|
+
{
|
|
18
|
+
wrapper.textAndInputPrivacy = val
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if let raw = imagePrivacy as String?,
|
|
22
|
+
let val = mapImagePrivacy(raw)
|
|
23
|
+
{
|
|
24
|
+
wrapper.imagePrivacy = val
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if let raw = touchPrivacy as String?,
|
|
28
|
+
let val = mapTouchPrivacy(raw)
|
|
29
|
+
{
|
|
30
|
+
wrapper.touchPrivacy = val
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
wrapper.hide = NSNumber(value: hide)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
private static func mapTextPrivacy(_ string: String) -> objc_TextAndInputPrivacyLevelOverride? {
|
|
37
|
+
switch string.uppercased() {
|
|
38
|
+
case "MASK_SENSITIVE_INPUTS": return .maskSensitiveInputs
|
|
39
|
+
case "MASK_ALL_INPUTS": return .maskAllInputs
|
|
40
|
+
case "MASK_ALL": return .maskAll
|
|
41
|
+
default: return objc_TextAndInputPrivacyLevelOverride.none
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
private static func mapImagePrivacy(_ string: String) -> objc_ImagePrivacyLevelOverride? {
|
|
46
|
+
switch string.uppercased() {
|
|
47
|
+
case "MASK_NONE": return .maskNone
|
|
48
|
+
case "MASK_NON_BUNDLED_ONLY": return .maskNonBundledOnly
|
|
49
|
+
case "MASK_ALL": return .maskAll
|
|
50
|
+
default: return objc_ImagePrivacyLevelOverride.none
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
private static func mapTouchPrivacy(_ string: String) -> objc_TouchPrivacyLevelOverride? {
|
|
55
|
+
switch string.uppercased() {
|
|
56
|
+
case "SHOW": return .show
|
|
57
|
+
case "HIDE": return .hide
|
|
58
|
+
default: return objc_TouchPrivacyLevelOverride.none
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
@objc public static func debugPrint(for view: UIView) {
|
|
63
|
+
let wrapper = objc_SessionReplayPrivacyOverrides(view: view)
|
|
64
|
+
print("""
|
|
65
|
+
- text: \(wrapper.textAndInputPrivacy)
|
|
66
|
+
- image: \(wrapper.imagePrivacy)
|
|
67
|
+
- touch: \(wrapper.touchPrivacy)
|
|
68
|
+
- hide: \(String(describing: wrapper.hide))
|
|
69
|
+
""")
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
|
|
3
|
+
* This product includes software developed at Datadog (https://www.datadoghq.com/).
|
|
4
|
+
* Copyright 2016-Present Datadog, Inc.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
#if RCT_NEW_ARCH_ENABLED
|
|
8
|
+
#import <React/RCTViewComponentView.h>
|
|
9
|
+
#import <react/renderer/components/DdSDKReactNativeSessionReplay/ComponentDescriptors.h>
|
|
10
|
+
#import <react/renderer/components/DdSDKReactNativeSessionReplay/EventEmitters.h>
|
|
11
|
+
#import <react/renderer/components/DdSDKReactNativeSessionReplay/Props.h>
|
|
12
|
+
#import <react/renderer/components/DdSDKReactNativeSessionReplay/RCTComponentViewHelpers.h>
|
|
13
|
+
#import <React/RCTFabricComponentsPlugins.h>
|
|
14
|
+
#import "DatadogSDKReactNativeSessionReplay-Swift.h"
|
|
15
|
+
|
|
16
|
+
using namespace facebook::react;
|
|
17
|
+
|
|
18
|
+
@interface DdPrivacyViewFabric : RCTViewComponentView <RCTDdPrivacyViewViewProtocol>
|
|
19
|
+
@end
|
|
20
|
+
|
|
21
|
+
@implementation DdPrivacyViewFabric {
|
|
22
|
+
UIView * _view;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
+ (ComponentDescriptorProvider)componentDescriptorProvider {
|
|
26
|
+
return concreteComponentDescriptorProvider<DdPrivacyViewComponentDescriptor>();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
- (instancetype)initWithFrame:(CGRect)frame {
|
|
30
|
+
if (self = [super initWithFrame:frame]) {
|
|
31
|
+
static const auto defaultProps = std::make_shared<const DdPrivacyViewProps>();
|
|
32
|
+
_props = defaultProps;
|
|
33
|
+
}
|
|
34
|
+
return self;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps {
|
|
38
|
+
const auto &newProps = *std::static_pointer_cast<DdPrivacyViewProps const>(props);
|
|
39
|
+
|
|
40
|
+
NSString *text = [NSString stringWithUTF8String:newProps.textAndInputPrivacy.c_str()];
|
|
41
|
+
NSString *image = [NSString stringWithUTF8String:newProps.imagePrivacy.c_str()];
|
|
42
|
+
NSString *touch = [NSString stringWithUTF8String:newProps.touchPrivacy.c_str()];
|
|
43
|
+
|
|
44
|
+
[DdPrivacyOverrider setOverridesFor:self textPrivacy:text imagePrivacy:image touchPrivacy:touch hide:newProps.hide];
|
|
45
|
+
|
|
46
|
+
[super updateProps:props oldProps:oldProps];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
@end
|
|
50
|
+
|
|
51
|
+
Class<RCTComponentViewProtocol> DdPrivacyViewCls(void) {
|
|
52
|
+
return DdPrivacyViewFabric.class;
|
|
53
|
+
}
|
|
54
|
+
#endif
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
|
|
3
|
+
* This product includes software developed at Datadog (https://www.datadoghq.com/).
|
|
4
|
+
* Copyright 2016-Present Datadog, Inc.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
#import <React/RCTViewManager.h>
|
|
8
|
+
#import "DatadogSDKReactNativeSessionReplay-Swift.h"
|
|
9
|
+
|
|
10
|
+
@interface DdPrivacyView : UIView
|
|
11
|
+
|
|
12
|
+
@property (nonatomic, strong) NSString *textPrivacy;
|
|
13
|
+
@property (nonatomic, strong) NSString *imagePrivacy;
|
|
14
|
+
@property (nonatomic, strong) NSString *touchPrivacy;
|
|
15
|
+
@property (nonatomic, assign) BOOL hide;
|
|
16
|
+
|
|
17
|
+
@end
|
|
18
|
+
|
|
19
|
+
@implementation DdPrivacyView
|
|
20
|
+
@end
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@interface DdPrivacyViewPaper : RCTViewManager
|
|
24
|
+
@end
|
|
25
|
+
|
|
26
|
+
@implementation DdPrivacyViewPaper
|
|
27
|
+
|
|
28
|
+
RCT_EXPORT_MODULE(DdPrivacyView)
|
|
29
|
+
|
|
30
|
+
- (UIView *) view {
|
|
31
|
+
return [[DdPrivacyView alloc] init];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
RCT_CUSTOM_VIEW_PROPERTY(textAndInputPrivacy, NSString, DdPrivacyView) {
|
|
35
|
+
view.textPrivacy = [RCTConvert NSString:json];
|
|
36
|
+
[self setPrivacyOverridesFor:view];
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
RCT_CUSTOM_VIEW_PROPERTY(imagePrivacy, NSString, DdPrivacyView) {
|
|
40
|
+
view.imagePrivacy = [RCTConvert NSString:json];
|
|
41
|
+
[self setPrivacyOverridesFor:view];
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
RCT_CUSTOM_VIEW_PROPERTY(touchPrivacy, NSString, DdPrivacyView) {
|
|
45
|
+
view.touchPrivacy = [RCTConvert NSString:json];
|
|
46
|
+
[self setPrivacyOverridesFor:view];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
RCT_CUSTOM_VIEW_PROPERTY(hide, BOOL, DdPrivacyView) {
|
|
50
|
+
view.hide = json ? [json boolValue] : NO;
|
|
51
|
+
[self setPrivacyOverridesFor:view];
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
- (void) setPrivacyOverridesFor:(DdPrivacyView *) view {
|
|
55
|
+
[DdPrivacyOverrider setOverridesFor:view textPrivacy:view.textPrivacy imagePrivacy:view.imagePrivacy touchPrivacy:view.touchPrivacy hide:view.hide];
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
@end
|
|
@@ -12,13 +12,12 @@
|
|
|
12
12
|
#import <React-RCTFabric/React/RCTParagraphComponentView.h>
|
|
13
13
|
#import <React-RCTFabric/React/RCTConversions.h>
|
|
14
14
|
|
|
15
|
-
#if
|
|
15
|
+
#if __has_include(<React-FabricComponents/react/renderer/components/text/ParagraphProps.h>)
|
|
16
16
|
#import <React-FabricComponents/react/renderer/components/text/ParagraphProps.h>
|
|
17
17
|
#else
|
|
18
18
|
#import <React-Fabric/react/renderer/components/text/ParagraphProps.h>
|
|
19
19
|
#endif
|
|
20
20
|
|
|
21
|
-
|
|
22
21
|
namespace rct = facebook::react;
|
|
23
22
|
#endif
|
|
24
23
|
|
|
@@ -10,8 +10,8 @@ import DatadogSessionReplay
|
|
|
10
10
|
import React
|
|
11
11
|
|
|
12
12
|
internal class RCTTextViewRecorder: SessionReplayNodeRecorder {
|
|
13
|
-
internal var textObfuscator: (SessionReplayViewTreeRecordingContext) -> SessionReplayTextObfuscating = { context in
|
|
14
|
-
return context.
|
|
13
|
+
internal var textObfuscator: (SessionReplayViewTreeRecordingContext, SessionReplayViewAttributes) -> SessionReplayTextObfuscating = { context, viewAttributes in
|
|
14
|
+
return viewAttributes.resolveTextAndInputPrivacyLevel(in: context).staticTextObfuscator
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
internal var identifier = UUID()
|
|
@@ -41,7 +41,7 @@ internal class RCTTextViewRecorder: SessionReplayNodeRecorder {
|
|
|
41
41
|
text: textProperties.text,
|
|
42
42
|
textAlignment: textProperties.alignment,
|
|
43
43
|
textColor: textProperties.foregroundColor,
|
|
44
|
-
textObfuscator: textObfuscator(context),
|
|
44
|
+
textObfuscator: textObfuscator(context, attributes),
|
|
45
45
|
fontSize: textProperties.fontSize,
|
|
46
46
|
contentRect: textProperties.contentRect
|
|
47
47
|
)
|
|
@@ -78,8 +78,23 @@ internal class RCTTextViewRecorder: SessionReplayNodeRecorder {
|
|
|
78
78
|
var shadowView: RCTTextShadowView? = nil
|
|
79
79
|
let tag = textView.reactTag
|
|
80
80
|
|
|
81
|
-
|
|
82
|
-
|
|
81
|
+
let timeout: TimeInterval = 0.2
|
|
82
|
+
let semaphore = DispatchSemaphore(value: 0)
|
|
83
|
+
|
|
84
|
+
// We need to access the shadow view from the UIManager queue, but we're currently on the main thread.
|
|
85
|
+
// Calling `.sync` from the main thread to the UIManager queue is unsafe, because the UIManager queue
|
|
86
|
+
// may already be executing a layout operation that in turn requires the main thread (e.g. measuring a native view).
|
|
87
|
+
// That would create a circular dependency and deadlock the app.
|
|
88
|
+
// To avoid this, we dispatch the work asynchronously to the UIManager queue and wait with a timeout.
|
|
89
|
+
// This ensures we block only if absolutely necessary, and can fail gracefully if the queue is busy.
|
|
90
|
+
RCTGetUIManagerQueue().async {
|
|
91
|
+
shadowView = self.uiManager.shadowView(forReactTag: tag) as? RCTTextShadowView
|
|
92
|
+
semaphore.signal()
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
let waitResult = semaphore.wait(timeout: .now() + timeout)
|
|
96
|
+
if waitResult == .timedOut {
|
|
97
|
+
return nil
|
|
83
98
|
}
|
|
84
99
|
|
|
85
100
|
guard let shadow = shadowView else {
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.HideView = HideView;
|
|
7
|
+
var _react = _interopRequireDefault(require("react"));
|
|
8
|
+
var _PrivacyView = require("./PrivacyView");
|
|
9
|
+
var _jsxRuntime = require("react/jsx-runtime");
|
|
10
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
11
|
+
/*
|
|
12
|
+
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
|
|
13
|
+
* This product includes software developed at Datadog (https://www.datadoghq.com/).
|
|
14
|
+
* Copyright 2016-Present Datadog, Inc.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* A wrapper component that hides all of its content from session replays.
|
|
19
|
+
*
|
|
20
|
+
* When used, none of the children within this view will appear in the replay recording.
|
|
21
|
+
* This is useful for UI areas that contain sensitive or confidential information that should
|
|
22
|
+
* be completely excluded from visibility, not just masked.
|
|
23
|
+
*/
|
|
24
|
+
function HideView({
|
|
25
|
+
children,
|
|
26
|
+
...props
|
|
27
|
+
}) {
|
|
28
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_PrivacyView.PrivacyView, {
|
|
29
|
+
...props,
|
|
30
|
+
hide: true,
|
|
31
|
+
children: children
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=HideView.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["_react","_interopRequireDefault","require","_PrivacyView","_jsxRuntime","e","__esModule","default","HideView","children","props","jsx","PrivacyView","hide"],"sourceRoot":"../../../../src","sources":["components/SessionReplayView/HideView.tsx"],"mappings":";;;;;;AAOA,IAAAA,MAAA,GAAAC,sBAAA,CAAAC,OAAA;AAEA,IAAAC,YAAA,GAAAD,OAAA;AAA4C,IAAAE,WAAA,GAAAF,OAAA;AAAA,SAAAD,uBAAAI,CAAA,WAAAA,CAAA,IAAAA,CAAA,CAAAC,UAAA,GAAAD,CAAA,KAAAE,OAAA,EAAAF,CAAA;AAT5C;AACA;AACA;AACA;AACA;;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASG,QAAQA,CAAC;EAAEC,QAAQ;EAAE,GAAGC;AAAiB,CAAC,EAAE;EACxD,oBACI,IAAAN,WAAA,CAAAO,GAAA,EAACR,YAAA,CAAAS,WAAW;IAAA,GAAKF,KAAK;IAAEG,IAAI,EAAE,IAAK;IAAAJ,QAAA,EAC9BA;EAAQ,CACA,CAAC;AAEtB","ignoreList":[]}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.MaskAllView = MaskAllView;
|
|
7
|
+
var _react = _interopRequireDefault(require("react"));
|
|
8
|
+
var _SessionReplay = require("../../SessionReplay");
|
|
9
|
+
var _PrivacyView = require("./PrivacyView");
|
|
10
|
+
var _jsxRuntime = require("react/jsx-runtime");
|
|
11
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
12
|
+
/*
|
|
13
|
+
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
|
|
14
|
+
* This product includes software developed at Datadog (https://www.datadoghq.com/).
|
|
15
|
+
* Copyright 2016-Present Datadog, Inc.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* A wrapper component that enforces full masking on all content within it.
|
|
20
|
+
*
|
|
21
|
+
* This includes:
|
|
22
|
+
* - Masking all text and input values (e.g., replacing them with asterisks)
|
|
23
|
+
* - Masking all images
|
|
24
|
+
* - Hiding or optionally showing touch interactions, depending on `showTouch`
|
|
25
|
+
*
|
|
26
|
+
* This component is useful for marking sensitive UI sections that should not be visible
|
|
27
|
+
* in session replays.
|
|
28
|
+
*/
|
|
29
|
+
function MaskAllView({
|
|
30
|
+
children,
|
|
31
|
+
showTouch,
|
|
32
|
+
...props
|
|
33
|
+
}) {
|
|
34
|
+
const touchPrivacy = showTouch ? _SessionReplay.TouchPrivacyLevel.SHOW : _SessionReplay.TouchPrivacyLevel.HIDE;
|
|
35
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_PrivacyView.PrivacyView, {
|
|
36
|
+
...props,
|
|
37
|
+
textAndInputPrivacy: _SessionReplay.TextAndInputPrivacyLevel.MASK_ALL,
|
|
38
|
+
imagePrivacy: _SessionReplay.ImagePrivacyLevel.MASK_ALL,
|
|
39
|
+
touchPrivacy: touchPrivacy,
|
|
40
|
+
hide: false,
|
|
41
|
+
children: children
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=MaskAllView.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["_react","_interopRequireDefault","require","_SessionReplay","_PrivacyView","_jsxRuntime","e","__esModule","default","MaskAllView","children","showTouch","props","touchPrivacy","TouchPrivacyLevel","SHOW","HIDE","jsx","PrivacyView","textAndInputPrivacy","TextAndInputPrivacyLevel","MASK_ALL","imagePrivacy","ImagePrivacyLevel","hide"],"sourceRoot":"../../../../src","sources":["components/SessionReplayView/MaskAllView.tsx"],"mappings":";;;;;;AAOA,IAAAA,MAAA,GAAAC,sBAAA,CAAAC,OAAA;AAEA,IAAAC,cAAA,GAAAD,OAAA;AAMA,IAAAE,YAAA,GAAAF,OAAA;AAA4C,IAAAG,WAAA,GAAAH,OAAA;AAAA,SAAAD,uBAAAK,CAAA,WAAAA,CAAA,IAAAA,CAAA,CAAAC,UAAA,GAAAD,CAAA,KAAAE,OAAA,EAAAF,CAAA;AAf5C;AACA;AACA;AACA;AACA;;AAqBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASG,WAAWA,CAAC;EAAEC,QAAQ;EAAEC,SAAS;EAAE,GAAGC;AAAa,CAAC,EAAE;EAClE,MAAMC,YAAY,GAAGF,SAAS,GACxBG,gCAAiB,CAACC,IAAI,GACtBD,gCAAiB,CAACE,IAAI;EAE5B,oBACI,IAAAX,WAAA,CAAAY,GAAA,EAACb,YAAA,CAAAc,WAAW;IAAA,GACJN,KAAK;IACTO,mBAAmB,EAAEC,uCAAwB,CAACC,QAAS;IACvDC,YAAY,EAAEC,gCAAiB,CAACF,QAAS;IACzCR,YAAY,EAAEA,YAAa;IAC3BW,IAAI,EAAE,KAAM;IAAAd,QAAA,EAEXA;EAAQ,CACA,CAAC;AAEtB","ignoreList":[]}
|