@dynatrace/react-native-plugin 2.327.1 → 2.327.2
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 +18 -12
- package/android/build.gradle +1 -1
- package/files/plugin.gradle +1 -1
- package/instrumentation/libs/react-native/Touchables.js +9 -0
- package/ios/DynatraceRNBridge.mm +99 -8
- package/lib/next/appstart/AppStartObserver.js +11 -14
- package/package.json +1 -1
- package/react-native-dynatrace.podspec +1 -1
package/README.md
CHANGED
|
@@ -26,16 +26,16 @@ If you want to start using this plugin and are not a Dynatrace customer yet, hea
|
|
|
26
26
|
* Gradle version 7.0+ ([How to update?](#updating-to-gradle-7))
|
|
27
27
|
* Android Gradle plugin version 7.0+
|
|
28
28
|
* Java 11
|
|
29
|
-
* Kotlin 2.0.21
|
|
30
|
-
* Jetpack Compose 1.4 - 1.9 - see [Compose Compatibility Note](
|
|
29
|
+
* Kotlin 2.0.21 - see [Kotlin Compatibility Note](#kotlin-compatibility-note)
|
|
30
|
+
* Jetpack Compose 1.4 - 1.9 - see [Compose Compatibility Note](#compose-compatibility-note)
|
|
31
31
|
* For iOS users: Minimum iOS 12
|
|
32
32
|
* NodeJS 16.0.0+ since our dependencies require NodeJS 16.0.0
|
|
33
33
|
|
|
34
34
|
## Agent Versions
|
|
35
35
|
This agent versions are configured in this plugin:
|
|
36
36
|
|
|
37
|
-
* Android Agent: 8.327.
|
|
38
|
-
* iOS Agent: 8.327.
|
|
37
|
+
* Android Agent: 8.327.3.1006
|
|
38
|
+
* iOS Agent: 8.327.2.1022
|
|
39
39
|
|
|
40
40
|
## Quick Setup
|
|
41
41
|
|
|
@@ -89,8 +89,8 @@ This agent versions are configured in this plugin:
|
|
|
89
89
|
* [React Automatic Runtime](#react-automatic-runtime)
|
|
90
90
|
* [Using a second transformer besides the dynatrace transformer](#using-a-second-transformer-besides-the-dynatrace-transformer)
|
|
91
91
|
* [Upgrading project to Gradle 7](#updating-to-gradle-7)
|
|
92
|
-
* [Kotlin Compatibility Note](
|
|
93
|
-
* [Compose Compatibility Note](
|
|
92
|
+
* [Kotlin Compatibility Note](#kotlin-compatibility-note)
|
|
93
|
+
* [Compose Compatibility Note](#compose-compatibility-note)
|
|
94
94
|
* [Maven Central in top-level gradle file](#maven-central-in-top-level-gradle-file)
|
|
95
95
|
* [Configuration of standalone React Native project](#configuration-of-standalone-react-native-project)
|
|
96
96
|
* [Instrumentation Overhead](#instrumentation-overhead)
|
|
@@ -705,7 +705,7 @@ This example shows two *TouchableHighlight*, which will fire the *onPress()* fun
|
|
|
705
705
|
|
|
706
706
|
## New RUM experience preview
|
|
707
707
|
|
|
708
|
-
>
|
|
708
|
+
> **â ï¸ Preview Feature**: The New RUM Experience APIs are currently in preview and may be subject to changes. These APIs provide enhanced event tracking capabilities with the new Dynatrace RUM on Grail feature.
|
|
709
709
|
|
|
710
710
|
The New RUM Experience introduces a set of advanced APIs that allow you to send custom events, modify event data, track exceptions, monitor HTTP requests, and manage view contexts in your React Native application. These APIs provide more granular control over the data captured by Dynatrace and are designed for the next generation RUM capabilities.
|
|
711
711
|
|
|
@@ -960,7 +960,7 @@ pod 'react-native-dynatrace', :path => '../node_modules/@dynatrace/react-native-
|
|
|
960
960
|
5. Under Build Phases expand the Link Binary With Libraries header.
|
|
961
961
|
6. Scroll down and click + to add a library.
|
|
962
962
|
7. Find and add `libRNDynatrace.a` under the Workspace group.
|
|
963
|
-
8.
|
|
963
|
+
8. â+B
|
|
964
964
|
|
|
965
965
|
## Setup for tvOS
|
|
966
966
|
|
|
@@ -1583,7 +1583,7 @@ dependencies {
|
|
|
1583
1583
|
|
|
1584
1584
|
```
|
|
1585
1585
|
|
|
1586
|
-
##
|
|
1586
|
+
## Kotlin Compatibility Note
|
|
1587
1587
|
|
|
1588
1588
|
Our Android Agent currently requires **Kotlin 2.0.21**. However, it should be noted that using this version may cause compatibility issues with older versions of React Native and the corresponding `react-native-gradle-plugin` due to, for instance, differences in Kotlin metadata:
|
|
1589
1589
|
|
|
@@ -1595,7 +1595,7 @@ Kotlin embeds language-specific features that Java doesn't natively support (lik
|
|
|
1595
1595
|
|
|
1596
1596
|
In summary, ensure your build fulfills our Kotlin 2.0.21 requirement while simultaneously fulfilling the requirements of your React Native version and its `react-native-gradle-plugin`.
|
|
1597
1597
|
|
|
1598
|
-
##
|
|
1598
|
+
## Compose Compatibility Note
|
|
1599
1599
|
|
|
1600
1600
|
Our Android Agent currently supports **Jetpack Compose 1.4 - 1.9**. If you are using an incompatible version of Jetpack Compose, you may encounter the following error message during build:
|
|
1601
1601
|
|
|
@@ -1728,8 +1728,14 @@ If you are struggling with a problem, submit a support ticket to Dynatrace (supp
|
|
|
1728
1728
|
<br/><br/>
|
|
1729
1729
|
## Changelog
|
|
1730
1730
|
|
|
1731
|
+
2.327.2
|
|
1732
|
+
* Fixed iOS startup time calculation issues for React Native 0.72 and lower
|
|
1733
|
+
* Fixed static properties during auto instrumentation of Touchables
|
|
1734
|
+
* Updated Android (8.327.3.1006) & iOS Agent (8.327.2.1022)
|
|
1735
|
+
|
|
1736
|
+
|
|
1731
1737
|
2.327.1
|
|
1732
|
-
* Added [Compose Compatibility Note](
|
|
1738
|
+
* Added [Compose Compatibility Note](#compose-compatibility-note)
|
|
1733
1739
|
* Added [New RUM experience preview](#new-rum-experience-preview) documentation
|
|
1734
1740
|
* Fixed iOS crash reporting by delaying the crash by 200ms on iOS to give the Agent enough time to report it
|
|
1735
1741
|
* Updated Android (8.327.2.1004) & iOS Agent (8.327.1.1020)
|
|
@@ -2044,4 +2050,4 @@ If you are struggling with a problem, submit a support ticket to Dynatrace (supp
|
|
|
2044
2050
|
* Added auto instrumentation for React classes
|
|
2045
2051
|
|
|
2046
2052
|
0.168.0
|
|
2047
|
-
* Initial Beta Release
|
|
2053
|
+
* Initial Beta Release
|
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.327.
|
|
75
|
+
implementation 'com.dynatrace.agent:agent-android:8.327.3.1006'
|
|
76
76
|
implementation "com.facebook.react:react-native:${safeExtGet('reactNative', '+')}"
|
|
77
77
|
}
|
|
78
78
|
|
package/files/plugin.gradle
CHANGED
|
@@ -7,6 +7,15 @@ exports.Button = (0, withOnPressMonitoring_1.withOnPressMonitoring)(ReactNative.
|
|
|
7
7
|
exports.TouchableOpacity = (0, withOnPressMonitoring_1.withOnPressMonitoring)(ReactNative.TouchableOpacity, 'Touchable');
|
|
8
8
|
exports.TouchableHighlight = (0, withOnPressMonitoring_1.withOnPressMonitoring)(ReactNative.TouchableHighlight, 'Touchable');
|
|
9
9
|
exports.TouchableNativeFeedback = (0, withOnPressMonitoring_1.withOnPressMonitoring)(ReactNative.TouchableNativeFeedback, 'Touchable');
|
|
10
|
+
[
|
|
11
|
+
'Ripple',
|
|
12
|
+
'SelectableBackground',
|
|
13
|
+
'SelectableBackgroundBorderless',
|
|
14
|
+
'canUseNativeForeground',
|
|
15
|
+
].forEach((prop) => {
|
|
16
|
+
exports.TouchableNativeFeedback[prop] =
|
|
17
|
+
ReactNative.TouchableNativeFeedback[prop];
|
|
18
|
+
});
|
|
10
19
|
exports.TouchableWithoutFeedback = (0, withOnPressMonitoring_1.withOnPressMonitoring)(ReactNative.TouchableWithoutFeedback, 'Touchable');
|
|
11
20
|
exports.Text = (0, withOnPressMonitoring_1.withOnPressMonitoring)(ReactNative.Text, 'Text');
|
|
12
21
|
exports.Pressable = (0, withOnPressMonitoring_1.withOnPressMonitoring)(ReactNative.Pressable, 'Pressable');
|
package/ios/DynatraceRNBridge.mm
CHANGED
|
@@ -14,8 +14,10 @@
|
|
|
14
14
|
#import <React/RCTPerformanceLogger.h>
|
|
15
15
|
#import <React/RCTRootView.h>
|
|
16
16
|
#import <cxxreact/ReactMarker.h>
|
|
17
|
+
#import <cxxreact/ReactNativeVersion.h>
|
|
17
18
|
|
|
18
19
|
#include <chrono>
|
|
20
|
+
#include <type_traits>
|
|
19
21
|
|
|
20
22
|
@implementation DynatraceRNBridge
|
|
21
23
|
|
|
@@ -59,6 +61,16 @@ bool didEmit;
|
|
|
59
61
|
*/
|
|
60
62
|
int64_t contentAppeared;
|
|
61
63
|
|
|
64
|
+
/**
|
|
65
|
+
* When the JavaScript bundle started running
|
|
66
|
+
*/
|
|
67
|
+
int64_t runJSBundleStartTime;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* When the JavaScript bundle stopped running
|
|
71
|
+
*/
|
|
72
|
+
int64_t runJSBundleEndTime;
|
|
73
|
+
|
|
62
74
|
RCT_EXPORT_MODULE(DynatraceBridge);
|
|
63
75
|
|
|
64
76
|
- (instancetype) init
|
|
@@ -69,10 +81,51 @@ RCT_EXPORT_MODULE(DynatraceBridge);
|
|
|
69
81
|
hasListeners = NO;
|
|
70
82
|
didEmit = NO;
|
|
71
83
|
contentAppeared = -1;
|
|
84
|
+
runJSBundleStartTime = -1;
|
|
85
|
+
runJSBundleEndTime = -1;
|
|
86
|
+
registerLogTaggedMarkerCallbacks();
|
|
72
87
|
}
|
|
73
88
|
return self;
|
|
74
89
|
}
|
|
75
90
|
|
|
91
|
+
// We have to make sure facebook::react::ReactMarker::StartupLogger::getInstance().getRunJSBundleEndTime() is always available even for the RN < 72s cases.
|
|
92
|
+
// Relying on the if constexpr else does not work since namespaces get resolved before the if branch in the if constexpr gets discarded.
|
|
93
|
+
// SFINAE does not work for top level symbols in namespaces (because it actually is an error).
|
|
94
|
+
// We cannot use preprocessor directives since we don't have the React Native version as preprocessor macro.
|
|
95
|
+
// We cannot use C++ concepts since C++20 is not available.
|
|
96
|
+
// Thus we provide a fallback definition for StartupLogger.
|
|
97
|
+
// Calling the class methods without a definition cannot happen and won't result in a linker error since the if branch in the if constexpr does not get compiled.
|
|
98
|
+
namespace fallback {
|
|
99
|
+
class StartupLogger {
|
|
100
|
+
public:
|
|
101
|
+
static StartupLogger& getInstance();
|
|
102
|
+
double getRunJSBundleStartTime();
|
|
103
|
+
double getRunJSBundleEndTime();
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
namespace facebook::react::ReactMarker {
|
|
108
|
+
using namespace fallback;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
int64_t getRunJSBundleStartTime() {
|
|
112
|
+
if constexpr(facebook::react::ReactNativeVersion.Minor >= 72) {
|
|
113
|
+
auto time = facebook::react::ReactMarker::StartupLogger::getInstance().getRunJSBundleStartTime();
|
|
114
|
+
return std::isnan(time) ? -1 : time;
|
|
115
|
+
} else {
|
|
116
|
+
return runJSBundleStartTime;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
int64_t getRunJSBundleEndTime() {
|
|
121
|
+
if constexpr(facebook::react::ReactNativeVersion.Minor >= 72) {
|
|
122
|
+
auto time = facebook::react::ReactMarker::StartupLogger::getInstance().getRunJSBundleEndTime();
|
|
123
|
+
return std::isnan(time) ? -1 : time;
|
|
124
|
+
} else {
|
|
125
|
+
return runJSBundleEndTime;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
76
129
|
- (NSArray<NSString *> *)supportedEvents {
|
|
77
130
|
return @[EmitAppMeasurementsIdentifier];
|
|
78
131
|
}
|
|
@@ -83,21 +136,53 @@ int64_t GetTimestampUnix()
|
|
|
83
136
|
return millisecondsUTC;
|
|
84
137
|
}
|
|
85
138
|
|
|
139
|
+
/*
|
|
140
|
+
In RN < 72, logTaggedMarker and logTaggedMarkerBridgeless are lambdas. In RN >= 72, these symbols are functions.
|
|
141
|
+
Relying on an if constexpr else does not work since types get checked before one branch in an if constexpr else gets discarded.
|
|
142
|
+
We cannot use a fallback declaration since since the symbol is declared as a function in RN >=72.
|
|
143
|
+
We cannot use preprocessor directives since we don't have the React Native version as preprocessor macro.
|
|
144
|
+
We cannot use C++ concepts since C++20 is not available.
|
|
145
|
+
Thus we use SFINAE. This works since types only get checked after template resolution.
|
|
146
|
+
*/
|
|
147
|
+
template<typename T = void> std::enable_if_t<(facebook::react::ReactNativeVersion.Minor < 72), T> registerLogTaggedMarkerCallbacks() {
|
|
148
|
+
using namespace facebook::react::ReactMarker;
|
|
149
|
+
auto logTaggedMarkerCommon = [](const ReactMarkerId markerId, const char* tag, auto previousLogTaggedMarker) {
|
|
150
|
+
if (previousLogTaggedMarker) {
|
|
151
|
+
previousLogTaggedMarker(markerId, tag);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (markerId == RUN_JS_BUNDLE_START) {
|
|
155
|
+
runJSBundleStartTime = GetTimestampUnix();
|
|
156
|
+
} else if (markerId == RUN_JS_BUNDLE_STOP) {
|
|
157
|
+
runJSBundleEndTime = GetTimestampUnix();
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
auto previousLogTaggedMarker = logTaggedMarker;
|
|
162
|
+
logTaggedMarker = [=](const ReactMarkerId markerId, const char* tag) {
|
|
163
|
+
logTaggedMarkerCommon(markerId, tag, previousLogTaggedMarker);
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
auto previousLogTaggedMarkerBridgeless = logTaggedMarkerBridgeless;
|
|
167
|
+
logTaggedMarkerBridgeless = [=](const ReactMarkerId markerId, const char* tag) {
|
|
168
|
+
logTaggedMarkerCommon(markerId, tag, previousLogTaggedMarkerBridgeless);
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
template<typename T = void> std::enable_if_t<(facebook::react::ReactNativeVersion.Minor >= 72), T> registerLogTaggedMarkerCallbacks() {}
|
|
173
|
+
|
|
86
174
|
/**
|
|
87
175
|
* When bridge is starting we will add an observer for content did appear so we can emit our app start measurements
|
|
88
176
|
*/
|
|
89
177
|
- (void)setBridge:(RCTBridge *)bridge
|
|
90
178
|
{
|
|
91
179
|
[super setBridge:bridge];
|
|
92
|
-
[[NSNotificationCenter defaultCenter] addObserver:self
|
|
93
|
-
selector:@selector(contentAppeared)
|
|
94
|
-
name:RCTContentDidAppearNotification
|
|
95
|
-
object:nil];
|
|
180
|
+
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(contentAppeared) name:RCTContentDidAppearNotification object:nil];
|
|
96
181
|
}
|
|
97
182
|
|
|
98
183
|
- (BOOL)isReady
|
|
99
184
|
{
|
|
100
|
-
return contentAppeared != -1 &&
|
|
185
|
+
return contentAppeared != -1 && getRunJSBundleEndTime() != -1;
|
|
101
186
|
}
|
|
102
187
|
|
|
103
188
|
- (void) contentAppeared
|
|
@@ -116,8 +201,8 @@ int64_t GetTimestampUnix()
|
|
|
116
201
|
|
|
117
202
|
NSMutableDictionary<NSString*, NSNumber*> *appStartMeasurements = [[NSMutableDictionary alloc] init];
|
|
118
203
|
|
|
119
|
-
[appStartMeasurements setObject:[self correctionOfTimestamp:
|
|
120
|
-
[appStartMeasurements setObject:[self correctionOfTimestamp:
|
|
204
|
+
[appStartMeasurements setObject:[self correctionOfTimestamp:getRunJSBundleStartTime()] forKey:RunJSBundleStart];
|
|
205
|
+
[appStartMeasurements setObject:[self correctionOfTimestamp:getRunJSBundleEndTime()] forKey:RunJSBundleEnd];
|
|
121
206
|
[appStartMeasurements setObject:[NSNumber numberWithLongLong:contentAppeared] forKey:ContentAppeared];
|
|
122
207
|
|
|
123
208
|
if (hasListeners) {
|
|
@@ -128,7 +213,13 @@ int64_t GetTimestampUnix()
|
|
|
128
213
|
|
|
129
214
|
- (NSNumber* )correctionOfTimestamp:(int64_t) timestamp
|
|
130
215
|
{
|
|
131
|
-
|
|
216
|
+
if constexpr (facebook::react::ReactNativeVersion.Minor < 72) {
|
|
217
|
+
// In RN < 72, timestamps are unix timestamps
|
|
218
|
+
return [NSNumber numberWithLongLong:timestamp];
|
|
219
|
+
} else {
|
|
220
|
+
// IN RN >= 72, timestamps are relative to the system start, which is we we add the unix timestamp of the system start
|
|
221
|
+
return [NSNumber numberWithLongLong:timestamp + GetTimestampUnix() - (CACurrentMediaTime() * 1000)];
|
|
222
|
+
}
|
|
132
223
|
}
|
|
133
224
|
|
|
134
225
|
/**
|
|
@@ -15,20 +15,17 @@ class AppStartObserverImpl {
|
|
|
15
15
|
call() {
|
|
16
16
|
}
|
|
17
17
|
setupNativeEventEmitter() {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
30
|
-
});
|
|
31
|
-
}
|
|
18
|
+
const emitter = new react_native_1.NativeEventEmitter(DynatraceBridge_1.DynatraceNative);
|
|
19
|
+
emitter.addListener(this.EMIT_APP_START, (data) => {
|
|
20
|
+
this.logger.debug(`emitter(${JSON.stringify(data)}})`);
|
|
21
|
+
const appStartEvent = (0, EventCreator_1.createAppStartEvent)(data);
|
|
22
|
+
if (appStartEvent != null) {
|
|
23
|
+
EventPipeline_1.EventPipeline.insertEvent(Object.assign({}, appStartEvent));
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
this.logger.debug(`emitter(${JSON.stringify(data)}}): App Start event ignored!`);
|
|
27
|
+
}
|
|
28
|
+
});
|
|
32
29
|
}
|
|
33
30
|
}
|
|
34
31
|
exports.AppStartObserver = new AppStartObserverImpl();
|
package/package.json
CHANGED
|
@@ -111,7 +111,7 @@ Pod::Spec.new do |s|
|
|
|
111
111
|
#
|
|
112
112
|
|
|
113
113
|
s.dependency "React"
|
|
114
|
-
s.dependency 'Dynatrace', '~> 8.327.
|
|
114
|
+
s.dependency 'Dynatrace', '~> 8.327.2.1022'
|
|
115
115
|
|
|
116
116
|
# Allows for better compatibility for older and newer versions
|
|
117
117
|
if defined?(install_modules_dependencies)
|