@dynatrace/react-native-plugin 2.341.1 → 2.343.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.
Files changed (39) hide show
  1. package/README.md +37 -9
  2. package/android/build.gradle +11 -2
  3. package/android/src/main/java/com/dynatrace/android/agent/DynatraceAppStartModule.kt +9 -31
  4. package/android/src/main/java/com/dynatrace/android/agent/DynatraceConfigurationModule.kt +1 -0
  5. package/android/src/main/java/com/dynatrace/android/agent/DynatraceRNBridgeImpl.kt +41 -0
  6. package/android/src/main/java/com/dynatrace/android/agent/DynatraceUtils.kt +1 -0
  7. package/android/src/main/java/com/dynatrace/android/agent/ScreenshotSelfMonitor.kt +175 -0
  8. package/android/src/main/java/com/dynatrace/android/agent/UIChangeScreenshotListener.kt +124 -0
  9. package/android/src/new/java/com/dynatrace/android/agent/DynatraceRNBridge.kt +33 -0
  10. package/android/src/old/java/com/dynatrace/android/agent/DynatraceRNBridge.kt +40 -0
  11. package/files/plugin.gradle +1 -1
  12. package/instrumentation/libs/UserInteraction.js +1 -1
  13. package/ios/DTXScreenshotSelfMonitor.h +29 -0
  14. package/ios/DTXScreenshotSelfMonitor.mm +213 -0
  15. package/ios/DTXScreenshotSelfMonitorSwizzler.h +15 -0
  16. package/ios/DTXScreenshotSelfMonitorSwizzler.mm +68 -0
  17. package/ios/DynatraceRNBridge.h +6 -0
  18. package/ios/DynatraceRNBridge.mm +53 -0
  19. package/lib/core/Dynatrace.js +2 -0
  20. package/lib/core/logging/LogMessages.js +42 -0
  21. package/lib/features/ui-interaction/IUserInteractionEvent.js +1 -1
  22. package/lib/features/ui-interaction/Runtime.js +1 -1
  23. package/lib/next/Dynatrace.js +26 -1
  24. package/lib/next/events/EventPipeline.js +48 -31
  25. package/lib/next/events/HttpRequestEventData.js +1 -1
  26. package/lib/next/events/spec/EventSpecContstants.js +1 -1
  27. package/lib/next/userAction/NullUserAction.js +15 -0
  28. package/lib/next/userAction/UserAction.js +2 -0
  29. package/lib/next/userAction/UserActionConfiguration.js +10 -0
  30. package/lib/next/userAction/UserActionImpl.js +70 -0
  31. package/lib/next/util/TraceContextUtils.js +8 -14
  32. package/lib/next/util/Utils.js +13 -0
  33. package/package.json +7 -3
  34. package/public.js +3 -1
  35. package/react-native-dynatrace.podspec +10 -3
  36. package/scripts/Config.js +17 -3
  37. package/scripts/core/InstrumentCall.js +12 -4
  38. package/src/lib/core/interface/NativeDynatraceBridge.ts +34 -1
  39. package/types.d.ts +29 -2
@@ -83,7 +83,7 @@ const flushTouch = (responderComponentInfo) => {
83
83
  clearTimeout(timeoutId);
84
84
  pendingTouch = null;
85
85
  const eventTimestamp = new EventTimestamp_1.EventTimestamp(TimestampProvider_1.defaultTimestampProvider);
86
- const event = Object.assign(Object.assign({ 'characteristics.has_user_interaction': true, 'ui_element.detected_name': touchedComponentInfo.detectedName, 'ui_element.components': touchedComponentInfo.components, 'ui_element.id': touchedComponentInfo.id, 'interaction.name': 'touch', positions, 'ui_element.name_origin': touchedComponentInfo.nameOrigin }, (responderComponentInfo && {
86
+ const event = Object.assign(Object.assign({ 'characteristics.has_user_interaction': true, 'ui_element.detected_name': touchedComponentInfo.detectedName, 'ui_element.components': touchedComponentInfo.components, 'ui_element.id': touchedComponentInfo.id, 'interaction.type': 'touch', positions, 'ui_element.name_origin': touchedComponentInfo.nameOrigin }, (responderComponentInfo && {
87
87
  'ui_element.responder.detected_name': responderComponentInfo.detectedName,
88
88
  'ui_element.responder.components': responderComponentInfo.components,
89
89
  'ui_element.responder.id': responderComponentInfo.id,
@@ -0,0 +1,29 @@
1
+ //
2
+ // DTXScreenshotSelfMonitor.h
3
+ //
4
+ // Self-monitoring counterpart of the Session Replay UI-change listener. Instead of capturing a
5
+ // screenshot it only increments the cross-platform screenshot counter via the agent, to estimate
6
+ // how many screenshots Session Replay would take in production.
7
+ //
8
+ // Monitoring is gated by the remote `replay_metrics_enabled` flag delivered through the
9
+ // configuration; it stays dormant until the server enables it.
10
+ //
11
+
12
+ #import <Foundation/Foundation.h>
13
+ #import "ConfigurationSubscriber.h"
14
+
15
+ // Build-time master switch for the screenshot self-monitoring (replay metrics) feature.
16
+ // Defaults to enabled. Disable for a build with `DYNATRACE_REPLAY_METRICS_ENABLED=0 pod install`
17
+ // (the podspec then injects `#define DTX_REPLAY_METRICS_ENABLED 0` via the prefix header). When 0,
18
+ // the monitor is never registered, regardless of the remote `replay_metrics_enabled` flag.
19
+ #ifndef DTX_REPLAY_METRICS_ENABLED
20
+ #define DTX_REPLAY_METRICS_ENABLED 1
21
+ #endif
22
+
23
+ NS_ASSUME_NONNULL_BEGIN
24
+
25
+ @interface DTXScreenshotSelfMonitor : NSObject <ConfigurationSubscriber>
26
+
27
+ @end
28
+
29
+ NS_ASSUME_NONNULL_END
@@ -0,0 +1,213 @@
1
+ //
2
+ // DTXScreenshotSelfMonitor.mm
3
+ //
4
+
5
+ #import "DTXScreenshotSelfMonitor.h"
6
+ #import "DTXScreenshotSelfMonitorSwizzler.h"
7
+ #import <UIKit/UIKit.h>
8
+ #import <QuartzCore/QuartzCore.h>
9
+
10
+ static const double kDebounceMs = 500.0;
11
+ static const double kMaxDebounceMs = 2000.0;
12
+
13
+ // Remote feature-flag key in the cross-platform configuration map. Monitoring stays off unless the
14
+ // server delivers this flag as `true`.
15
+ static NSString *const kReplayMetricsConfigKey = @"replay_metrics_enabled";
16
+
17
+ // DEM-26735: replay metrics experiment sunsets on 2026-10-15T00:00:00Z; remove this class after that date.
18
+ static const NSTimeInterval kExperimentExpiryEpoch = 1792022400.0;
19
+
20
+ static BOOL DTXIsReplayMetricsExperimentExpired(void) {
21
+ return [[NSDate date] timeIntervalSince1970] >= kExperimentExpiryEpoch;
22
+ }
23
+
24
+ // Minimal declaration of the agent's HybridBridge facade. The implementation is provided by the
25
+ // Dynatrace framework; we only need the screenshot-tracking entry point here.
26
+ //
27
+ // NOTE: the underlying store moved to ios-core (DynatraceCoreStatic's
28
+ // Assembly.shared.crossPlatformScreenshotTracker). DynatraceCoreStatic is not exposed to this plugin
29
+ // (it is statically merged into the Dynatrace framework and not re-exported), so we keep calling the
30
+ // ObjC HybridBridge facade; the agent's HybridBridge delegates to the ios-core tracker
31
+ // (+[HybridBridge trackCrossPlatformScreenshot] → [Assembly.shared.crossPlatformScreenshotTracker trackScreenshot]).
32
+ @interface HybridBridge : NSObject
33
+ + (void)trackCrossPlatformScreenshot;
34
+ @end
35
+
36
+ @implementation DTXScreenshotSelfMonitor {
37
+ BOOL _started;
38
+ BOOL _swizzleInstalled;
39
+ BOOL _pending;
40
+ double _lastChangeTime;
41
+ double _firstChangeTime;
42
+ uint32_t _generation;
43
+ }
44
+
45
+ - (instancetype)init {
46
+ self = [super init];
47
+ if (self) {
48
+ _started = NO;
49
+ _swizzleInstalled = NO;
50
+ _pending = NO;
51
+ _lastChangeTime = 0;
52
+ _firstChangeTime = 0;
53
+ _generation = 0;
54
+ }
55
+ return self;
56
+ }
57
+
58
+ - (void)dealloc {
59
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
60
+ if (_swizzleInstalled) {
61
+ [DTXScreenshotSelfMonitorSwizzler uninstall];
62
+ _swizzleInstalled = NO;
63
+ }
64
+ }
65
+
66
+ #pragma mark - ConfigurationSubscriber
67
+
68
+ - (void)notifyWithConfiguration:(NSDictionary<NSString *, id> *)configuration {
69
+ id value = configuration[kReplayMetricsConfigKey];
70
+ BOOL flagEnabled = [value isKindOfClass:[NSNumber class]] && [value boolValue];
71
+ BOOL enabled = flagEnabled && !DTXIsReplayMetricsExperimentExpired();
72
+ if (flagEnabled && !enabled) {
73
+ NSLog(@"[dtxScreenshotSelfMonitor] config: %@=YES but experiment expired — treating as disabled", kReplayMetricsConfigKey);
74
+ } else {
75
+ NSLog(@"[dtxScreenshotSelfMonitor] config: %@=%@ → %@", kReplayMetricsConfigKey, value, enabled ? @"ENABLED" : @"DISABLED");
76
+ }
77
+
78
+ // Configuration is delivered on a background queue; start/stop touch UIApplication and the global
79
+ // swizzle, so they must run on the main thread. start/stop are idempotent.
80
+ dispatch_async(dispatch_get_main_queue(), ^{
81
+ if (enabled) {
82
+ [self start];
83
+ } else {
84
+ [self stop];
85
+ }
86
+ });
87
+ }
88
+
89
+ #pragma mark - Lifecycle (must be called on the main thread)
90
+
91
+ - (void)start {
92
+ if (_started) {
93
+ NSLog(@"[dtxScreenshotSelfMonitor] start ignored — already started");
94
+ return;
95
+ }
96
+ _started = YES;
97
+
98
+ [[NSNotificationCenter defaultCenter] addObserver:self
99
+ selector:@selector(appDidBecomeActive)
100
+ name:UIApplicationDidBecomeActiveNotification
101
+ object:nil];
102
+ [[NSNotificationCenter defaultCenter] addObserver:self
103
+ selector:@selector(appDidEnterBackground)
104
+ name:UIApplicationDidEnterBackgroundNotification
105
+ object:nil];
106
+
107
+ UIApplicationState appState = [UIApplication sharedApplication].applicationState;
108
+ NSLog(@"[dtxScreenshotSelfMonitor] start (appState=%ld, mainThread=%d)", (long)appState, (int)[NSThread isMainThread]);
109
+
110
+ // Install immediately unless we are backgrounded (avoids observing while there is nothing to do).
111
+ if (appState != UIApplicationStateBackground) {
112
+ [self installSwizzle];
113
+ } else {
114
+ NSLog(@"[dtxScreenshotSelfMonitor] start: app backgrounded — deferring swizzle install to appDidBecomeActive");
115
+ }
116
+ }
117
+
118
+ - (void)stop {
119
+ if (!_started) return;
120
+ _started = NO;
121
+ NSLog(@"[dtxScreenshotSelfMonitor] stop");
122
+
123
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
124
+ [self uninstallSwizzle];
125
+ }
126
+
127
+ #pragma mark - Swizzle install / uninstall
128
+
129
+ - (void)installSwizzle {
130
+ if (_swizzleInstalled) return;
131
+ _swizzleInstalled = YES;
132
+ NSLog(@"[dtxScreenshotSelfMonitor] installing layer swizzle");
133
+
134
+ __weak __typeof__(self) weakSelf = self;
135
+ [DTXScreenshotSelfMonitorSwizzler installWithChangeHandler:^{
136
+ [weakSelf onLayerChanged];
137
+ }];
138
+ }
139
+
140
+ - (void)uninstallSwizzle {
141
+ if (!_swizzleInstalled) return;
142
+ _swizzleInstalled = NO;
143
+ NSLog(@"[dtxScreenshotSelfMonitor] uninstalling layer swizzle (disarming handler)");
144
+
145
+ [DTXScreenshotSelfMonitorSwizzler uninstall];
146
+ _generation++;
147
+ _pending = NO;
148
+ }
149
+
150
+ #pragma mark - App lifecycle
151
+
152
+ - (void)appDidBecomeActive {
153
+ NSLog(@"[dtxScreenshotSelfMonitor] appDidBecomeActive");
154
+ [self installSwizzle];
155
+ }
156
+
157
+ - (void)appDidEnterBackground {
158
+ NSLog(@"[dtxScreenshotSelfMonitor] appDidEnterBackground");
159
+ [self uninstallSwizzle];
160
+ }
161
+
162
+ #pragma mark - CALayer change callback
163
+
164
+ - (void)onLayerChanged {
165
+ double now = CACurrentMediaTime() * 1000.0;
166
+ _lastChangeTime = now;
167
+
168
+ if (!_pending) {
169
+ _pending = YES;
170
+ _firstChangeTime = now;
171
+ NSLog(@"[dtxScreenshotSelfMonitor] UI change detected — starting %.0fms debounce", kDebounceMs);
172
+ [self scheduleCapture];
173
+ }
174
+ }
175
+
176
+ #pragma mark - Debounce & capture
177
+
178
+ - (void)scheduleCapture {
179
+ uint32_t gen = _generation;
180
+ __weak __typeof__(self) weakSelf = self;
181
+ dispatch_after(
182
+ dispatch_time(DISPATCH_TIME_NOW, (int64_t)(kDebounceMs * NSEC_PER_MSEC)),
183
+ dispatch_get_main_queue(),
184
+ ^{
185
+ __typeof__(self) strongSelf = weakSelf;
186
+ if (!strongSelf || gen != strongSelf->_generation) return;
187
+ [strongSelf performCapture];
188
+ }
189
+ );
190
+ }
191
+
192
+ - (void)performCapture {
193
+ double now = CACurrentMediaTime() * 1000.0;
194
+ double elapsed = now - _lastChangeTime;
195
+ double sinceFirst = now - _firstChangeTime;
196
+
197
+ if (elapsed < kDebounceMs && sinceFirst < kMaxDebounceMs) {
198
+ NSLog(@"[dtxScreenshotSelfMonitor] UI still active (%.0fms since last change) — rescheduling", elapsed);
199
+ [self scheduleCapture];
200
+ return;
201
+ }
202
+
203
+ _pending = NO;
204
+
205
+ @try {
206
+ NSLog(@"[dtxScreenshotSelfMonitor] capture settled — calling [HybridBridge trackCrossPlatformScreenshot]");
207
+ [HybridBridge trackCrossPlatformScreenshot];
208
+ } @catch (NSException *exception) {
209
+ NSLog(@"[dtxScreenshotSelfMonitor] trackCrossPlatformScreenshot threw: %@", exception.name);
210
+ }
211
+ }
212
+
213
+ @end
@@ -0,0 +1,15 @@
1
+ //
2
+ // DTXScreenshotSelfMonitorSwizzler.h
3
+ //
4
+ // Detects UI changes by swizzling -[CALayer layoutSublayers] and invoking a change handler on
5
+ // the main thread. Used by the cross-platform screenshot self-monitoring feature.
6
+ //
7
+
8
+ #import <Foundation/Foundation.h>
9
+
10
+ @interface DTXScreenshotSelfMonitorSwizzler : NSObject
11
+
12
+ + (void)installWithChangeHandler:(void (^)(void))handler;
13
+ + (void)uninstall;
14
+
15
+ @end
@@ -0,0 +1,68 @@
1
+ //
2
+ // DTXScreenshotSelfMonitorSwizzler.mm
3
+ //
4
+
5
+ #import "DTXScreenshotSelfMonitorSwizzler.h"
6
+ #import <QuartzCore/QuartzCore.h>
7
+ #import <objc/runtime.h>
8
+
9
+ static void (^_changeHandler)(void) = nil;
10
+ static BOOL _installed = NO;
11
+ static BOOL _isHandlingChange = NO;
12
+
13
+ static IMP original_layoutSublayers_imp = NULL;
14
+
15
+ static void notifyChange(void) {
16
+ if (!_changeHandler) return;
17
+ if (![NSThread isMainThread]) return;
18
+ if (_isHandlingChange) return;
19
+
20
+ _isHandlingChange = YES;
21
+ _changeHandler();
22
+ _isHandlingChange = NO;
23
+ }
24
+
25
+ static void swizzled_layoutSublayers(id self, SEL _cmd) {
26
+ ((void (*)(id, SEL))original_layoutSublayers_imp)(self, _cmd);
27
+ notifyChange();
28
+ }
29
+
30
+ @implementation DTXScreenshotSelfMonitorSwizzler
31
+
32
+ + (void)installWithChangeHandler:(void (^)(void))handler {
33
+ _changeHandler = [handler copy];
34
+
35
+ // Swizzle exactly once for the process lifetime, then drive activity through _changeHandler.
36
+ //
37
+ // We must NOT swizzle/unswizzle on every foreground/background. -[CALayer layoutSublayers] is a
38
+ // shared selector that DynatraceSessionReplay also swizzles; two independent swizzlers each
39
+ // restoring + re-installing the IMP can interleave such that an install captures an
40
+ // already-swizzled IMP as its "original". swizzled_layoutSublayers() then calls back into a
41
+ // swizzled implementation, recursing without bound → stack overflow (EXC_BAD_ACCESS on
42
+ // foreground). Installing once removes all IMP churn and keeps the swizzle chain stable.
43
+ if (_installed) {
44
+ NSLog(@"[dtxScreenshotSelfMonitor] swizzler: handler re-armed (already installed)");
45
+ return;
46
+ }
47
+ _installed = YES;
48
+
49
+ Class cls = [CALayer class];
50
+ Method m = class_getInstanceMethod(cls, @selector(layoutSublayers));
51
+ IMP current = method_getImplementation(m);
52
+ // Defensive: never capture our own swizzled function as the original (would self-recurse).
53
+ if (current != (IMP)swizzled_layoutSublayers) {
54
+ original_layoutSublayers_imp = current;
55
+ }
56
+ method_setImplementation(m, (IMP)swizzled_layoutSublayers);
57
+ NSLog(@"[dtxScreenshotSelfMonitor] swizzler: installed on -[CALayer layoutSublayers] (one-time)");
58
+ }
59
+
60
+ + (void)uninstall {
61
+ // Intentionally does NOT restore the original IMP (see installWithChangeHandler:). Restoring is
62
+ // what enables the cross-swizzler recursion above, and it would also clobber any swizzler layered
63
+ // on top of us. We leave the one-time swizzle in place and simply stop notifying — notifyChange()
64
+ // no-ops while _changeHandler is nil, so there is no work and no risk when monitoring is off.
65
+ _changeHandler = nil;
66
+ }
67
+
68
+ @end
@@ -22,6 +22,12 @@
22
22
  + (void)startView:(NSDictionary<NSString*,id>* _Nullable)fields NS_SWIFT_NAME(startView(fields:));
23
23
  + (void)stopView;
24
24
  + (void)addConfigurationSubscriber:(id<ConfigurationSubscriber>)subscriber;
25
+ + (void)trackCrossPlatformScreenshot;
26
+ + (void)setAutomaticUserActionDetection:(BOOL)enabled NS_SWIFT_NAME(setAutomaticUserActionDetection(enabled:));
27
+ + (void)createUserAction:(NSString *)actionId name:(NSString *)name completeAutomatically:(BOOL)completeAutomatically properties:(NSDictionary<NSString*,id>* _Nullable)properties NS_SWIFT_NAME(createUserAction(actionId:name:completeAutomatically:properties:));
28
+ + (void)addEventPropertyToUserAction:(NSString *)actionId key:(NSString *)key value:(id _Nullable)value NS_SWIFT_NAME(addEventPropertyToUserAction(actionId:key:value:));
29
+ + (void)completeUserAction:(NSString *)actionId NS_SWIFT_NAME(completeUserAction(actionId:));
30
+ + (void)setCompleteUserActionAutomatically:(NSString *)actionId enabled:(BOOL)enabled NS_SWIFT_NAME(setCompleteUserActionAutomatically(actionId:enabled:));
25
31
  @end
26
32
 
27
33
  typedef enum : NSUInteger {
@@ -3,6 +3,7 @@
3
3
  //
4
4
 
5
5
  #import "DynatraceRNBridge.h"
6
+ #import "DTXScreenshotSelfMonitor.h"
6
7
 
7
8
  // For Turbo Module
8
9
  #ifdef RCT_NEW_ARCH_ENABLED
@@ -111,6 +112,11 @@ static bool remoteConfigSubscribed;
111
112
  static NSDictionary<NSString*, id>* lastRuntimeConfiguration;
112
113
  static RNConfigurationSubscriber* configurationSubscriber;
113
114
 
115
+ // Screenshot self-monitoring. Registered once per process; the configuration publisher retains it
116
+ // as a subscriber and the remote `replay_metrics_enabled` flag toggles monitoring on/off.
117
+ static bool screenshotMonitorSubscribed;
118
+ static DTXScreenshotSelfMonitor* screenshotMonitor;
119
+
114
120
  RCT_EXPORT_MODULE(DynatraceBridge);
115
121
 
116
122
  - (instancetype) init
@@ -307,6 +313,18 @@ template<typename T = void> std::enable_if_t<(facebook::react::ReactNativeVersio
307
313
  }
308
314
  remoteConfigSubscribed = YES;
309
315
  [HybridBridge addConfigurationSubscriber:(id)configurationSubscriber];
316
+
317
+ // Start the screenshot self-monitor here — same proven-safe timing as the config subscriber
318
+ // above (post-startup). Started once; -start touches UIApplication and the layer swizzle, so it
319
+ // must run on the main thread.
320
+ #if DTX_REPLAY_METRICS_ENABLED
321
+ if (!screenshotMonitorSubscribed) {
322
+ screenshotMonitorSubscribed = YES;
323
+ NSLog(@"[dtxScreenshotSelfMonitor] bridge: registering screenshot self-monitor as config subscriber");
324
+ screenshotMonitor = [[DTXScreenshotSelfMonitor alloc] init];
325
+ [HybridBridge addConfigurationSubscriber:(id)screenshotMonitor];
326
+ }
327
+ #endif
310
328
  }
311
329
 
312
330
  - (void)emitToJS:(NSString*)event body:(id)body
@@ -627,6 +645,41 @@ RCT_EXPORT_METHOD(forwardAppStartEvent:(NSDictionary<NSString*, id>*) attributes
627
645
  [HybridBridge forwardAppStartEvent:attributes keys:appStartKeys];
628
646
  }
629
647
 
648
+ RCT_EXPORT_METHOD(setAutomaticUserActionDetection:(BOOL)enabled)
649
+ {
650
+ [HybridBridge setAutomaticUserActionDetection:enabled];
651
+ }
652
+
653
+ RCT_EXPORT_METHOD(createUserAction:(NSString *)actionId name:(NSString *)name completeAutomatically:(BOOL)completeAutomatically properties:(NSDictionary<NSString*, id>* _Nullable)properties)
654
+ {
655
+ [HybridBridge createUserAction:actionId name:name completeAutomatically:completeAutomatically properties:properties];
656
+ }
657
+
658
+ RCT_EXPORT_METHOD(addEventStringPropertyToUserAction:(NSString *)actionId key:(NSString *)key value:(NSString *)value)
659
+ {
660
+ [HybridBridge addEventPropertyToUserAction:actionId key:key value:value];
661
+ }
662
+
663
+ RCT_EXPORT_METHOD(addEventDoublePropertyToUserAction:(NSString *)actionId key:(NSString *)key value:(double)value)
664
+ {
665
+ [HybridBridge addEventPropertyToUserAction:actionId key:key value:@(value)];
666
+ }
667
+
668
+ RCT_EXPORT_METHOD(addEventBooleanPropertyToUserAction:(NSString *)actionId key:(NSString *)key value:(BOOL)value)
669
+ {
670
+ [HybridBridge addEventPropertyToUserAction:actionId key:key value:@(value)];
671
+ }
672
+
673
+ RCT_EXPORT_METHOD(completeUserAction:(NSString *)actionId)
674
+ {
675
+ [HybridBridge completeUserAction:actionId];
676
+ }
677
+
678
+ RCT_EXPORT_METHOD(setCompleteUserActionAutomatically:(NSString *)actionId enabled:(BOOL)enabled)
679
+ {
680
+ [HybridBridge setCompleteUserActionAutomatically:actionId enabled:enabled];
681
+ }
682
+
630
683
  RCT_EXPORT_METHOD(setGPSLocation:(double)latitude andLongitude: (double)longitude platform: (NSString *) platform)
631
684
  {
632
685
  if ([self shouldWorkOnIosWithPlatform: platform])
@@ -426,4 +426,6 @@ exports.Dynatrace = {
426
426
  generateTraceContext(traceparent, tracestate) {
427
427
  return Dynatrace_1.Dynatrace.generateTraceContext(traceparent, tracestate);
428
428
  },
429
+ createUserAction: (configuration) => Dynatrace_1.Dynatrace.createUserAction(configuration),
430
+ setAutomaticUserActionDetection: (enabled) => Dynatrace_1.Dynatrace.setAutomaticUserActionDetection(enabled),
429
431
  };
@@ -36,6 +36,8 @@ var LogMessage;
36
36
  LogMessage["COMPONENT_NOT_STARTED"] = "COMPONENT_NOT_STARTED";
37
37
  LogMessage["CONFIGURATION_DUPLICATE_STARTUP"] = "CONFIGURATION_DUPLICATE_STARTUP";
38
38
  LogMessage["CONFIGURATION_SET"] = "CONFIGURATION_SET";
39
+ LogMessage["CREATE_USER_ACTION"] = "CREATE_USER_ACTION";
40
+ LogMessage["CREATE_USER_ACTION_NOT_STARTED"] = "CREATE_USER_ACTION_NOT_STARTED";
39
41
  LogMessage["END_SESSION"] = "END_SESSION";
40
42
  LogMessage["END_SESSION_NOT_STARTED"] = "END_SESSION_NOT_STARTED";
41
43
  LogMessage["ENTER_AUTO_ACTION"] = "ENTER_AUTO_ACTION";
@@ -115,6 +117,8 @@ var LogMessage;
115
117
  LogMessage["SEND_SESSION_PROPERTY_EVENT"] = "SEND_SESSION_PROPERTY_EVENT";
116
118
  LogMessage["SEND_SESSION_PROPERTY_EVENT_INVALID_TYPE"] = "SEND_SESSION_PROPERTY_EVENT_INVALID_TYPE";
117
119
  LogMessage["SESSION_PROPERTIES_FILTERED"] = "SESSION_PROPERTIES_FILTERED";
120
+ LogMessage["SET_AUTOMATIC_USER_ACTION_DETECTION"] = "SET_AUTOMATIC_USER_ACTION_DETECTION";
121
+ LogMessage["SET_AUTOMATIC_USER_ACTION_DETECTION_NOT_STARTED"] = "SET_AUTOMATIC_USER_ACTION_DETECTION_NOT_STARTED";
118
122
  LogMessage["SET_BEACON_HEADERS"] = "SET_BEACON_HEADERS";
119
123
  LogMessage["SET_BEACON_HEADERS_NOT_STARTED"] = "SET_BEACON_HEADERS_NOT_STARTED";
120
124
  LogMessage["SET_CRASH_REPORTING_OPTED_IN"] = "SET_CRASH_REPORTING_OPTED_IN";
@@ -137,6 +141,10 @@ var LogMessage;
137
141
  LogMessage["TRACE_CONTEXT_NOT_STARTED"] = "TRACE_CONTEXT_NOT_STARTED";
138
142
  LogMessage["TRIM_STRING_VALUE_LIMITED"] = "TRIM_STRING_VALUE_LIMITED";
139
143
  LogMessage["UI_INTERACTION_DEBUG"] = "UI_INTERACTION_DEBUG";
144
+ LogMessage["USER_ACTION_ADD_EVENT_PROPERTY"] = "USER_ACTION_ADD_EVENT_PROPERTY";
145
+ LogMessage["USER_ACTION_COMPLETE"] = "USER_ACTION_COMPLETE";
146
+ LogMessage["USER_ACTION_CREATED"] = "USER_ACTION_CREATED";
147
+ LogMessage["USER_ACTION_SET_COMPLETE_AUTOMATICALLY"] = "USER_ACTION_SET_COMPLETE_AUTOMATICALLY";
140
148
  LogMessage["VALUE_SIZE_LIMITED"] = "VALUE_SIZE_LIMITED";
141
149
  LogMessage["WEB_REQUEST_TIMING_START"] = "WEB_REQUEST_TIMING_START";
142
150
  LogMessage["WEB_REQUEST_TIMING_START_FAILED"] = "WEB_REQUEST_TIMING_START_FAILED";
@@ -281,6 +289,15 @@ exports.LOG_MESSAGES = {
281
289
  template: ({ config }) => `Configuration set: ${config}`,
282
290
  logType: LogType_1.LogType.Info,
283
291
  },
292
+ [LogMessage.CREATE_USER_ACTION]: {
293
+ template: ({ customName, completeAutomatically, }) => `createUserAction(${customName}, ${completeAutomatically})`,
294
+ logType: LogType_1.LogType.Info,
295
+ },
296
+ [LogMessage.CREATE_USER_ACTION_NOT_STARTED]: {
297
+ template: 'createUserAction(): React Native plugin has not been started yet! User action will not be created!',
298
+ logType: LogType_1.LogType.Warning,
299
+ documentationUri: 'https://dt-url.net/r2g3975',
300
+ },
284
301
  [LogMessage.END_SESSION]: {
285
302
  template: 'Dynatrace endSession()',
286
303
  logType: LogType_1.LogType.Info,
@@ -640,6 +657,15 @@ exports.LOG_MESSAGES = {
640
657
  logType: LogType_1.LogType.Warning,
641
658
  documentationUri: 'https://dt-url.net/lsk39cn',
642
659
  },
660
+ [LogMessage.SET_AUTOMATIC_USER_ACTION_DETECTION]: {
661
+ template: ({ enabled }) => `setAutomaticUserActionDetection(${enabled})`,
662
+ logType: LogType_1.LogType.Info,
663
+ },
664
+ [LogMessage.SET_AUTOMATIC_USER_ACTION_DETECTION_NOT_STARTED]: {
665
+ template: 'setAutomaticUserActionDetection(): React Native plugin has not been started yet! Setting will not be applied!',
666
+ logType: LogType_1.LogType.Warning,
667
+ documentationUri: 'https://dt-url.net/r2g3975',
668
+ },
643
669
  [LogMessage.SET_BEACON_HEADERS]: {
644
670
  template: 'setBeaconHeaders(headers)',
645
671
  logType: LogType_1.LogType.Info,
@@ -738,6 +764,22 @@ exports.LOG_MESSAGES = {
738
764
  template: ({ event }) => `[DT UI]${event}`,
739
765
  logType: LogType_1.LogType.Info,
740
766
  },
767
+ [LogMessage.USER_ACTION_ADD_EVENT_PROPERTY]: {
768
+ template: ({ key, value, customName, }) => `addEventProperty(${key}, ${value}): in UserAction - ${customName}`,
769
+ logType: LogType_1.LogType.Info,
770
+ },
771
+ [LogMessage.USER_ACTION_COMPLETE]: {
772
+ template: ({ customName }) => `complete(): ${customName}`,
773
+ logType: LogType_1.LogType.Info,
774
+ },
775
+ [LogMessage.USER_ACTION_CREATED]: {
776
+ template: ({ customName, completeAutomatically, actionId, }) => `UserAction created: ${customName} (actionId: ${actionId}, completeAutomatically: ${completeAutomatically})`,
777
+ logType: LogType_1.LogType.Info,
778
+ },
779
+ [LogMessage.USER_ACTION_SET_COMPLETE_AUTOMATICALLY]: {
780
+ template: ({ enabled, customName, }) => `setCompleteAutomatically(${enabled}): ${customName}`,
781
+ logType: LogType_1.LogType.Info,
782
+ },
741
783
  [LogMessage.VALUE_SIZE_LIMITED]: {
742
784
  template: ({ key, maxLength }) => `restrictingValueSize(): Limiting value of ${key} as maximum value length (${maxLength}) is reached!`,
743
785
  logType: LogType_1.LogType.Warning,
@@ -8,7 +8,7 @@ var UserInteractionEventKey;
8
8
  UserInteractionEventKey["UiElementComponents"] = "ui_element.components";
9
9
  UserInteractionEventKey["UiElementId"] = "ui_element.id";
10
10
  UserInteractionEventKey["UiElementNameOrigin"] = "ui_element.name_origin";
11
- UserInteractionEventKey["InteractionName"] = "interaction.name";
11
+ UserInteractionEventKey["InteractionType"] = "interaction.type";
12
12
  UserInteractionEventKey["UiElementResponderDetectedName"] = "ui_element.responder.detected_name";
13
13
  UserInteractionEventKey["UiElementResponderComponents"] = "ui_element.responder.components";
14
14
  UserInteractionEventKey["UiElementResponderOriginName"] = "ui_element.responder.name_origin";
@@ -330,7 +330,7 @@ function _an_flat(e) {
330
330
  [IUserInteractionEvent_1.UserInteractionEventKey.UiElementDetectedName]: (_c = (_b = e === null || e === void 0 ? void 0 : e.ui_element) === null || _b === void 0 ? void 0 : _b.detected_name) !== null && _c !== void 0 ? _c : null,
331
331
  [IUserInteractionEvent_1.UserInteractionEventKey.UiElementComponents]: normalizedUiComponents,
332
332
  [IUserInteractionEvent_1.UserInteractionEventKey.UiElementId]: (_e = (_d = e === null || e === void 0 ? void 0 : e.ui_element) === null || _d === void 0 ? void 0 : _d.id) !== null && _e !== void 0 ? _e : null,
333
- [IUserInteractionEvent_1.UserInteractionEventKey.InteractionName]: _an_interaction_type(e),
333
+ [IUserInteractionEvent_1.UserInteractionEventKey.InteractionType]: _an_interaction_type(e),
334
334
  positions: Array.isArray(e === null || e === void 0 ? void 0 : e.positions)
335
335
  ? e.positions.map((pos) => ({
336
336
  x: Math.trunc(pos.x),
@@ -14,6 +14,8 @@ const EventData_1 = require("./events/EventData");
14
14
  const SessionPropertyEventData_1 = require("./events/SessionPropertyEventData");
15
15
  const ExceptionEventData_1 = require("./events/ExceptionEventData");
16
16
  const HttpRequestEventData_1 = require("./events/HttpRequestEventData");
17
+ const NullUserAction_1 = require("./userAction/NullUserAction");
18
+ const UserActionImpl_1 = require("./userAction/UserActionImpl");
17
19
  const DynatraceArgValidators_1 = require("./DynatraceArgValidators");
18
20
  const TraceContextUtils_1 = require("./util/TraceContextUtils");
19
21
  const DECISION_REASON_TEXT = {
@@ -169,12 +171,14 @@ class DynatraceImpl {
169
171
  let parsedTraceparent = traceparent === undefined
170
172
  ? undefined
171
173
  : (0, TraceContextUtils_1.parseTraceparent)(traceparent);
174
+ let traceparentFromDynatrace = false;
172
175
  if (parsedTraceparent === undefined) {
173
176
  traceparent = (0, TraceContextUtils_1.generateTraceparentHeader)();
174
177
  parsedTraceparent = (0, TraceContextUtils_1.parseTraceparent)(traceparent);
175
178
  tracestate = undefined;
179
+ traceparentFromDynatrace = true;
176
180
  }
177
- tracestate = (0, TraceContextUtils_1.generateTracestate)(parsedTraceparent.parentId, tracestate);
181
+ tracestate = (0, TraceContextUtils_1.generateTracestate)(parsedTraceparent.parentId, traceparentFromDynatrace, tracestate);
178
182
  if (tracestate === undefined) {
179
183
  this.logger.info(LogMessages_1.LogMessage.TRACE_CONTEXT_DISABLED_OR_INVALID, {
180
184
  existingTraceparent: existingTraceparent !== null && existingTraceparent !== void 0 ? existingTraceparent : 'undefined',
@@ -187,5 +191,26 @@ class DynatraceImpl {
187
191
  tracestate,
188
192
  };
189
193
  }
194
+ createUserAction(configuration) {
195
+ if (!ConfigurationHandler_1.ConfigurationHandler.isConfigurationAvailable()) {
196
+ this.logger.info(LogMessages_1.LogMessage.CREATE_USER_ACTION_NOT_STARTED);
197
+ return new NullUserAction_1.NullUserAction();
198
+ }
199
+ this.logger.debug(LogMessages_1.LogMessage.CREATE_USER_ACTION, {
200
+ customName: configuration.customName,
201
+ completeAutomatically: configuration.completeAutomatically,
202
+ });
203
+ return new UserActionImpl_1.UserActionImpl(configuration);
204
+ }
205
+ setAutomaticUserActionDetection(enabled) {
206
+ if (!ConfigurationHandler_1.ConfigurationHandler.isConfigurationAvailable()) {
207
+ this.logger.info(LogMessages_1.LogMessage.SET_AUTOMATIC_USER_ACTION_DETECTION_NOT_STARTED);
208
+ return;
209
+ }
210
+ this.logger.debug(LogMessages_1.LogMessage.SET_AUTOMATIC_USER_ACTION_DETECTION, {
211
+ enabled,
212
+ });
213
+ DynatraceBridge_1.DynatraceNative.setAutomaticUserActionDetection(enabled);
214
+ }
190
215
  }
191
216
  exports.Dynatrace = new DynatraceImpl(TimestampProvider_1.defaultTimestampProvider);