@dynatrace/react-native-plugin 2.333.1 → 2.337.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 (50) hide show
  1. package/README.md +181 -232
  2. package/android/build.gradle +1 -1
  3. package/files/plugin-runtime.gradle +27 -13
  4. package/files/plugin.gradle +1 -1
  5. package/instrumentation/BabelPluginDynatrace.js +1 -0
  6. package/instrumentation/DynatraceInstrumentation.js +1 -1
  7. package/instrumentation/jsx/JsxRuntime.js +4 -4
  8. package/instrumentation/libs/UserInteraction.js +114 -0
  9. package/instrumentation/libs/community/Picker.js +1 -1
  10. package/instrumentation/libs/community/gesture-handler/Touchables.InstrInfo.js +2 -0
  11. package/instrumentation/libs/community/gesture-handler/Touchables.js +3 -1
  12. package/instrumentation/libs/community/gesture-handler/index.js +3 -1
  13. package/instrumentation/libs/react-navigation/ReactNavigation.js +9 -0
  14. package/instrumentation/libs/withOnPressMonitoring.js +65 -14
  15. package/lib/core/Dynatrace.js +3 -0
  16. package/lib/core/DynatraceBridge.js +5 -7
  17. package/lib/core/configuration/ActionNameOptions.js +2 -0
  18. package/lib/core/configuration/Configuration.js +5 -1
  19. package/lib/core/configuration/ConfigurationBuilder.js +11 -1
  20. package/lib/core/configuration/ConfigurationDefaults.js +3 -1
  21. package/lib/core/configuration/ConfigurationHandler.js +64 -0
  22. package/lib/core/configuration/ConfigurationPreset.js +6 -0
  23. package/lib/core/configuration/ManualStartupConfiguration.js +9 -1
  24. package/lib/dynatrace-reporter.js +0 -14
  25. package/lib/dynatrace-transformer.js +10 -13
  26. package/lib/features/ui-interaction/Config.js +8 -2
  27. package/lib/features/ui-interaction/Plugin.Fragment.Test.js +170 -0
  28. package/lib/features/ui-interaction/Plugin.js +226 -882
  29. package/lib/features/ui-interaction/Run.js +11 -7
  30. package/lib/features/ui-interaction/Runtime.js +258 -913
  31. package/lib/features/ui-interaction/TouchMetaResolver.js +492 -0
  32. package/lib/features/ui-interaction/Types.js +1 -62
  33. package/lib/next/Dynatrace.js +44 -0
  34. package/lib/next/configuration/INativeRuntimeConfiguration.js +9 -0
  35. package/lib/next/configuration/RuntimeConfigurationObserver.js +50 -6
  36. package/lib/next/events/EventPipeline.js +14 -6
  37. package/lib/next/events/HttpRequestEventData.js +26 -30
  38. package/lib/next/provider/TimestampProvider.js +20 -7
  39. package/lib/next/util/TraceContextUtils.js +108 -0
  40. package/package.json +8 -10
  41. package/react-native-dynatrace.podspec +1 -1
  42. package/scripts/Android.js +96 -66
  43. package/scripts/Config.js +11 -1
  44. package/scripts/Ios.js +288 -71
  45. package/scripts/PathsConstants.js +34 -20
  46. package/scripts/core/InstrumentCall.js +8 -3
  47. package/scripts/core/LineOffsetAnalyzeCall.js +9 -15
  48. package/scripts/util/SourceMapUtil.js +49 -11
  49. package/types.d.ts +178 -39
  50. package/scripts/util/ReactOptions.js +0 -21
package/README.md CHANGED
@@ -10,9 +10,10 @@ If you want to start using this plugin and are not a Dynatrace customer yet, hea
10
10
  * Web requests
11
11
  * Crashes
12
12
  * React-native Auto-instrumentation
13
- * User actions for onPress and onLongPress (Touchables, Buttons, Pickers, RefreshControl, Pressable)
13
+ * User actions for onPress and onLongPress (Touchables, Buttons, Pressable, Switch, RefreshControl, Picker)
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`
16
17
  * UI Interaction feature toggle via `react.userInteraction` (enable/disable user interaction capturing at runtime)
17
18
  * Manual instrumentation
18
19
  * Typescript bindings to add manual instrumentation
@@ -32,18 +33,18 @@ If you want to start using this plugin and are not a Dynatrace customer yet, hea
32
33
  * NodeJS 16.0.0+ since our dependencies require NodeJS 16.0.0
33
34
 
34
35
  ## Agent Versions
35
- This agent versions are configured in this plugin:
36
+ These agent versions are configured in this plugin:
36
37
 
37
- * Android Agent: 8.333.1.1006
38
- * iOS Agent: 8.333.1.1005
38
+ * Android Agent: 8.337.2.1010
39
+ * iOS Agent: 8.337.1.1003
39
40
 
40
41
  ## Quick Setup
41
42
 
42
43
  1. [Install plugin](#1-install-the-plugin)
43
- 2. [Register Dynatrace transformer and reporter](#2-register-the-dynatrace-transformer-and-reporter)
44
- 3. [Setup configuration](#3-setup-dynatraceconfigjs)
45
- 4. [Update Babel Configuration](#4-update-babel-configuration)
46
- 5. [Build and run your app](#4-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)
47
48
 
48
49
  ## Advanced topics
49
50
  * [Manual OneAgent Startup](#manual-oneagent-startup)
@@ -72,7 +73,6 @@ This agent versions are configured in this plugin:
72
73
  * [Send Exception Event](#send-exception-event)
73
74
  * [Send HTTP Request Event](#send-http-request-event)
74
75
  * [View Monitoring](#view-monitoring)
75
- * [User Interaction](#user-interaction-1)
76
76
  * [React Native Symbolication](#react-native-symbolication)
77
77
  * [NPX Commands](#npx-commands)
78
78
  * [npx instrumentDynatrace](#npx-instrumentdynatrace)
@@ -92,7 +92,9 @@ This agent versions are configured in this plugin:
92
92
  * [Bundle Name and Version](#bundle-name-and-version)
93
93
  * [Navigation](#navigation)
94
94
  * [Source Map](#source-map)
95
- * [User Interaction](#user-interaction-1)
95
+ * [User Interaction Configuration](#user-interaction-configuration)
96
+ * [Debugging our auto-instrumentation](#debugging-our-auto-instrumentation)
97
+ * [Using our legacy jscodeshift auto-instrumentation](#using-our-legacy-jscodeshift-auto-instrumentation)
96
98
  * [Android block](#android-block)
97
99
  * [iOS block](#ios-block)
98
100
  * [Lifecycle modes](#lifecycle)
@@ -125,9 +127,7 @@ This agent versions are configured in this plugin:
125
127
  > **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.
126
128
 
127
129
  ## 1. Install the plugin
128
- 1. Install the plugin by calling:
129
- - React Native v0.60 or newer : `npm install @dynatrace/react-native-plugin`
130
- - React Native v0.59.x : `react-native install @dynatrace/react-native-plugin`.
130
+ 1. Install the plugin by calling `npm install @dynatrace/react-native-plugin`
131
131
  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.
132
132
 
133
133
  ### Troubleshooting
@@ -135,81 +135,36 @@ This agent versions are configured in this plugin:
135
135
  - 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).
136
136
  - 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).
137
137
 
138
- ## 2. Register the Dynatrace transformer and reporter
138
+ ## 2. Setup dynatrace.config.js
139
139
 
140
- The transformer will add modifications to your code during build. The reporter will notify us if you clear the cache of the metro bundler.
141
-
142
- 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.
143
-
144
- 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.
145
-
146
- In your project's root directory, create or extend `metro.config.js` so that it contains the following configuration properties `transformer.babelTransformerPath` and `reporter`:
147
-
148
- #### For React Native v0.72.1 or newer
149
-
150
- ```js
151
- const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config');
152
- const defaultConfig = getDefaultConfig(__dirname);
153
-
154
- /**
155
- * Metro configuration
156
- * https://facebook.github.io/metro/docs/configuration
157
- *
158
- * @type {import('metro-config').MetroConfig}
159
- */
160
- const config = {
161
- transformer: {
162
- babelTransformerPath: require.resolve(
163
- '@dynatrace/react-native-plugin/lib/dynatrace-transformer',
164
- ),
165
- },
166
- reporter: require('@dynatrace/react-native-plugin/lib/dynatrace-reporter'),
167
- };
168
-
169
- module.exports = mergeConfig(defaultConfig, config);
170
- ```
171
-
172
- #### For Expo
140
+ > **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`.
173
141
 
174
- ```js
175
- const {getDefaultConfig} = require('expo/metro-config');
176
- const config = getDefaultConfig(__dirname);
142
+ 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.
177
143
 
178
- config.transformer.babelTransformerPath = require.resolve(
179
- '@dynatrace/react-native-plugin/lib/dynatrace-transformer',
180
- );
144
+ > **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.
181
145
 
182
- config.reporter = require('@dynatrace/react-native-plugin/lib/dynatrace-reporter');
146
+ For more details about the configuration, see [Advanced topics](#structure-of-the-dynatracejs-file).
183
147
 
184
- module.exports = config;
185
- ```
148
+ ## 3. Register our babel plugin in babel.config.js
186
149
 
187
- #### For React Native v0.59 or newer
150
+ Add the Dynatrace babel plugin to your `babel.config.js`:
188
151
 
189
152
  ```js
190
153
  module.exports = {
191
- transformer: {
192
- babelTransformerPath: require.resolve(
193
- '@dynatrace/react-native-plugin/lib/dynatrace-transformer'
194
- )
195
- },
196
- reporter: require('@dynatrace/react-native-plugin/lib/dynatrace-reporter'),
154
+ ...
155
+ plugins: [..., '@dynatrace/react-native-plugin/instrumentation/BabelPluginDynatrace'],
197
156
  };
198
157
  ```
199
158
 
200
- ## 3. Setup dynatrace.config.js
159
+ This plugin handles the auto-instrumentation of your React Native code at build time.
201
160
 
202
- > **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`.
161
+ > **Note**: We recently moved our auto-instrumentation from a custom Metro transformer to a babel plugin for much faster bundling, independence of Metro and correct sourcemaps. 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 Metro transformer and reporter. In short, no configuration change is needed. If you continue using the Dynatrace Metro transformer and reporter, we reroute the instrumentation logic to the babel plugin internally.
203
162
 
204
- 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.
163
+ > **Note**: Bypassing Metro by adding the Babel plugin directly allows for the use of alternative bundlers. However, please be aware that we only regularly test with the default Metro bundler; other bundlers are not explicitly supported or documented.
205
164
 
206
- > **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.
207
-
208
- For more details about the configuration, see [Advanced topics](#structure-of-the-dynatracejs-file).
165
+ ## 4. Register our jsx-runtime in babel.config.js
209
166
 
210
- ## 4. Update Babel Configuration
211
-
212
- Depending on your version of Metro or Expo (if used), your babel configuration `babel.config.js` will need to be updated.
167
+ 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`.
213
168
 
214
169
  The changes have to be done in the following cases:
215
170
 
@@ -303,7 +258,9 @@ configurationBuilder.withCrashReporting(true)
303
258
  .withLogLevel(LogLevel.Info)
304
259
  .withLifecycleUpdate(false)
305
260
  .withUserOptIn(false)
306
- .withActionNamePrivacy(false);
261
+ .withActionNamePrivacy(false)
262
+ .withActionNamePreference('any')
263
+ .withActionNameAlgorithm('depth-first');
307
264
 
308
265
  await Dynatrace.start(configurationBuilder.buildConfiguration());
309
266
  ```
@@ -320,7 +277,9 @@ await Dynatrace.start(configurationBuilder.buildConfiguration());
320
277
  |logLevel |LogLevel|LogLevel.Info|Allows you to choose between `LogLevel.Info` and `LogLevel.Debug`. Debug returns more logs. This is especially important when something is not functioning correctly.|
321
278
  |lifecycleUpdate |boolean |false |Decide if you want to see update cycles on lifecycle actions as well. This is per default false as it creates a lot more actions.|
322
279
  |userOptIn |boolean |false |Activates the privacy mode when set to `true`. User consent must be queried and set. The privacy settings for [data collection](#user-privacy-options) and [crash reporting](#crash-reporting) can be changed via OneAgent SDK for Mobile as described under Data privacy. The default value is `false`.|
323
- |actionNamePrivacy |boolean |false |Activates a privacy mode especially for Touchables and Buttons. Setting this option to true means that a name for the control will no longer be shown, e.g. "Touch on Button". When setting a dtActionName onto the component this setting will be ignored.
280
+ |actionNamePrivacy |boolean |false |Activates a privacy mode especially for `onPress`. Setting this option to true means that a name for the control will no longer be shown, e.g. "Touch on Button". When setting a dtActionName onto the component this setting will be ignored.
281
+ |actionNamePreference |string |'any' |Controls which type of child element is preferred when searching the component tree for the name of an `onPress` action. `'text'` prefers text and falls back to any match. `'icon'` prefers `ReactNative.Image` and custom Icons and falls back to any match. `'any'` accepts the first match regardless of type (text, image, or custom icon).
282
+ |actionNameAlgorithm |string |'depth-first' |Controls the traversal algorithm used when searching the component tree for the name of an `onPress` action. `'depth-first'` follows the first child branch fully before trying siblings. `'breadth-first'` visits all siblings at a level before going deeper, returning the shallowest match first.|
324
283
  |bundleName |string |undefined |Should be used only if you have a multiple bundle setup where you load several .bundle files within your React Native application. Enter the name of your bundle. This should be unique in comparison to your other bundle names. This will ensure that actions coming from different bundles will not interfere with each other.
325
284
 
326
285
  **Attention:**
@@ -699,7 +658,7 @@ myAction.leaveAction();
699
658
 
700
659
  With `sendBizEvent`, you can report business events. These events are standalone events, as OneAgent sends them detached from user actions or user sessions.
701
660
 
702
- For more information on business events, see [dynatrace documentation](https://www.dynatrace.com/support/help/how-to-use-dynatrace/business-analytics/ba-events-capturing#expand--example-configuration-files-for-rum--2).
661
+ For more information on business events, see [dynatrace documentation](https://docs.dynatrace.com/docs/observe/business-observability/explore-business-events).
703
662
 
704
663
  ```ts
705
664
  import { Dynatrace } from '@dynatrace/react-native-plugin';
@@ -1020,7 +979,53 @@ Dynatrace.startView("UserProfileDetailed");
1020
979
 
1021
980
  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.
1022
981
 
1023
- To enable this feature, see the [User Interaction configuration](#user-interaction-1) section.
982
+ The following is an example of how this feature can be configured in your `dynatrace.config.js` file. Note that this feature is disabled by default.
983
+
984
+ ```js
985
+ react: {
986
+ userInteraction: true
987
+ }
988
+ ```
989
+
990
+ When enabled, UI Interaction can be controlled by two layers:
991
+
992
+ 1. **Build/config layer (`dynatrace.config.js`)**
993
+ - `react.userInteraction: true|false` controls whether the UI Interaction instrumentation feature is applied.
994
+
995
+ 2. **Runtime remote layer (`RuntimeConfigurationObserver`)**
996
+ - Runtime emission checks the remote flag `touch_interaction_enabled`.
997
+ - If remote flag is present, it is used as the source of truth.
998
+ - If remote flag is temporarily unavailable, the plugin falls back to the last known good remote value.
999
+ - If no remote value was received yet, runtime defaults to enabled behavior.
1000
+
1001
+ #### Masking sensitive UI labels
1002
+
1003
+ UI Interaction also supports masking sensitive labels before events are sent.
1004
+
1005
+ Masking is applied when:
1006
+
1007
+ * the touched element or one of its parents is marked with `dtMask`
1008
+ * the runtime masking rules classify the detected text as sensitive
1009
+ * the runtime masking rules classify the element `testID` as sensitive
1010
+
1011
+ When masking is active:
1012
+
1013
+ * the interaction path and component information are still reported
1014
+ * the detected UI label is replaced with the configured replacement string (default: `***`)
1015
+ * `ui_element.name_origin` is reported as `masked`
1016
+
1017
+ Example using `dtMask`:
1018
+
1019
+ ```tsx
1020
+ <View dtMask>
1021
+ <Pressable onPress={onPress}>
1022
+ <Text>john.doe@example.com</Text>
1023
+ </Pressable>
1024
+ </View>
1025
+ ```
1026
+
1027
+ This allows you to preserve interaction analytics while avoiding exposure of sensitive text in the emitted UI Interaction event.
1028
+
1024
1029
 
1025
1030
  #### Produced data
1026
1031
 
@@ -1034,6 +1039,8 @@ Each captured interaction produces an event describing what the user touched and
1034
1039
 
1035
1040
  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.
1036
1041
 
1042
+ If masking is active for an interaction, the event still contains the same structural information, but the detected name is replaced and the name origin changes to `masked`.
1043
+
1037
1044
  #### Example event
1038
1045
 
1039
1046
  ```json
@@ -1071,13 +1078,6 @@ To generate a sourcemap:
1071
1078
  * Then run `npx react-native run-ios --mode Release`, or
1072
1079
  * Build for release in Xcode
1073
1080
 
1074
- #### Accounting for Auto-Instrumentation
1075
-
1076
- Since the plugin auto-instruments your code, sourcemap line numbers may be slightly offset. To ensure accurate symbolication:
1077
-
1078
- * **Android**: Automatic patching is **enabled by default** and patches sourcemaps automatically at the end of every release build (see [Source Map](#source-map) configuration)
1079
- * **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
1080
-
1081
1081
  #### Uploading Sourcemaps
1082
1082
 
1083
1083
  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).
@@ -1100,27 +1100,20 @@ npx instrumentDynatrace [optional: config=... gradle=... plist=...]
1100
1100
  * `plist=C:\MyReactIOSProject\projectName\info.plist`: Tell the script where your info.plist file is. The plist file is used for updating the configuration for the agent.
1101
1101
  * `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.
1102
1102
 
1103
- ### npx configDynatrace
1103
+ If `plist=...` is not provided, the plugin tries to resolve `Info.plist` automatically in this order:
1104
1104
 
1105
- ```
1106
- npx configDynatrace [optional: config=...]
1107
- ```
1108
-
1109
- * `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.
1105
+ 1. Resolve app name from Expo config files in the app root (`app.json`, `app.config.js`, `app.config.ts`) and check common iOS plist locations.
1106
+ 2. Fallback to scanning the `ios/` folder for `Info.plist`.
1110
1107
 
1111
- ## npx lineOffsetDynatrace
1108
+ For monorepos or multi-target iOS setups, automatic discovery can be ambiguous. In those cases, pass `plist=...` explicitly to select the exact file.
1112
1109
 
1113
- 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.
1114
-
1115
- 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.
1116
-
1117
- **Usage:**
1110
+ ### npx configDynatrace
1118
1111
 
1119
1112
  ```
1120
- npx lineOffsetDynatrace sourcemapPath=/path/to/your/sourcemap.map
1113
+ npx configDynatrace [optional: config=...]
1121
1114
  ```
1122
1115
 
1123
- * `sourcemapPath=/path/to/your/sourcemap.map`: **(Required)** The path to the sourcemap file that should be patched.
1116
+ * `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.
1124
1117
 
1125
1118
  ## Customizing paths for configuration
1126
1119
 
@@ -1149,6 +1142,32 @@ npx react-native run-android --port=2000
1149
1142
 
1150
1143
  > **Note:** that custom arguments must not be prefixed with -- !
1151
1144
 
1145
+ ### pnpm Monorepo Setup
1146
+
1147
+ In a pnpm monorepo where React Native apps share a single native project (e.g. `packages/shared/android` and `packages/shared/ios`), the native platform folders are not located inside each app directory. To use shared native projects, you must provide the paths explicitly via `config=`, `gradle=`, and `plist=` arguments.
1148
+
1149
+ Add a dedicated `instrument` script for each app in the **root** `package.json` of your monorepo:
1150
+
1151
+ ```json
1152
+ "scripts": {
1153
+ "instrument:my-app": "pnpm --filter my-app exec instrumentDynatrace config=$PWD/apps/my-app/dynatrace.config.js gradle=$PWD/packages/shared/android/build.gradle plist=$PWD/packages/shared/ios/MyApp/Info.plist",
1154
+ "instrument:another-app": "pnpm --filter another-app exec instrumentDynatrace config=$PWD/apps/another-app/dynatrace.config.js gradle=$PWD/packages/shared/android/build.gradle plist=$PWD/packages/shared/ios/AnotherApp/Info.plist"
1155
+ }
1156
+ ```
1157
+
1158
+ Then run the instrumentation for each app from the monorepo root:
1159
+
1160
+ ```
1161
+ pnpm instrument:my-app
1162
+ pnpm instrument:another-app
1163
+ ```
1164
+
1165
+ **Key points:**
1166
+ * `$PWD` expands to the monorepo root at the time the script runs, so all paths are absolute and unambiguous regardless of the calling directory.
1167
+ * `--filter <app-name>` scopes `pnpm exec` to the correct app workspace so `instrumentDynatrace` is resolved from that app's `node_modules`.
1168
+ * The `gradle=` argument accepts either a `build.gradle` / `build.gradle.kts` file path or a folder path. When a file is given, the plugin derives the `app/build.gradle(.kts)` path from the same directory automatically.
1169
+ * If your project uses Kotlin DSL, point `gradle=` to `build.gradle.kts` instead.
1170
+
1152
1171
  ## Manually adding iOS OneAgent to a project
1153
1172
 
1154
1173
  Adding the iOS agent manually depends on the availability of support for CocoaPods.
@@ -1180,9 +1199,6 @@ Before installing the plugin, add the following to your `package.json`:
1180
1199
 
1181
1200
  ```
1182
1201
  "overrides": {
1183
- "@react-native-picker/picker": {
1184
- "react-native": "<insert-version-here>"
1185
- },
1186
1202
  "@dynatrace/react-native-plugin": {
1187
1203
  "react-native": "<insert-version-here>"
1188
1204
  }
@@ -1193,9 +1209,6 @@ If you are using the following `"react-native": "npm:react-native-tvos@0.69.8-2"
1193
1209
 
1194
1210
  ```
1195
1211
  "overrides": {
1196
- "@react-native-picker/picker": {
1197
- "react-native": "0.69.8-2"
1198
- },
1199
1212
  "@dynatrace/react-native-plugin": {
1200
1213
  "react-native": "0.69.8-2"
1201
1214
  }
@@ -1259,6 +1272,8 @@ Here is a list of all the counterparts for the options that can be used with a m
1259
1272
  |lifecycleUpdate|false| - | - | lifecycle.includeUpdate |
1260
1273
  |userOptIn|false|userOptIn|DTXUserOptIn| - |
1261
1274
  |actionNamePrivacy|false|-|-|input.actionNamePrivacy
1275
+ |actionNamePreference|'any'|-|-|input.actionNamePreference
1276
+ |actionNameAlgorithm|'depth-first'|-|-|input.actionNameAlgorithm
1262
1277
  |bundleName|undefined|-|-|bundleName
1263
1278
 
1264
1279
  ### React block
@@ -1269,13 +1284,14 @@ The `react` configuration block contains all settings regarding the react instru
1269
1284
 
1270
1285
  ```js
1271
1286
  react : {
1272
-
1273
1287
  input : {
1274
1288
  instrument(filename) => {
1275
1289
  return true;
1276
1290
  },
1277
1291
 
1278
1292
  actionNamePrivacy: false,
1293
+ actionNamePreference: 'any',
1294
+ actionNameAlgorithm: 'depth-first',
1279
1295
  }
1280
1296
  }
1281
1297
  ```
@@ -1311,7 +1327,7 @@ react: {
1311
1327
  This activates the debug mode. You will get more console output during instrumentation and at runtime.
1312
1328
 
1313
1329
 
1314
- ### User Interaction
1330
+ #### User Interaction Configuration
1315
1331
 
1316
1332
  ```js
1317
1333
  react: {
@@ -1319,37 +1335,7 @@ react: {
1319
1335
  }
1320
1336
  ```
1321
1337
 
1322
- Enables or disables the UI interaction (user interaction) feature.
1323
- Set to false to disable capturing of user interactions (e.g., touch/click actions) produced by the React Native UI interaction instrumentation.
1324
-
1325
- #### What customers will observe after enabling UI Interaction
1326
-
1327
- After setting `react.userInteraction: true` and rebuilding with instrumentation, the expected flow is:
1328
-
1329
- 1. Build-time instrumentation wraps supported UI elements and app root entrypoints.
1330
- 2. At runtime, touch/press interactions are captured and converted into UI interaction events.
1331
- 3. Events are processed by the plugin event pipeline and sent to Dynatrace.
1332
- 4. In Dynatrace, customers can analyze captured user interactions (for example, touch-driven behavior and related UI element context).
1333
-
1334
- Notes:
1335
-
1336
- - No extra UI needs to be added in customer screens for standard automatic capture.
1337
- - If `react.debug` is enabled, additional debug output can appear during instrumentation/runtime.
1338
-
1339
- #### Runtime switching (config + remote configuration observer)
1340
-
1341
- UI Interaction can be controlled by two layers:
1342
-
1343
- 1. **Build/config layer (`dynatrace.config.js`)**
1344
- - `react.userInteraction: true|false` controls whether the UI Interaction instrumentation feature is applied.
1345
-
1346
- 2. **Runtime remote layer (`RuntimeConfigurationObserver`)**
1347
- - Runtime emission checks the remote flag `touch_interaction_enabled`.
1348
- - If remote flag is present, it is used as the source of truth.
1349
- - If remote flag is temporarily unavailable, the plugin falls back to the last known good remote value.
1350
- - If no remote value was received yet, runtime defaults to enabled behavior.
1351
-
1352
- In short: local config enables the feature path, while remote configuration can dynamically allow/deny event emission at runtime.
1338
+ Enables or disables the UI interaction (user interaction) feature. Set to `false` to disable capturing of user interactions (for example, touch/click actions) produced by the React Native UI interaction instrumentation. See the [User Interaction](#user-interaction) section for behavior, produced data, and runtime control details.
1353
1339
 
1354
1340
  #### Error Handler
1355
1341
 
@@ -1420,33 +1406,32 @@ react: {
1420
1406
  }
1421
1407
  ```
1422
1408
 
1423
- #### Source Map
1424
-
1425
- This feature is enabled by default and patches sourcemap files so that any modifications made through Dynatrace will result in correct line numbers. If this feature is not enabled, line numbers of symbolicated stacktraces in Dynatrace might not match with your original source.
1409
+ #### Debugging our auto-instrumentation
1426
1410
 
1427
- The following is an example of how this feature can be configured in your `dynatrace.config.js` file:
1411
+ You can see the changes our auto-instrumentation is making to your code with this flag:
1428
1412
 
1429
1413
  ```js
1430
1414
  react: {
1431
- sourceMap: {
1432
- enabled: true
1433
- }
1415
+ debugBabelPlugin: true
1434
1416
  }
1435
1417
  ```
1436
1418
 
1437
- > **Note:** This automatic patching only works for Android. For iOS, you need to manually call [lineOffsetDynatrace](#npx-lineoffsetdynatrace) after the creation of the sourcemap is finished or before uploading it to Dynatrace.
1419
+ 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.
1420
+
1421
+ > **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.
1422
+
1423
+ #### Using our legacy jscodeshift auto-instrumentation
1438
1424
 
1439
- The automatic patching for Android can be customized using the `androidSourcemapLocation` property to specify a custom path to your sourcemap file, resolving from the `android/` directory since that is where the automation gets executed:
1425
+ 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:
1440
1426
 
1441
1427
  ```js
1442
1428
  react: {
1443
- sourceMap: {
1444
- enabled: true,
1445
- androidSourcemapLocation: 'sourcemap.map'
1446
- }
1429
+ useLegacyJscodeshift: true
1447
1430
  }
1448
1431
  ```
1449
1432
 
1433
+ > **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.
1434
+
1450
1435
  ### Android block
1451
1436
 
1452
1437
  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:
@@ -1614,20 +1599,38 @@ ios: {
1614
1599
  * displayName: Use the displayName property to check if React views have a display name set
1615
1600
  * instrumentation string: Auto instrumentation or manual instrumentation is passing a string. This will be used if available.
1616
1601
  * class name: If the display name is not available, the class name is used by taking the property name from the constructor
1617
- * Touchables
1618
- * dtActionName: Use a custom property called dtActionName
1619
- * If [actionNamePrivacy](#plugin-startup) is activated anything below will not be detected
1620
- * accessibilityLabel property
1621
- * If both are not set, it will search for an inner text
1622
- * If it is an Image Button, it will search for a source
1623
- * Buttons
1602
+ * Touchables, Buttons, Pressable
1624
1603
  * dtActionName: Use a custom property called dtActionName
1625
- * If [actionNamePrivacy](#plugin-startup) is activated any below will not be detected
1626
- * Button title property
1604
+ * If [actionNamePrivacy](#plugin-startup) is activated anything below will not be detected
1605
+ * title property
1627
1606
  * accessibilityLabel property
1628
- * If it is an Image Button, it will search for a source
1629
- * If it finds nothing, it will search for an inner text
1630
- * Switch, RefreshControl or Picker
1607
+ * If none of the above exist, we recursively traverse `children` to find a name. We consider text, the source property of any `ReactNative.Image` and the name property of any functional component called `Icon`.
1608
+ * You can use `actionNamePreference` to specify which of these 3 you prefer. Consider the following example:
1609
+ ```tsx
1610
+ <TouchableOpacity onPress={onPress}>
1611
+ <View>
1612
+ <Image source={{ uri: 'https://reactnative.dev/img/tiny_logo.png' }} />
1613
+ <Text>Some Text</Text>
1614
+ </View>
1615
+ </TouchableOpacity>
1616
+ ```
1617
+ - `'text'`: Resulting name: `Some Text`. Prefers text and falls back to any match.
1618
+ - `'icon'`: Resulting name: `Image Button: https://reactnative.dev/img/tiny_logo.png`. Prefers `ReactNative.Image` and custom Icons and falls back to any match.
1619
+ - `'any'`: Resulting name: `Image Button: https://reactnative.dev/img/tiny_logo.png`. Accepts the first match regardless of type (text, image, or custom icon).
1620
+ * You can use `actionNameAlgorithm` to specify with what algorithm `children` are traversed recursively, which in turn decides which name will be found first and used. Consider the following example:
1621
+ ```tsx
1622
+ <TouchableOpacity onPress={onPress}>
1623
+ <View>
1624
+ <View>
1625
+ <Text>Deep Text</Text>
1626
+ </View>
1627
+ <Text>Shallow Text</Text>
1628
+ </View>
1629
+ </TouchableOpacity>
1630
+ ```
1631
+ - `'depth-first'`: Resulting name: `Deep Text`. Follows the first child branch fully before trying siblings.
1632
+ - `'breadth-first'`: Resulting name: `Shallow Text`. Visits all siblings at a level before going deeper, returning the shallowest match first.
1633
+ * Switch, RefreshControl, Picker
1631
1634
  * dtActionName: Use a custom property called dtActionName
1632
1635
  * accessibilityLabel property
1633
1636
 
@@ -1745,75 +1748,6 @@ module.exports = {
1745
1748
  };
1746
1749
  ```
1747
1750
 
1748
- ## Using a second transformer besides the dynatrace transformer
1749
-
1750
- 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.
1751
-
1752
- 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.
1753
-
1754
- #### dynatrace.config.js
1755
-
1756
- ```js
1757
- // The `...` only indicates that there are other values as well, but we've omitted them in this example.
1758
- module.exports = {
1759
- react : {
1760
- upstreamTransformer: require.resolve('react-native-svg-transformer/react-native'),
1761
- // ...
1762
- },
1763
- // ...
1764
- };
1765
- ```
1766
-
1767
- #### metro.config.js for React Native v0.72.1 or newer
1768
- ```js
1769
- const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config');
1770
- const defaultConfig = getDefaultConfig(__dirname);
1771
- const {assetExts, sourceExts} = defaultConfig.resolver;
1772
-
1773
- /**
1774
- * Metro configuration
1775
- * https://facebook.github.io/metro/docs/configuration
1776
- *
1777
- * @type {import('metro-config').MetroConfig}
1778
- */
1779
- const config = {
1780
- transformer: {
1781
- babelTransformerPath: require.resolve(
1782
- '@dynatrace/react-native-plugin/lib/dynatrace-transformer',
1783
- ),
1784
- },
1785
- reporter: require('@dynatrace/react-native-plugin/lib/dynatrace-reporter'),
1786
- resolver: {
1787
- assetExts: assetExts.filter((ext) => ext !== 'svg'),
1788
- sourceExts: [...sourceExts, 'cjs', 'svg'],
1789
- },
1790
- };
1791
-
1792
- module.exports = mergeConfig(defaultConfig, config);
1793
- ```
1794
-
1795
- #### metro.config.js for React Native v0.59 or newer
1796
-
1797
- ```js
1798
- const { getDefaultConfig } = require("metro-config");
1799
-
1800
- module.exports = (async () => {
1801
- const {
1802
- resolver: { sourceExts, assetExts }
1803
- } = await getDefaultConfig();
1804
- return {
1805
- transformer: {
1806
- babelTransformerPath: require.resolve('@dynatrace/react-native-plugin/lib/dynatrace-transformer')
1807
- },
1808
- reporter: require('@dynatrace/react-native-plugin/lib/dynatrace-reporter'),
1809
- resolver: {
1810
- assetExts: assetExts.filter((ext) => ext !== "svg"),
1811
- sourceExts: [...sourceExts, "cjs", "svg"]
1812
- }
1813
- };
1814
- })();
1815
- ```
1816
-
1817
1751
  ## Maven Central in top-level gradle file
1818
1752
 
1819
1753
  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.
@@ -2054,12 +1988,27 @@ If you are struggling with a problem, submit a support ticket to Dynatrace (supp
2054
1988
  <br/><br/>
2055
1989
  ## Changelog
2056
1990
 
2057
- Latest
1991
+ 2.337.1
1992
+ * Updated Android (8.337.2.1010) & iOS Agent (8.337.1.1003)
1993
+ * Fixed gradle path derivation for custom `--gradle` arguments: the plugin now correctly probes the filesystem to auto-detect `app/build.gradle(.kts)` with proper Kotlin DSL support, and validates that only `build.gradle` or `build.gradle.kts` files are accepted (not `settings.gradle`).
1994
+ * Enables [pnpm monorepo instrumentation](#pnpm-monorexpo-setup) by allowing explicit `config=`, `gradle=`, and `plist=` arguments in root `package.json` scripts, supporting shared native project layouts where `android/` and `ios/` are not co-located with each app.
1995
+ * Added [actionNamePreference](#plugin-startup) and [actionNameAlgorithm](#plugin-startup) configuration flags.
1996
+
1997
+ 2.335.1
1998
+ * Updated Android (8.335.1.1001) & iOS Agent (8.335.1.1009)
1999
+ * 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.
2000
+ * Updated Android Gradle plugin configuration for Gradle 9 compatibility in `plugin-runtime.gradle`.
2001
+ * Moved auto-instrumentation from jscodeshift to a Babel plugin, improvements include:
2002
+ * Significantly faster JS bundle builds
2003
+ * Sourcemaps now natively account for our auto-instrumentation - no patching needed
2004
+ * Added instrumentation for `BorderlessButton` and `BaseButton` from `react-native-gesture-handler`.
2005
+ * Improved iOS `Info.plist` auto-discovery for `npx instrumentDynatrace` by resolving names from `app.json`, `app.config.js`, and `app.config.ts`, plus `INFOPLIST_FILE` values from Xcode project settings.
2006
+ * Added safer fallback scanning for `Info.plist` in `ios/`, with explicit ambiguity errors for multi-target/monorepo layouts and guidance to pass `plist=...` when needed.
2058
2007
 
2059
2008
  2.333.1
2060
2009
  * Jetpack Compose support range extended to 1.4 - 1.10 see [Compose Compatibility Note](#compose-compatibility-note)
2061
2010
  * Updated Android (8.333.1.1006) & iOS Agent (8.333.1.1005)
2062
- * Added Configuration flag to enable/disable the [User Interaction feature](#user-interaction-1).
2011
+ * Added configuration flag to enable/disable the [User Interaction feature](#user-interaction-configuration).
2063
2012
  * Added [User Interaction feature](#user-interaction) to collect UI interaction data such as touches, providing insights into user behavior
2064
2013
 
2065
2014
  2.331.1
@@ -72,7 +72,7 @@ repositories {
72
72
  }
73
73
 
74
74
  dependencies {
75
- implementation 'com.dynatrace.agent:agent-android:8.333.1.1006'
75
+ implementation 'com.dynatrace.agent:agent-android:8.337.2.1010'
76
76
  implementation "com.facebook.react:react-native:${safeExtGet('reactNative', '+')}"
77
77
  }
78
78