@dynatrace/react-native-plugin 2.331.1 → 2.335.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +136 -177
- package/android/build.gradle +1 -1
- package/android/src/main/java/com/dynatrace/android/agent/DynatraceRNBridgeImpl.kt +7 -1
- package/android/src/main/java/com/dynatrace/android/agent/DynatraceUtils.kt +1 -0
- package/android/src/new/java/com/dynatrace/android/agent/DynatraceRNBridge.kt +1 -0
- package/android/src/old/java/com/dynatrace/android/agent/DynatraceRNBridge.kt +2 -1
- package/files/plugin-runtime.gradle +27 -13
- package/files/plugin.gradle +1 -1
- package/instrumentation/BabelPluginDynatrace.js +1 -0
- package/instrumentation/DynatraceInstrumentation.js +1 -1
- package/instrumentation/jsx/CreateElement.js +106 -6
- package/instrumentation/jsx/JsxDevRuntime.js +2 -6
- package/instrumentation/jsx/JsxRuntime.js +6 -10
- package/instrumentation/libs/UserInteraction.js +114 -0
- package/instrumentation/libs/community/gesture-handler/Touchables.InstrInfo.js +2 -0
- package/instrumentation/libs/community/gesture-handler/Touchables.js +3 -1
- package/instrumentation/libs/community/gesture-handler/index.js +3 -1
- package/instrumentation/libs/withOnPressMonitoring.js +55 -3
- package/ios/DynatraceRNBridge.mm +8 -1
- package/lib/core/Application.js +2 -0
- package/lib/core/Dynatrace.js +2 -1
- package/lib/core/UserPrivacyOptions.js +8 -1
- package/lib/core/configuration/ConfigurationHandler.js +21 -0
- package/lib/dynatrace-reporter.js +0 -14
- package/lib/dynatrace-transformer.js +10 -13
- package/lib/features/ui-interaction/Config.js +42 -0
- package/lib/features/ui-interaction/IUserInteractionEvent.js +16 -0
- package/lib/features/ui-interaction/Plugin.Fragment.Test.js +170 -0
- package/lib/features/ui-interaction/Plugin.js +289 -0
- package/lib/features/ui-interaction/RootDetection.js +51 -0
- package/lib/features/ui-interaction/RootWrapper.js +236 -0
- package/lib/features/ui-interaction/Run.js +38 -0
- package/lib/features/ui-interaction/Runtime.js +827 -0
- package/lib/features/ui-interaction/TouchMetaResolver.js +492 -0
- package/lib/features/ui-interaction/Types.js +14 -0
- package/lib/next/Dynatrace.js +1 -1
- package/lib/next/configuration/INativeRuntimeConfiguration.js +1 -0
- package/lib/next/configuration/RuntimeConfigurationObserver.js +47 -12
- package/lib/next/events/EventPipeline.js +9 -0
- package/package.json +19 -13
- package/react-native-dynatrace.podspec +1 -1
- package/scripts/Android.js +75 -62
- package/scripts/Config.js +12 -1
- package/scripts/core/InstrumentCall.js +1 -2
- package/scripts/core/LineOffsetAnalyzeCall.js +9 -15
- package/src/lib/core/interface/NativeDynatraceBridge.ts +1 -0
- package/types.d.ts +22 -9
- package/scripts/util/ReactOptions.js +0 -21
package/README.md
CHANGED
|
@@ -13,6 +13,8 @@ If you want to start using this plugin and are not a Dynatrace customer yet, hea
|
|
|
13
13
|
* User actions for onPress and onLongPress (Touchables, Buttons, Pickers, RefreshControl, Pressable)
|
|
14
14
|
* User actions for class and functional components (lifecycle events such as render(), didMount() and didUpdate())
|
|
15
15
|
* Reporting React Native errors
|
|
16
|
+
* Tracking navigation via `react.navigation.enabled`
|
|
17
|
+
* UI Interaction feature toggle via `react.userInteraction` (enable/disable user interaction capturing at runtime)
|
|
16
18
|
* Manual instrumentation
|
|
17
19
|
* Typescript bindings to add manual instrumentation
|
|
18
20
|
* New React-Native architecture
|
|
@@ -26,23 +28,23 @@ If you want to start using this plugin and are not a Dynatrace customer yet, hea
|
|
|
26
28
|
* Android Gradle plugin version 7.0+
|
|
27
29
|
* Java 11
|
|
28
30
|
* Kotlin 2.0.21 - see [Kotlin Compatibility Note](#kotlin-compatibility-note)
|
|
29
|
-
* Jetpack Compose 1.4 - 1.
|
|
31
|
+
* Jetpack Compose 1.4 - 1.10 - see [Compose Compatibility Note](#compose-compatibility-note)
|
|
30
32
|
* For iOS users: Minimum iOS 12
|
|
31
33
|
* NodeJS 16.0.0+ since our dependencies require NodeJS 16.0.0
|
|
32
34
|
|
|
33
35
|
## Agent Versions
|
|
34
|
-
|
|
36
|
+
These agent versions are configured in this plugin:
|
|
35
37
|
|
|
36
|
-
* Android Agent: 8.
|
|
37
|
-
* iOS Agent: 8.
|
|
38
|
+
* Android Agent: 8.335.1.1001
|
|
39
|
+
* iOS Agent: 8.335.1.1009
|
|
38
40
|
|
|
39
41
|
## Quick Setup
|
|
40
42
|
|
|
41
43
|
1. [Install plugin](#1-install-the-plugin)
|
|
42
|
-
2. [
|
|
43
|
-
3. [
|
|
44
|
-
4. [
|
|
45
|
-
5. [Build and run your app](#
|
|
44
|
+
2. [Setup configuration](#2-setup-dynatraceconfigjs)
|
|
45
|
+
3. [Register babel plugin](#3-register-our-babel-plugin-in-babelconfigjs)
|
|
46
|
+
4. [Register jsx-runtime](#4-register-our-jsx-runtime-in-babelconfigjs)
|
|
47
|
+
5. [Build and run your app](#5-build-and-run-your-app)
|
|
46
48
|
|
|
47
49
|
## Advanced topics
|
|
48
50
|
* [Manual OneAgent Startup](#manual-oneagent-startup)
|
|
@@ -64,12 +66,14 @@ This agent versions are configured in this plugin:
|
|
|
64
66
|
* [Set beacon headers](#setting-beacon-headers)
|
|
65
67
|
* [Exclude Individual JSX Elements](#exclude-individual-jsx-elements)
|
|
66
68
|
* [New RUM experience](#new-rum-experience)
|
|
69
|
+
* [User Interaction](#user-interaction)
|
|
67
70
|
* [Send Event](#send-event)
|
|
68
71
|
* [Send Session Property Event](#send-session-property-event)
|
|
69
72
|
* [Event Modifier](#event-modifier)
|
|
70
73
|
* [Send Exception Event](#send-exception-event)
|
|
71
74
|
* [Send HTTP Request Event](#send-http-request-event)
|
|
72
75
|
* [View Monitoring](#view-monitoring)
|
|
76
|
+
* [User Interaction](#user-interaction-1)
|
|
73
77
|
* [React Native Symbolication](#react-native-symbolication)
|
|
74
78
|
* [NPX Commands](#npx-commands)
|
|
75
79
|
* [npx instrumentDynatrace](#npx-instrumentdynatrace)
|
|
@@ -89,6 +93,9 @@ This agent versions are configured in this plugin:
|
|
|
89
93
|
* [Bundle Name and Version](#bundle-name-and-version)
|
|
90
94
|
* [Navigation](#navigation)
|
|
91
95
|
* [Source Map](#source-map)
|
|
96
|
+
* [User Interaction](#user-interaction-1)
|
|
97
|
+
* [Debugging our auto-instrumentation](#debugging-our-auto-instrumentation)
|
|
98
|
+
* [Using our legacy jscodeshift auto-instrumentation](#using-our-legacy-jscodeshift-auto-instrumentation)
|
|
92
99
|
* [Android block](#android-block)
|
|
93
100
|
* [iOS block](#ios-block)
|
|
94
101
|
* [Lifecycle modes](#lifecycle)
|
|
@@ -121,9 +128,7 @@ This agent versions are configured in this plugin:
|
|
|
121
128
|
> **Note**: If you are upgrading to React Native v0.70 (or newer) or using the @react-native-community/cli 9.x+ version, be aware that our automated script running before every start/run-android/run-ios command is no longer working. When your *dynatrace.config.js* changed be sure to execute `npx instrumentDynatrace` beforehand.
|
|
122
129
|
|
|
123
130
|
## 1. Install the plugin
|
|
124
|
-
1. Install the plugin by calling
|
|
125
|
-
- React Native v0.60 or newer : `npm install @dynatrace/react-native-plugin`
|
|
126
|
-
- React Native v0.59.x : `react-native install @dynatrace/react-native-plugin`.
|
|
131
|
+
1. Install the plugin by calling `npm install @dynatrace/react-native-plugin`
|
|
127
132
|
2. **iOS only :** If you use pods, you need to go into your `ios` directory and execute `pod install` to install the new Dynatrace dependency to your xCode project.
|
|
128
133
|
|
|
129
134
|
### Troubleshooting
|
|
@@ -131,81 +136,34 @@ This agent versions are configured in this plugin:
|
|
|
131
136
|
- Standalone Project: If you are using React Native standalone and embed it in your native project have a look [here](#configuration-of-standalone-react-native-project).
|
|
132
137
|
- If for some reason (e.g. seperate native projects) `react-native link` doesn't work as expected, [manually add the iOS agent to your project](#manually-adding-ios-oneagent-to-a-project).
|
|
133
138
|
|
|
134
|
-
## 2.
|
|
139
|
+
## 2. Setup dynatrace.config.js
|
|
135
140
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
Depending on your React Native version, you will need to use a different way to register the transformer. If you don't know the version, enter `react-native --version` in your terminal.
|
|
139
|
-
|
|
140
|
-
The following configuration must be added. If you already have a babel transformer (babelTransformerPath) in place, you need to [use the upstreamTransformer property in dynatrace.config.js](#using-a-second-transformer-besides-the-dynatrace-transformer) to use a transformer besides our dynatrace transformer.
|
|
141
|
-
|
|
142
|
-
In your project's root directory, create or extend `metro.config.js` so that it contains the following configuration properties `transformer.babelTransformerPath` and `reporter`:
|
|
143
|
-
|
|
144
|
-
#### For React Native v0.72.1 or newer
|
|
145
|
-
|
|
146
|
-
```js
|
|
147
|
-
const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config');
|
|
148
|
-
const defaultConfig = getDefaultConfig(__dirname);
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* Metro configuration
|
|
152
|
-
* https://facebook.github.io/metro/docs/configuration
|
|
153
|
-
*
|
|
154
|
-
* @type {import('metro-config').MetroConfig}
|
|
155
|
-
*/
|
|
156
|
-
const config = {
|
|
157
|
-
transformer: {
|
|
158
|
-
babelTransformerPath: require.resolve(
|
|
159
|
-
'@dynatrace/react-native-plugin/lib/dynatrace-transformer',
|
|
160
|
-
),
|
|
161
|
-
},
|
|
162
|
-
reporter: require('@dynatrace/react-native-plugin/lib/dynatrace-reporter'),
|
|
163
|
-
};
|
|
164
|
-
|
|
165
|
-
module.exports = mergeConfig(defaultConfig, config);
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
#### For Expo
|
|
141
|
+
> **Note**: If you are upgrading from a previous version of this plugin, you'll notice that the file format has changed. Your old configuration is still available in `dynatrace.config` and you have to copy your values to the new `dynatrace.config.js`.
|
|
169
142
|
|
|
170
|
-
|
|
171
|
-
const {getDefaultConfig} = require('expo/metro-config');
|
|
172
|
-
const config = getDefaultConfig(__dirname);
|
|
143
|
+
Define a mobile app in Dynatrace and open the Mobile app instrumentation settings. In the settings you will see a `dynatrace.config.js` file which can be downloaded for React Native. Download and copy this file into the root folder of your application. If you are not sure you can always use `npx configDynatrace` to create a default configuration file.
|
|
173
144
|
|
|
174
|
-
|
|
175
|
-
'@dynatrace/react-native-plugin/lib/dynatrace-transformer',
|
|
176
|
-
);
|
|
145
|
+
> **Note**: Define the components that you want to see lifecycle instrumented ([example](#lifecycle)). This is important as you will only see Application startup and Touches out of the box.
|
|
177
146
|
|
|
178
|
-
|
|
147
|
+
For more details about the configuration, see [Advanced topics](#structure-of-the-dynatracejs-file).
|
|
179
148
|
|
|
180
|
-
|
|
181
|
-
```
|
|
149
|
+
## 3. Register our babel plugin in babel.config.js
|
|
182
150
|
|
|
183
|
-
|
|
151
|
+
Add the Dynatrace babel plugin to your `babel.config.js`:
|
|
184
152
|
|
|
185
153
|
```js
|
|
186
154
|
module.exports = {
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
'@dynatrace/react-native-plugin/lib/dynatrace-transformer'
|
|
190
|
-
)
|
|
191
|
-
},
|
|
192
|
-
reporter: require('@dynatrace/react-native-plugin/lib/dynatrace-reporter'),
|
|
155
|
+
...
|
|
156
|
+
plugins: [..., '@dynatrace/react-native-plugin/instrumentation/BabelPluginDynatrace'],
|
|
193
157
|
};
|
|
194
158
|
```
|
|
195
159
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
> **Note**: If you are upgrading from a previous version of this plugin, you'll notice that the file format has changed. Your old configuration is still available in `dynatrace.config` and you have to copy your values to the new `dynatrace.config.js`.
|
|
199
|
-
|
|
200
|
-
Define a mobile app in Dynatrace and open the Mobile app instrumentation settings. In the settings you will see a `dynatrace.config.js` file which can be downloaded for React Native. Download and copy this file into the root folder of your application. If you are not sure you can always use `npx configDynatrace` to create a default configuration file.
|
|
160
|
+
This plugin handles the auto-instrumentation of your React Native code at build time.
|
|
201
161
|
|
|
202
|
-
> **Note**:
|
|
203
|
-
|
|
204
|
-
For more details about the configuration, see [Advanced topics](#structure-of-the-dynatracejs-file).
|
|
162
|
+
> **Note**: We recently moved our auto-instrumentation from a custom metro transformer to a babel plugin. The code shown above is the new and recommended way to add our auto-instrumentation to your project by adding the babel plugin directly. However, our plugin is backwards compatible in a sense that we keep supporting auto-instrumentation via the Dynatrace transformer and reporter. In short, no configuration change is needed. If you continue using the Dynatrace transformer and reporter, we reroute the instrumentation logic to the babel plugin internally.
|
|
205
163
|
|
|
206
|
-
## 4.
|
|
164
|
+
## 4. Register our jsx-runtime in babel.config.js
|
|
207
165
|
|
|
208
|
-
Depending on your version of Metro or Expo (if used), your babel configuration `babel.config.js
|
|
166
|
+
Depending on your version of Metro or Expo (if used), you additionally need to add our jsx-runtime to your babel configuration `babel.config.js`.
|
|
209
167
|
|
|
210
168
|
The changes have to be done in the following cases:
|
|
211
169
|
|
|
@@ -427,7 +385,7 @@ import { Dynatrace, DynatraceWebRequestTiming } from '@dynatrace/react-native-pl
|
|
|
427
385
|
const action = Dynatrace.enterManualAction('API Data Fetch');
|
|
428
386
|
const url = 'https://api.example.com/data';
|
|
429
387
|
const tag = await action.getRequestTag(url);
|
|
430
|
-
const timing = new DynatraceWebRequestTiming(
|
|
388
|
+
const timing = new DynatraceWebRequestTiming(tag, url);
|
|
431
389
|
|
|
432
390
|
try {
|
|
433
391
|
timing.startWebRequestTiming();
|
|
@@ -457,7 +415,7 @@ import { Dynatrace, DynatraceWebRequestTiming } from '@dynatrace/react-native-pl
|
|
|
457
415
|
const action = Dynatrace.enterManualAction('API Data Upload');
|
|
458
416
|
const url = 'https://api.example.com/upload';
|
|
459
417
|
const tag = await action.getRequestTag(url);
|
|
460
|
-
const timing = new DynatraceWebRequestTiming(
|
|
418
|
+
const timing = new DynatraceWebRequestTiming(tag, url);
|
|
461
419
|
const requestData = JSON.stringify({ key: 'value' });
|
|
462
420
|
|
|
463
421
|
try {
|
|
@@ -1012,6 +970,42 @@ Dynatrace.sendEvent(new EventData()
|
|
|
1012
970
|
Dynatrace.startView("UserProfileDetailed");
|
|
1013
971
|
```
|
|
1014
972
|
|
|
973
|
+
### User Interaction
|
|
974
|
+
|
|
975
|
+
User Interaction is an automatic instrumentation feature that captures touch and press events in your React Native application without requiring any manual API calls. When enabled, the plugin instruments your UI components at build time and sends structured interaction events to Dynatrace at runtime.
|
|
976
|
+
|
|
977
|
+
To enable this feature, see the [User Interaction configuration](#user-interaction-1) section.
|
|
978
|
+
|
|
979
|
+
#### Produced data
|
|
980
|
+
|
|
981
|
+
Each captured interaction produces an event describing what the user touched and where. The event includes:
|
|
982
|
+
|
|
983
|
+
- **Element name** — the resolved label of the touched element, derived from its visible text, accessibility label, component name, or test ID.
|
|
984
|
+
- **Component type** — the type of the UI component that was touched (e.g. `Pressable`).
|
|
985
|
+
- **Element path** — a stable path through the component tree that uniquely identifies the element (e.g. `App/View[1]/Pressable[1]`).
|
|
986
|
+
- **Interaction type** — how the user interacted (e.g. `touch`).
|
|
987
|
+
- **Position** — the screen coordinates where the touch occurred.
|
|
988
|
+
|
|
989
|
+
In some cases, a **responder** is also included. The responder is the component that ultimately handled the user's touch — for example, a `Pressable` that received the press event. It carries the same name, component type, and path information as the touched element, and can differ when a touch is visually on a child element but handled by a parent.
|
|
990
|
+
|
|
991
|
+
#### Example event
|
|
992
|
+
|
|
993
|
+
```json
|
|
994
|
+
{
|
|
995
|
+
"characteristics.has_user_interaction": true,
|
|
996
|
+
"ui_element.detected_name": "LoginButton",
|
|
997
|
+
"ui_element.components": ["Pressable"],
|
|
998
|
+
"ui_element.id": "App/View[1]/Pressable[1]",
|
|
999
|
+
"ui_element.name_origin": "component",
|
|
1000
|
+
"interaction.type": "touch",
|
|
1001
|
+
"positions": [{ "x": 120, "y": 460 }],
|
|
1002
|
+
"ui_element.responder.detected_name": "Pressable",
|
|
1003
|
+
"ui_element.responder.components": ["Pressable"],
|
|
1004
|
+
"ui_element.responder.id": "App/View[1]/Pressable[1]",
|
|
1005
|
+
"ui_element.responder.name_origin": "component"
|
|
1006
|
+
}
|
|
1007
|
+
```
|
|
1008
|
+
|
|
1015
1009
|
### React Native Symbolication
|
|
1016
1010
|
|
|
1017
1011
|
Dynatrace can automatically symbolicate JavaScript stack traces captured by the plugin using sourcemaps. This allows you to view human-readable file names, line numbers, and column information in your crash reports.
|
|
@@ -1031,13 +1025,6 @@ To generate a sourcemap:
|
|
|
1031
1025
|
* Then run `npx react-native run-ios --mode Release`, or
|
|
1032
1026
|
* Build for release in Xcode
|
|
1033
1027
|
|
|
1034
|
-
#### Accounting for Auto-Instrumentation
|
|
1035
|
-
|
|
1036
|
-
Since the plugin auto-instruments your code, sourcemap line numbers may be slightly offset. To ensure accurate symbolication:
|
|
1037
|
-
|
|
1038
|
-
* **Android**: Automatic patching is **enabled by default** and patches sourcemaps automatically at the end of every release build (see [Source Map](#source-map) configuration)
|
|
1039
|
-
* **iOS**: There is currently **no automation** available. You **must** execute [`npx lineOffsetDynatrace`](#npx-lineoffsetdynatrace) to patch your sourcemap files before uploading them to Dynatrace. Without this step, line numbers will be slightly off depending on instrumentation in iOS
|
|
1040
|
-
|
|
1041
1028
|
#### Uploading Sourcemaps
|
|
1042
1029
|
|
|
1043
1030
|
Once generated and patched, upload your sourcemaps to Dynatrace. For detailed instructions, see the [symbol file management documentation](https://docs.dynatrace.com/docs/observe/digital-experience/mobile-applications/analyze-and-use/upload-and-manage-symbol-files).
|
|
@@ -1068,20 +1055,6 @@ npx configDynatrace [optional: config=...]
|
|
|
1068
1055
|
|
|
1069
1056
|
* `config=C:\SpecialFolderForDynatrace\dynatrace.config.js`: If you have not got your config file in the root folder of the React Native project but somewhere else.
|
|
1070
1057
|
|
|
1071
|
-
## npx lineOffsetDynatrace
|
|
1072
|
-
|
|
1073
|
-
Our auto-instrumentation modifies your source code during the build process, which causes line numbers in your sourcemaps to become slightly offset from the original source. This can result in incorrect line numbers when viewing crash reports or stack traces in Dynatrace.
|
|
1074
|
-
|
|
1075
|
-
The `npx lineOffsetDynatrace` command patches your sourcemap file with offset information, allowing Dynatrace to accurately map instrumented line numbers back to the original source code. The patching process adds Dynatrace-specific metadata alongside the original sourcemap content without modifying any existing fields, ensuring your sourcemap continues to work as expected with all standard tooling.
|
|
1076
|
-
|
|
1077
|
-
**Usage:**
|
|
1078
|
-
|
|
1079
|
-
```
|
|
1080
|
-
npx lineOffsetDynatrace sourcemapPath=/path/to/your/sourcemap.map
|
|
1081
|
-
```
|
|
1082
|
-
|
|
1083
|
-
* `sourcemapPath=/path/to/your/sourcemap.map`: **(Required)** The path to the sourcemap file that should be patched.
|
|
1084
|
-
|
|
1085
1058
|
## Customizing paths for configuration
|
|
1086
1059
|
|
|
1087
1060
|
> **Note:** This feature works directly on run-android, run-ios or start command only for React Native v0.60.1 or newer until v0.69.x.
|
|
@@ -1269,6 +1242,47 @@ react: {
|
|
|
1269
1242
|
|
|
1270
1243
|
This activates the debug mode. You will get more console output during instrumentation and at runtime.
|
|
1271
1244
|
|
|
1245
|
+
|
|
1246
|
+
#### User Interaction
|
|
1247
|
+
|
|
1248
|
+
```js
|
|
1249
|
+
react: {
|
|
1250
|
+
userInteraction: true // set it to true here if you want to enable UI interaction, default value is false
|
|
1251
|
+
}
|
|
1252
|
+
```
|
|
1253
|
+
|
|
1254
|
+
Enables or disables the UI interaction (user interaction) feature.
|
|
1255
|
+
Set to false to disable capturing of user interactions (e.g., touch/click actions) produced by the React Native UI interaction instrumentation.
|
|
1256
|
+
|
|
1257
|
+
##### What customers will observe after enabling UI Interaction
|
|
1258
|
+
|
|
1259
|
+
After setting `react.userInteraction: true` and rebuilding with instrumentation, the expected flow is:
|
|
1260
|
+
|
|
1261
|
+
1. Build-time instrumentation wraps supported UI elements and app root entrypoints.
|
|
1262
|
+
2. At runtime, touch/press interactions are captured and converted into UI interaction events.
|
|
1263
|
+
3. Events are processed by the plugin event pipeline and sent to Dynatrace.
|
|
1264
|
+
4. In Dynatrace, customers can analyze captured user interactions (for example, touch-driven behavior and related UI element context).
|
|
1265
|
+
|
|
1266
|
+
Notes:
|
|
1267
|
+
|
|
1268
|
+
- No extra UI needs to be added in customer screens for standard automatic capture.
|
|
1269
|
+
- If `react.debug` is enabled, additional debug output can appear during instrumentation/runtime.
|
|
1270
|
+
|
|
1271
|
+
##### Runtime switching (config + remote configuration observer)
|
|
1272
|
+
|
|
1273
|
+
UI Interaction can be controlled by two layers:
|
|
1274
|
+
|
|
1275
|
+
1. **Build/config layer (`dynatrace.config.js`)**
|
|
1276
|
+
- `react.userInteraction: true|false` controls whether the UI Interaction instrumentation feature is applied.
|
|
1277
|
+
|
|
1278
|
+
2. **Runtime remote layer (`RuntimeConfigurationObserver`)**
|
|
1279
|
+
- Runtime emission checks the remote flag `touch_interaction_enabled`.
|
|
1280
|
+
- If remote flag is present, it is used as the source of truth.
|
|
1281
|
+
- If remote flag is temporarily unavailable, the plugin falls back to the last known good remote value.
|
|
1282
|
+
- If no remote value was received yet, runtime defaults to enabled behavior.
|
|
1283
|
+
|
|
1284
|
+
In short: local config enables the feature path, while remote configuration can dynamically allow/deny event emission at runtime.
|
|
1285
|
+
|
|
1272
1286
|
#### Error Handler
|
|
1273
1287
|
|
|
1274
1288
|
```js
|
|
@@ -1338,33 +1352,32 @@ react: {
|
|
|
1338
1352
|
}
|
|
1339
1353
|
```
|
|
1340
1354
|
|
|
1341
|
-
####
|
|
1355
|
+
#### Debugging our auto-instrumentation
|
|
1342
1356
|
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
The following is an example of how this feature can be configured in your `dynatrace.config.js` file:
|
|
1357
|
+
You can see the changes our auto-instrumentation is making to your code with this flag:
|
|
1346
1358
|
|
|
1347
1359
|
```js
|
|
1348
1360
|
react: {
|
|
1349
|
-
|
|
1350
|
-
enabled: true
|
|
1351
|
-
}
|
|
1361
|
+
debugBabelPlugin: true
|
|
1352
1362
|
}
|
|
1353
1363
|
```
|
|
1354
1364
|
|
|
1355
|
-
|
|
1365
|
+
The changes our auto-instrumentation is making now get dumped into the `node_modules/@dynatrace/react-native-plugin/build` folder when building the Javascript bundle. The `*.dtx` files show what your code looks like after only our auto-instrumentation was applied to your code. The `*.dtx.downstream` files show what your code looks like after both our auto-instrumentation and all other babel plugins were applied to your code.
|
|
1356
1366
|
|
|
1357
|
-
|
|
1367
|
+
> **Note:** This feature increases the time it takes to build the Javascript bundle. Only use it for debugging purposes. Deactivate it otherwise, especially when fast build times are important.
|
|
1368
|
+
|
|
1369
|
+
#### Using our legacy jscodeshift auto-instrumentation
|
|
1370
|
+
|
|
1371
|
+
We recently moved our auto-instrumentation to a babel plugin. In case you need to, you can still switch to the old jscodeshift auto-instrumentation with this flag:
|
|
1358
1372
|
|
|
1359
1373
|
```js
|
|
1360
1374
|
react: {
|
|
1361
|
-
|
|
1362
|
-
enabled: true,
|
|
1363
|
-
androidSourcemapLocation: 'sourcemap.map'
|
|
1364
|
-
}
|
|
1375
|
+
useLegacyJscodeshift: true
|
|
1365
1376
|
}
|
|
1366
1377
|
```
|
|
1367
1378
|
|
|
1379
|
+
> **Note:** When we moved our auto-instrumentation to a babel plugin, we removed documentation that was only relevant for the jscodeshift auto-instrumentation. Most notably, we removed documentation concerning registering a custom metro transformer and patching sourcemaps. If you use the `useLegacyJscodeshift` flag, please refer to the [legacy documentation (v2.333.1)](https://www.npmjs.com/package/@dynatrace/react-native-plugin/v/2.333.1) for details on custom metro transformers and sourcemap patching.
|
|
1380
|
+
|
|
1368
1381
|
### Android block
|
|
1369
1382
|
|
|
1370
1383
|
The Android block is a wrapper for the Android configuration you find in the WebUI (in the Mobile Application Settings). Copy the content into the following block:
|
|
@@ -1663,75 +1676,6 @@ module.exports = {
|
|
|
1663
1676
|
};
|
|
1664
1677
|
```
|
|
1665
1678
|
|
|
1666
|
-
## Using a second transformer besides the dynatrace transformer
|
|
1667
|
-
|
|
1668
|
-
If you want to register the Dynatrace transformer in your configuration and you already have a transformer in place, change the upstreaming transformer for the Dynatrace transformer.
|
|
1669
|
-
|
|
1670
|
-
This can be done via a configuration value in the `dynatrace.config.js`. The following example shows how the configuration might look like for the popular `react-native-svg-transformer`. Be aware that the following example is targeting *React Native v0.72.1* or newer. Be aware if you are using a different second transformer, you need to change `react-native-svg-transformer/react-native` accordingly.
|
|
1671
|
-
|
|
1672
|
-
#### dynatrace.config.js
|
|
1673
|
-
|
|
1674
|
-
```js
|
|
1675
|
-
// The `...` only indicates that there are other values as well, but we've omitted them in this example.
|
|
1676
|
-
module.exports = {
|
|
1677
|
-
react : {
|
|
1678
|
-
upstreamTransformer: require.resolve('react-native-svg-transformer/react-native'),
|
|
1679
|
-
// ...
|
|
1680
|
-
},
|
|
1681
|
-
// ...
|
|
1682
|
-
};
|
|
1683
|
-
```
|
|
1684
|
-
|
|
1685
|
-
#### metro.config.js for React Native v0.72.1 or newer
|
|
1686
|
-
```js
|
|
1687
|
-
const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config');
|
|
1688
|
-
const defaultConfig = getDefaultConfig(__dirname);
|
|
1689
|
-
const {assetExts, sourceExts} = defaultConfig.resolver;
|
|
1690
|
-
|
|
1691
|
-
/**
|
|
1692
|
-
* Metro configuration
|
|
1693
|
-
* https://facebook.github.io/metro/docs/configuration
|
|
1694
|
-
*
|
|
1695
|
-
* @type {import('metro-config').MetroConfig}
|
|
1696
|
-
*/
|
|
1697
|
-
const config = {
|
|
1698
|
-
transformer: {
|
|
1699
|
-
babelTransformerPath: require.resolve(
|
|
1700
|
-
'@dynatrace/react-native-plugin/lib/dynatrace-transformer',
|
|
1701
|
-
),
|
|
1702
|
-
},
|
|
1703
|
-
reporter: require('@dynatrace/react-native-plugin/lib/dynatrace-reporter'),
|
|
1704
|
-
resolver: {
|
|
1705
|
-
assetExts: assetExts.filter((ext) => ext !== 'svg'),
|
|
1706
|
-
sourceExts: [...sourceExts, 'cjs', 'svg'],
|
|
1707
|
-
},
|
|
1708
|
-
};
|
|
1709
|
-
|
|
1710
|
-
module.exports = mergeConfig(defaultConfig, config);
|
|
1711
|
-
```
|
|
1712
|
-
|
|
1713
|
-
#### metro.config.js for React Native v0.59 or newer
|
|
1714
|
-
|
|
1715
|
-
```js
|
|
1716
|
-
const { getDefaultConfig } = require("metro-config");
|
|
1717
|
-
|
|
1718
|
-
module.exports = (async () => {
|
|
1719
|
-
const {
|
|
1720
|
-
resolver: { sourceExts, assetExts }
|
|
1721
|
-
} = await getDefaultConfig();
|
|
1722
|
-
return {
|
|
1723
|
-
transformer: {
|
|
1724
|
-
babelTransformerPath: require.resolve('@dynatrace/react-native-plugin/lib/dynatrace-transformer')
|
|
1725
|
-
},
|
|
1726
|
-
reporter: require('@dynatrace/react-native-plugin/lib/dynatrace-reporter'),
|
|
1727
|
-
resolver: {
|
|
1728
|
-
assetExts: assetExts.filter((ext) => ext !== "svg"),
|
|
1729
|
-
sourceExts: [...sourceExts, "cjs", "svg"]
|
|
1730
|
-
}
|
|
1731
|
-
};
|
|
1732
|
-
})();
|
|
1733
|
-
```
|
|
1734
|
-
|
|
1735
1679
|
## Maven Central in top-level gradle file
|
|
1736
1680
|
|
|
1737
1681
|
Because the Dynatrace Android agent now requires the MavenCentral repository, if either `jcenter()` or `mavenCentral()` is not added inside of **ALL** the repositories blocks via the [top-level build.gradle](https://dt-url.net/jm610pso), the build will fail.
|
|
@@ -1825,7 +1769,7 @@ In summary, ensure your build fulfills our Kotlin 2.0.21 requirement while simul
|
|
|
1825
1769
|
|
|
1826
1770
|
## Compose Compatibility Note
|
|
1827
1771
|
|
|
1828
|
-
Our Android Agent currently supports **Jetpack Compose 1.4 - 1.
|
|
1772
|
+
Our Android Agent currently supports **Jetpack Compose 1.4 - 1.10**. If you are using an incompatible version of Jetpack Compose, you may encounter the following error message during build:
|
|
1829
1773
|
|
|
1830
1774
|
```
|
|
1831
1775
|
Could not resolve all dependencies for configuration ':app:debugCompileClasspath'.
|
|
@@ -1972,6 +1916,21 @@ If you are struggling with a problem, submit a support ticket to Dynatrace (supp
|
|
|
1972
1916
|
<br/><br/>
|
|
1973
1917
|
## Changelog
|
|
1974
1918
|
|
|
1919
|
+
2.335.1
|
|
1920
|
+
* Updated Android (8.335.1.1001) & iOS Agent (8.335.1.1009)
|
|
1921
|
+
* Dynatrace Android configuration (`dynatrace.gradle`) is now written directly next to the `build.gradle` file instead of inside `node_modules`. Existing projects with the old path are migrated automatically.
|
|
1922
|
+
* Updated Android Gradle plugin configuration for Gradle 9 compatibility in `plugin-runtime.gradle`.
|
|
1923
|
+
* Moved auto-instrumentation from jscodeshift to a Babel plugin, improvements include:
|
|
1924
|
+
* Significantly faster JS bundle builds
|
|
1925
|
+
* Sourcemaps now natively account for our auto-instrumentation - no patching needed
|
|
1926
|
+
* Added instrumentation for `BorderlessButton` and `BaseButton` from `react-native-gesture-handler`.
|
|
1927
|
+
|
|
1928
|
+
2.333.1
|
|
1929
|
+
* Jetpack Compose support range extended to 1.4 - 1.10 see [Compose Compatibility Note](#compose-compatibility-note)
|
|
1930
|
+
* Updated Android (8.333.1.1006) & iOS Agent (8.333.1.1005)
|
|
1931
|
+
* Added Configuration flag to enable/disable the [User Interaction feature](#user-interaction-1).
|
|
1932
|
+
* Added [User Interaction feature](#user-interaction) to collect UI interaction data such as touches, providing insights into user behavior
|
|
1933
|
+
|
|
1975
1934
|
2.331.1
|
|
1976
1935
|
* Updated Android (8.331.1.1004) & iOS Agent (8.331.1.1008)
|
|
1977
1936
|
|
package/android/build.gradle
CHANGED
|
@@ -72,7 +72,7 @@ repositories {
|
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
dependencies {
|
|
75
|
-
implementation 'com.dynatrace.agent:agent-android:8.
|
|
75
|
+
implementation 'com.dynatrace.agent:agent-android:8.335.1.1001'
|
|
76
76
|
implementation "com.facebook.react:react-native:${safeExtGet('reactNative', '+')}"
|
|
77
77
|
}
|
|
78
78
|
|
|
@@ -75,6 +75,7 @@ class DynatraceRNBridgeImpl(
|
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
Dynatrace.startup(reactApplicationContext, builder.buildConfiguration())
|
|
78
|
+
|
|
78
79
|
promise.resolve(true)
|
|
79
80
|
}
|
|
80
81
|
}
|
|
@@ -383,6 +384,9 @@ class DynatraceRNBridgeImpl(
|
|
|
383
384
|
)!!
|
|
384
385
|
)
|
|
385
386
|
)
|
|
387
|
+
if (userPrivacyOptions.hasKey("_screenRecordOptedIn")) {
|
|
388
|
+
optionsBuilder.withScreenRecordOptedIn(userPrivacyOptions.getBoolean("_screenRecordOptedIn"))
|
|
389
|
+
}
|
|
386
390
|
Dynatrace.applyUserPrivacyOptions(
|
|
387
391
|
optionsBuilder
|
|
388
392
|
.build()
|
|
@@ -396,6 +400,7 @@ class DynatraceRNBridgeImpl(
|
|
|
396
400
|
val privacyMap = Arguments.createMap()
|
|
397
401
|
privacyMap.putString("dataCollectionLevel", options.dataCollectionLevel.name)
|
|
398
402
|
privacyMap.putBoolean("crashReportingOptedIn", options.isCrashReportingOptedIn)
|
|
403
|
+
privacyMap.putBoolean("screenRecordOptedIn", options.isScreenRecordOptedIn)
|
|
399
404
|
promise.resolve(privacyMap)
|
|
400
405
|
}
|
|
401
406
|
}
|
|
@@ -446,4 +451,5 @@ class DynatraceRNBridgeImpl(
|
|
|
446
451
|
private fun shouldWorkOnAndroid(platform: String?): Boolean {
|
|
447
452
|
return platform == null || platform == PLATFORM_ANDROID || platform == ""
|
|
448
453
|
}
|
|
449
|
-
|
|
454
|
+
|
|
455
|
+
}
|
|
@@ -1,19 +1,33 @@
|
|
|
1
|
-
import org.gradle.
|
|
1
|
+
import org.gradle.process.ExecOperations
|
|
2
|
+
import javax.inject.Inject
|
|
3
|
+
|
|
4
|
+
abstract class RunLineOffsetTask extends DefaultTask {
|
|
5
|
+
@Internal
|
|
6
|
+
abstract DirectoryProperty getWorkingDirectory()
|
|
7
|
+
|
|
8
|
+
@Inject
|
|
9
|
+
abstract ExecOperations getExecOperations()
|
|
10
|
+
|
|
11
|
+
@TaskAction
|
|
12
|
+
void run() {
|
|
13
|
+
execOperations.exec {
|
|
14
|
+
workingDir workingDirectory.get().asFile
|
|
15
|
+
if (System.getProperty('os.name').toLowerCase().contains('windows')) {
|
|
16
|
+
commandLine 'cmd', '/c', 'npx', 'lineOffsetDynatrace'
|
|
17
|
+
} else {
|
|
18
|
+
commandLine 'npx', 'lineOffsetDynatrace'
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
2
23
|
|
|
3
24
|
android.applicationVariants.all { variant ->
|
|
4
25
|
if (variant.buildType.name == "release") {
|
|
26
|
+
def lineOffsetTask = tasks.register("runLineOffset${variant.name.capitalize()}", RunLineOffsetTask) {
|
|
27
|
+
workingDirectory = layout.projectDirectory
|
|
28
|
+
}
|
|
5
29
|
variant.mergeAssetsProvider.configure { task ->
|
|
6
|
-
task.
|
|
7
|
-
exec {
|
|
8
|
-
workingDir rootDir
|
|
9
|
-
if (DefaultNativePlatform.currentOperatingSystem.isWindows()) {
|
|
10
|
-
// On windows, npx.cmd may not be a true binary executable and may need to be interpreted by a shell instead of executed direclty
|
|
11
|
-
commandLine 'cmd', '/c', 'npx', 'lineOffsetDynatrace'
|
|
12
|
-
} else {
|
|
13
|
-
commandLine 'npx', 'lineOffsetDynatrace'
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
}
|
|
30
|
+
task.dependsOn(lineOffsetTask)
|
|
17
31
|
}
|
|
18
32
|
}
|
|
19
|
-
}
|
|
33
|
+
}
|
package/files/plugin.gradle
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var _templateObject,_templateObject2,_templateObject3,_templateObject4,_templateObject5,_templateObject6,_interopRequireDefault=require("@babel/runtime/helpers/interopRequireDefault"),_taggedTemplateLiteral2=_interopRequireDefault(require("@babel/runtime/helpers/taggedTemplateLiteral"));function _createForOfIteratorHelper(e,t){var n,r,a,i,o="undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(o)return a=!(r=!0),{s:function(){o=o.call(e)},n:function(){var e=o.next();return r=e.done,e},e:function(e){a=!0,n=e},f:function(){try{r||null==o.return||o.return()}finally{if(a)throw n}}};if(Array.isArray(e)||(o=_unsupportedIterableToArray(e))||t&&e&&"number"==typeof e.length)return o&&(e=o),i=0,{s:t=function(){},n:function(){return i>=e.length?{done:!0}:{done:!1,value:e[i++]}},e:function(e){throw e},f:t};throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function _unsupportedIterableToArray(e,t){var n;if(e)return"string"==typeof e?_arrayLikeToArray(e,t):"Map"===(n="Object"===(n={}.toString.call(e).slice(8,-1))&&e.constructor?e.constructor.name:n)||"Set"===n?Array.from(e):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?_arrayLikeToArray(e,t):void 0}function _arrayLikeToArray(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n<t;n++)r[n]=e[n];return r}Object.defineProperty(exports,"__esModule",{value:!0});var reactOptions,fspath=require("path"),fs=require("fs"),core_1=require("@babel/core"),generator_1=require("@babel/generator"),PathsConstants_1=require("../scripts/PathsConstants"),Config_1=require("../scripts/Config"),GetValuesFromPackage_1=require("../lib/core/util/GetValuesFromPackage"),Types_1=require("./model/Types"),INSTRUMENTATION_LIBS="@dynatrace/react-native-plugin/instrumentation/libs",hasJSX=function(e){var t=!1;return e.traverse({"JSXElement|JSXFragment":function(){t=!0}}),t},instrumentUserInteraction=function(e){e.traverse({"FunctionDeclaration|ObjectMethod":function(e){var e=e.node,t=core_1.types.isFunctionDeclaration(e)?e.id:e.key;core_1.types.isIdentifier(t,{name:"registerComponent"})&&(t="".concat(INSTRUMENTATION_LIBS,"/UserInteraction"),e.body.body.unshift(core_1.template.statement('componentProvider = require("'.concat(t,'").wrapProvider(componentProvider);'))()))}})},instrumentAppRegistry=function(e){e.traverse({"FunctionDeclaration|ObjectMethod":function(e){var e=e.node,t=core_1.types.isFunctionDeclaration(e)?e.id:e.key;core_1.types.isIdentifier(t,{name:"runApplication"})&&e.body.body.unshift(core_1.template.statement(_templateObject=_templateObject||(0,_taggedTemplateLiteral2.default)(['require("@dynatrace/react-native-plugin").ApplicationHandler.startup();']))())}})},instrumentExceptionsManager=function(e){var t,n=null!=(t=null==(t=null==reactOptions?void 0:reactOptions.errorHandler)?void 0:t.reportFatalErrorAsCrash)&&t,r=(null==reactOptions?void 0:reactOptions.autoStart)&&(null==(t=null==reactOptions?void 0:reactOptions.errorHandler)?void 0:t.enabled);e.traverse({FunctionDeclaration:function(e){var t;core_1.types.isIdentifier(e.node.id,{name:"handleException"})&&(t=core_1.template.statement(_templateObject2=_templateObject2||(0,_taggedTemplateLiteral2.default)(['\n setTimeout(() => BODY, require("@dynatrace/react-native-plugin/lib/core/ErrorHandler")\n .reportErrorToDynatrace(e, isFatal, CRASH, AUTO));\n ']))({BODY:core_1.types.cloneNode(e.node.body),CRASH:core_1.types.booleanLiteral(n),AUTO:core_1.types.booleanLiteral(!!r)}),e.node.body.body=[t])}})},instrumentCssInterop=function(e){e.traverse({CallExpression:function(e){core_1.types.isIdentifier(e.node.callee,{name:"require"})&&(e=e.node.arguments[0],core_1.types.isStringLiteral(e))&&("react/jsx-runtime"===e.value?e.value="@dynatrace/react-native-plugin/jsx-runtime":"react/jsx-dev-runtime"===e.value&&(e.value="@dynatrace/react-native-plugin/jsx-dev-runtime"))}})},instrumentNavigation=function(e){e.traverse({VariableDeclarator:function(e){var t;core_1.types.isIdentifier(e.node.id,{name:"getRootState"})&&(t=core_1.template.statement(_templateObject3=_templateObject3||(0,_taggedTemplateLiteral2.default)(["\n require(PATH).monitorNavigation(getRootState);\n "]))({PATH:core_1.types.stringLiteral("".concat(INSTRUMENTATION_LIBS,"/react-navigation/ReactNavigation"))}),e.parentPath.insertAfter(t))}})},instrumentReactCreateElement=function(e){var t=core_1.template.statement(_templateObject4=_templateObject4||(0,_taggedTemplateLiteral2.default)(["\n require(PATH).instrumentCreateElement(module.exports);\n "]))({PATH:core_1.types.stringLiteral("@dynatrace/react-native-plugin/instrumentation/jsx/ElementHelper")});e.pushContainer("body",t)},instrumentComponents=function(e,n){e.traverse({FunctionDeclaration:function(e){var t;hasJSX(e)&&(t=e.node,core_1.types.isIdentifier(t.id))&&null!=(e=e.getStatementParent())&&e.insertAfter(n(t.id.name,Types_1.Types.FunctionalComponent))},ClassDeclaration:function(e){var t;hasJSX(e)&&(t=e.node,core_1.types.isIdentifier(t.id))&&null!=(e=e.getStatementParent())&&e.insertAfter(n(t.id.name,Types_1.Types.ClassComponent))},"FunctionExpression|ArrowFunctionExpression":function(e){var t;hasJSX(e)&&(t=e.parent,void 0!==(t=core_1.types.isVariableDeclarator(t)&&core_1.types.isIdentifier(t.id)?t.id.name:core_1.types.isAssignmentExpression(t)&&core_1.types.isIdentifier(t.left)?t.left.name:void 0))&&null!=(e=e.getStatementParent())&&e.insertAfter(n(t,Types_1.Types.FunctionalComponent))}})},instrumentLifecycle=function(e){instrumentComponents(e,function(e,t){return core_1.template.statement(_templateObject5=_templateObject5||(0,_taggedTemplateLiteral2.default)(["NAME._dtInfo = { type: TYPE, name: 'NAME_STR' }"]))({NAME:core_1.types.identifier(e),TYPE:core_1.types.numericLiteral(t),NAME_STR:core_1.types.stringLiteral(e)})})},instrumentComponentNames=function(e){instrumentComponents(e,function(e){return core_1.template.statement(_templateObject6=_templateObject6||(0,_taggedTemplateLiteral2.default)(["NAME.dtName = 'NAME_STR'"]))({NAME:core_1.types.identifier(e),NAME_STR:core_1.types.stringLiteral(e)})})},instrumentInput=function(e){var l=new Map([["react-native",{proxy:"".concat(INSTRUMENTATION_LIBS,"/react-native/"),components:new Set(["TouchableHighlight","TouchableNativeFeedback","TouchableOpacity","TouchableWithoutFeedback","Button","RefreshControl","Text","Pressable","Switch"])}],["react-native-gesture-handler",{proxy:"".concat(INSTRUMENTATION_LIBS,"/community/gesture-handler/"),components:new Set(["TouchableHighlight","TouchableNativeFeedback","TouchableOpacity","TouchableWithoutFeedback","RectButton","BorderlessButton","BaseButton"])}],["@react-native-picker/picker",{proxy:"".concat(INSTRUMENTATION_LIBS,"/community/Picker"),components:new Set(["Picker","PickerIOS"])}]]);e.traverse({ImportDeclaration:function(e){if(void 0===e.node.processed){var t=e.node.source;if(l.has(t.value)){var r=l.get(t.value),n=e.node.specifiers,a=[],i=[];if(n.forEach(function(e,t){var n;core_1.types.isImportSpecifier(e)&&(n=core_1.types.isIdentifier(e.imported)?e.imported.name:e.imported.value,r.components.has(n)||(a.push(e),i.push(t)))}),a.length!==n.length){var o,s=_createForOfIteratorHelper(i.reverse());try{for(s.s();!(o=s.n()).done;){var c=o.value;n.splice(c,1)}}catch(e){s.e(e)}finally{s.f()}0<a.length&&((t=core_1.types.importDeclaration(a,core_1.types.stringLiteral(t.value))).processed=!0,e.insertBefore(t)),e.node.source=core_1.types.stringLiteral(r.proxy),e.scope.crawl()}}}},CallExpression:function(e){core_1.types.isIdentifier(e.node.callee,{name:"require"})&&(e=e.node.arguments[0],core_1.types.isStringLiteral(e))&&l.has(e.value)&&(e.value=l.get(e.value).proxy)}})},instrumentJsxNames=function(e){e.traverse({JSXOpeningElement:function(e){var t=e.node.name,t=core_1.types.isJSXIdentifier(t)?t.name:core_1.types.isJSXMemberExpression(t)?(0,generator_1.default)(t).code:void 0;t&&e.node.attributes.push(core_1.types.jsxAttribute(core_1.types.jsxIdentifier("dtName"),core_1.types.stringLiteral(t)))}})},instrumentConfigurationPreset=function(e){var t,n=(0,GetValuesFromPackage_1.getHostAppBundleInfo)(PathsConstants_1.default.getPackageJsonFile()),r={getLifecycleUpdate:reactOptions.lifecycle.includeUpdate,getLogLevel:reactOptions.debug?0:1,getBundleName:null!=(t=reactOptions.bundleName)?t:null==n?void 0:n.name,getBundleVersion:null!=(t=reactOptions.bundleVersion)?t:null==n?void 0:n.version,getActionNamePrivacy:reactOptions.input.actionNamePrivacy,isErrorHandlerEnabled:reactOptions.errorHandler.enabled,isReportFatalErrorAsCrash:reactOptions.errorHandler.reportFatalErrorAsCrash,isAutoStartupEnabled:reactOptions.autoStart};e.traverse({ClassMethod:function(e){var t;core_1.types.isIdentifier(e.node.key)&&void 0!==(t=r[e.node.key.name])&&(e=e.node.body.body[0],core_1.types.isReturnStatement(e))&&(e.argument=core_1.types.valueToNode(t))}})};exports.default=function(){return{visitor:{Program:function(e,t){reactOptions=(0,Config_1.readConfigDefault)().react;var n,r,a,i,o,s,c=t.filename;void 0!==c&&(a=function(){for(var e=arguments.length,t=new Array(e),n=0;n<e;n++)t[n]=arguments[n];return t.some(function(e){return c.includes(fspath.join("node_modules",e)+fspath.sep)})},s=function(){for(var e=arguments.length,t=new Array(e),n=0;n<e;n++)t[n]=arguments[n];return t.some(function(e){return c.endsWith(e)})},!(i="")===reactOptions.debugBabelPlugin&&(i=(0,generator_1.default)(e.node).code),a("@dynatrace")&&s("ConfigurationPreset.js")&&instrumentConfigurationPreset(e),a("react-native")&&s("AppRegistry.js","AppRegistryImpl.js")&&(reactOptions.autoStart&&instrumentAppRegistry(e),reactOptions.userInteraction)&&instrumentUserInteraction(e),a("react-native")&&s("ExceptionsManager.js")&&instrumentExceptionsManager(e),a("react-native-css-interop")&&s("jsx-runtime.js","jsx-dev-runtime.js")&&instrumentCssInterop(e),reactOptions.navigation.enabled&&a("@react-navigation")&&s("BaseNavigationContainer.js","BaseNavigationContainer.tsx")&&instrumentNavigation(e),a("react")&&s("index.js")&&instrumentReactCreateElement(e),null!=(n=null==(r=reactOptions.lifecycle)?void 0:r.instrument)&&n.call(r,c)&&(!c.includes("node_modules")||a("react-native")&&s("renderApplication.js"))&&hasJSX(e)&&instrumentLifecycle(e),null==(r=null==(n=reactOptions.input)?void 0:n.instrument)||!r.call(n,c)||c.includes("node_modules")&&!a("@react-navigation","react-native-drawer-layout")||instrumentInput(e),reactOptions.userInteraction&&!c.includes("node_modules")&&(instrumentJsxNames(e),instrumentComponentNames(e)),!0===reactOptions.debugBabelPlugin)&&(o=(0,generator_1.default)(e.node).code)!==i&&(s=fspath.join(PathsConstants_1.default.getBuildPath(),fspath.relative(PathsConstants_1.default.getApplicationPath(),c)+".dtx"),fs.mkdirSync(fspath.dirname(s),{recursive:!0}),fs.writeFileSync(s,o),t.set("fileDidChange",!0))}},post:function(e){var t;!0===reactOptions.debugBabelPlugin&&!0===this.get("fileDidChange")&&(t=(0,generator_1.default)(e.ast).code,e=fspath.join(PathsConstants_1.default.getBuildPath(),fspath.relative(PathsConstants_1.default.getApplicationPath(),e.opts.filename)+".dtx.downstream"),fs.mkdirSync(fspath.dirname(e),{recursive:!0}),fs.writeFileSync(e,t))}}};
|