diff --git a/benchmarks/ios/Podfile.lock b/benchmarks/ios/Podfile.lock index 9a32882d8..9b2b7e3fa 100644 --- a/benchmarks/ios/Podfile.lock +++ b/benchmarks/ios/Podfile.lock @@ -2155,7 +2155,7 @@ SPEC CHECKSUMS: KSCrash: 8c4464fd5da7de520f2ce4a00fdf63f169a80f18 OpenTelemetry-Swift-Api: 3be9043f6288eb4ac3cbe7548b5bd45fb4ed5849 OpenTelemetry-Swift-Sdk: d9fa7bc839350f5a81467a5e877f727a8a77712d - RCT-Folly: 36fe2295e44b10d831836cc0d1daec5f8abcf809 + RCT-Folly: e78785aa9ba2ed998ea4151e314036f6c49e6d82 RCTDeprecation: be794de7dc6ed8f9f7fbf525f86e7651b8b68746 RCTRequired: a83787b092ec554c2eb6019ff3f5b8d125472b3b RCTTypeSafety: 48ad3c858926b1c46f46a81a58822b476e178e2c diff --git a/example-new-architecture/App.tsx b/example-new-architecture/App.tsx index f753110f7..db326f6d4 100644 --- a/example-new-architecture/App.tsx +++ b/example-new-architecture/App.tsx @@ -92,6 +92,10 @@ import {APPLICATION_ID, CLIENT_TOKEN, ENVIRONMENT} from './ddCredentials'; const spanId = await DdTrace.startSpan('test span'); await DdTrace.finishSpan(spanId); + + setTimeout(async () => { + await DdRum.reportAppFullyDisplayed(); + }, 5000); })(); function AppWithProviders() { diff --git a/example-new-architecture/android/app/build.gradle b/example-new-architecture/android/app/build.gradle index 8026744eb..b0d2e4404 100644 --- a/example-new-architecture/android/app/build.gradle +++ b/example-new-architecture/android/app/build.gradle @@ -107,10 +107,13 @@ dependencies { } constraints { - implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.4.10") { + // Pinned to the project's own Kotlin version: these shims pull the real + // kotlin-stdlib up with them, and a stdlib newer than kotlinVersion above fails + // compilation with "incompatible version of Kotlin". + implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk7:$rootProject.ext.kotlinVersion") { because("kotlin-stdlib-jdk7 is now a part of kotlin-stdlib") } - implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.4.10") { + implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:$rootProject.ext.kotlinVersion") { because("kotlin-stdlib-jdk8 is now a part of kotlin-stdlib") } } diff --git a/example-new-architecture/ios/Podfile.lock b/example-new-architecture/ios/Podfile.lock index 30a7d8fa1..57727dd2d 100644 --- a/example-new-architecture/ios/Podfile.lock +++ b/example-new-architecture/ios/Podfile.lock @@ -1883,7 +1883,7 @@ SPEC CHECKSUMS: hermes-engine: 9e868dc7be781364296d6ee2f56d0c1a9ef0bb11 KSCrash: 8c4464fd5da7de520f2ce4a00fdf63f169a80f18 OpenTelemetry-Swift-Api: 3be9043f6288eb4ac3cbe7548b5bd45fb4ed5849 - RCT-Folly: 7b4f73a92ad9571b9dbdb05bb30fad927fa971e1 + RCT-Folly: ea9d9256ba7f9322ef911169a9f696e5857b9e17 RCTDeprecation: ebe712bb05077934b16c6bf25228bdec34b64f83 RCTRequired: ca91e5dd26b64f577b528044c962baf171c6b716 RCTTypeSafety: e7678bd60850ca5a41df9b8dc7154638cb66871f diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle index 9ce87aa35..069f9e86d 100644 --- a/example/android/app/build.gradle +++ b/example/android/app/build.gradle @@ -109,10 +109,13 @@ dependencies { } constraints { - implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.4.10") { + // Pinned to the project's own Kotlin version: these shims pull the real + // kotlin-stdlib up with them, and a stdlib newer than kotlinVersion above fails + // compilation with "incompatible version of Kotlin". + implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk7:$rootProject.ext.kotlinVersion") { because("kotlin-stdlib-jdk7 is now a part of kotlin-stdlib") } - implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.4.10") { + implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:$rootProject.ext.kotlinVersion") { because("kotlin-stdlib-jdk8 is now a part of kotlin-stdlib") } } diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index bba37d368..d7959a13f 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -1987,7 +1987,7 @@ SPEC CHECKSUMS: HMSegmentedControl: 34c1f54d822d8308e7b24f5d901ec674dfa31352 KSCrash: 8c4464fd5da7de520f2ce4a00fdf63f169a80f18 OpenTelemetry-Swift-Api: 3be9043f6288eb4ac3cbe7548b5bd45fb4ed5849 - RCT-Folly: 7b4f73a92ad9571b9dbdb05bb30fad927fa971e1 + RCT-Folly: ea9d9256ba7f9322ef911169a9f696e5857b9e17 RCTDeprecation: ebe712bb05077934b16c6bf25228bdec34b64f83 RCTRequired: ca91e5dd26b64f577b528044c962baf171c6b716 RCTTypeSafety: e7678bd60850ca5a41df9b8dc7154638cb66871f diff --git a/example/src/App.tsx b/example/src/App.tsx index dc2f6acb5..95546c6df 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -8,7 +8,7 @@ import TraceScreen from './screens/TraceScreen'; import style from './screens/styles'; import { navigationRef } from './NavigationRoot'; import { DdRumReactNavigationTracking, NavigationTrackingOptions, ParamsTrackingPredicate, ViewNamePredicate, ViewTrackingPredicate } from '@datadog/mobile-react-navigation'; -import { DatadogProvider, TrackingConsent, DdFlags, DdLogs, DdSdkReactNative } from '@datadog/mobile-react-native' +import { DdSdkReactNative, DatadogProvider, TrackingConsent, DdLogs, DdRum, DdFlags } from '@datadog/mobile-react-native' import { OpenFeatureProvider } from '@openfeature/react-sdk'; import { ImagePrivacyLevel, @@ -96,6 +96,10 @@ const handleDatadogInitialization = async () => { // ConfigurationWire, no network); the "Flags source" switch on the Home screen flips to // the online provider (CDN) at runtime. await setFlagsProvider('offline'); + + setTimeout(async () => { + await DdRum.reportAppFullyDisplayed(); + }, 5000); } export default function App() { diff --git a/example/src/ddUtils.tsx b/example/src/ddUtils.tsx index 4933cec10..d4acbe069 100644 --- a/example/src/ddUtils.tsx +++ b/example/src/ddUtils.tsx @@ -1,6 +1,7 @@ import { DatadogProviderConfiguration, DdLogs, + DdRum, DdSdkReactNative, CoreConfiguration, SdkVerbosity, @@ -87,6 +88,10 @@ export function initializeDatadog(trackingConsent: TrackingConsent) { DdLogs.info('The RN Sdk was properly initialized') DdSdkReactNative.setUserInfo({id: "1337", name: "Xavier", email: "xg@example.com", extraInfo: { type: "premium" } }) DdSdkReactNative.addAttributes({campaign: "ad-network"}) + + setTimeout(async () => { + await DdRum.reportAppFullyDisplayed(); + }, 5000); }); // Enable the Flags feature. diff --git a/packages/core/__mocks__/react-native.ts b/packages/core/__mocks__/react-native.ts index db10d7f31..18e9a7be1 100644 --- a/packages/core/__mocks__/react-native.ts +++ b/packages/core/__mocks__/react-native.ts @@ -148,6 +148,9 @@ actualRN.NativeModules.DdRum = { addViewLoadingTime: jest.fn().mockImplementation( () => new Promise(resolve => resolve()) ) as jest.MockedFunction, + reportAppFullyDisplayed: jest.fn().mockImplementation( + () => new Promise(resolve => resolve()) + ) as jest.MockedFunction, stopSession: jest.fn().mockImplementation( () => new Promise(resolve => resolve()) ) as jest.MockedFunction, diff --git a/packages/core/android/build.gradle b/packages/core/android/build.gradle index 46e6be6a8..b06243c57 100644 --- a/packages/core/android/build.gradle +++ b/packages/core/android/build.gradle @@ -213,7 +213,7 @@ dependencies { // This breaks builds if the React Native target is below 0.76.0. as it relies on Gradle 8.5.0. // To avoid this, we enforce 1.0.0-beta01 on RN < 0.76.0 if (reactNativeMinorVersion < 76) { - implementation("com.datadoghq:dd-sdk-android-rum:3.12.1") { + implementation("com.datadoghq:dd-sdk-android-rum:3.13.1") { exclude group: "androidx.metrics", module: "metrics-performance" } implementation "androidx.metrics:metrics-performance:1.0.0-beta01" @@ -233,14 +233,16 @@ dependencies { } } } else { - implementation "com.datadoghq:dd-sdk-android-rum:3.12.1" + implementation "com.datadoghq:dd-sdk-android-rum:3.13.1" } - implementation "com.datadoghq:dd-sdk-android-logs:3.12.1" - implementation "com.datadoghq:dd-sdk-android-trace:3.12.1" - implementation "com.datadoghq:dd-sdk-android-webview:3.12.1" - implementation "com.datadoghq:dd-sdk-android-ndk:3.12.1" - implementation "com.datadoghq:dd-sdk-android-flags:3.12.1" - implementation "com.datadoghq:dd-sdk-android-internal:3.12.1" + implementation "com.datadoghq:dd-sdk-android-logs:3.13.1" + implementation "com.datadoghq:dd-sdk-android-trace:3.13.1" + implementation "com.datadoghq:dd-sdk-android-webview:3.13.1" + implementation "com.datadoghq:dd-sdk-android-ndk:3.13.1" + implementation "com.datadoghq:dd-sdk-android-flags:3.13.1" + implementation "com.datadoghq:dd-sdk-android-internal:3.13.1" + // TO DO: update once dd-sdk-android includes the prelaunch module + implementation "com.datadoghq:dd-sdk-android-rum-prelaunch:3.14.0" implementation "com.google.code.gson:gson:2.11.0" testImplementation "org.junit.platform:junit-platform-launcher:1.6.2" testImplementation "org.junit.jupiter:junit-jupiter-api:5.6.2" diff --git a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdFlagsImplementation.kt b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdFlagsImplementation.kt index 7d8d4e3b4..1920af4b8 100644 --- a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdFlagsImplementation.kt +++ b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdFlagsImplementation.kt @@ -182,6 +182,8 @@ private fun buildEvaluationContext( return EvaluationContext(targetingKey, parsed) } +private const val SERIAL_ID_KEY = "serialId" + private fun convertUnparsedFlagToMap( flagKey: String, flag: UnparsedFlag, @@ -222,6 +224,8 @@ private fun convertUnparsedFlagToMap( "reason" to flag.reason, "doLog" to flag.doLog, "extraLogging" to flag.extraLogging.toMap(), + // Serialized as a String because the React Native bridge converts Long values to Double + SERIAL_ID_KEY to flag.serialId?.toString() ) } @@ -237,4 +241,7 @@ private fun convertMapToUnparsedFlag(map: Map): UnparsedFlag = (map["extraLogging"] as? Map)?.toJSONObject() ?: JSONObject() override val reason: String = map["reason"] as? String ?: "" + override val serialId: Long? = + (map[SERIAL_ID_KEY] as? String)?.toLongOrNull() + ?: (map[SERIAL_ID_KEY] as? Number)?.toLong() } diff --git a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdRumImplementation.kt b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdRumImplementation.kt index e090f5338..8a09527ec 100644 --- a/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdRumImplementation.kt +++ b/packages/core/android/src/main/kotlin/com/datadog/reactnative/DdRumImplementation.kt @@ -327,6 +327,16 @@ class DdRumImplementation internal constructor( promise.resolve(null) } + /** + * This method can be used to mark the moment in time when the UI of the app is considered fully displayed. + * The duration between the application launch and this moment of time will be shown as TTFD (time to full display) + * in the RUM session explorer. Only the first call to this method will have any effect for a given RUM session. + */ + fun reportAppFullyDisplayed(promise: Promise) { + datadog.getRumMonitor().reportAppFullyDisplayed() + promise.resolve(null) + } + /** * Stops the current RUM Session. */ diff --git a/packages/core/android/src/newarch/kotlin/com/datadog/reactnative/DdRum.kt b/packages/core/android/src/newarch/kotlin/com/datadog/reactnative/DdRum.kt index 72baeecdd..2d31c8c4b 100644 --- a/packages/core/android/src/newarch/kotlin/com/datadog/reactnative/DdRum.kt +++ b/packages/core/android/src/newarch/kotlin/com/datadog/reactnative/DdRum.kt @@ -276,6 +276,16 @@ class DdRum( implementation.addViewLoadingTime(overwrite, promise) } + /** + * This method can be used to mark the moment in time when the UI of the app is considered fully displayed. + * The duration between the application launch and this moment of time will be shown as TTFD (time to full display) + * in the RUM session explorer. Only the first call to this method will have any effect for a given RUM session. + */ + @ReactMethod + override fun reportAppFullyDisplayed(promise: Promise) { + implementation.reportAppFullyDisplayed(promise) + } + /** * Stops the current RUM Session. */ diff --git a/packages/core/android/src/oldarchCommon/kotlin/com/datadog/reactnative/DdRum.kt b/packages/core/android/src/oldarchCommon/kotlin/com/datadog/reactnative/DdRum.kt index 79f7ad06a..327538dbb 100644 --- a/packages/core/android/src/oldarchCommon/kotlin/com/datadog/reactnative/DdRum.kt +++ b/packages/core/android/src/oldarchCommon/kotlin/com/datadog/reactnative/DdRum.kt @@ -258,6 +258,16 @@ class DdRum( implementation.addViewLoadingTime(overwrite, promise) } + /** + * This method can be used to mark the moment in time when the UI of the app is considered fully displayed. + * The duration between the application launch and this moment of time will be shown as TTFD (time to full display) + * in the RUM session explorer. Only the first call to this method will have any effect for a given RUM session. + */ + @ReactMethod + fun reportAppFullyDisplayed(promise: Promise) { + implementation.reportAppFullyDisplayed(promise) + } + /** * Stops the current RUM Session. */ diff --git a/packages/core/android/src/test/kotlin/com/datadog/reactnative/DdRumTest.kt b/packages/core/android/src/test/kotlin/com/datadog/reactnative/DdRumTest.kt index b03c377d8..ac007343b 100644 --- a/packages/core/android/src/test/kotlin/com/datadog/reactnative/DdRumTest.kt +++ b/packages/core/android/src/test/kotlin/com/datadog/reactnative/DdRumTest.kt @@ -557,6 +557,15 @@ internal class DdRumTest { verify(mockRumMonitor).addViewLoadingTime(overwrite) } + @Test + fun `M call reportAppFullyDisplayed w reportAppFullyDisplayed()`() { + // When + testedDdRum.reportAppFullyDisplayed(mockPromise) + + // Then + verify(mockRumMonitor).reportAppFullyDisplayed() + } + @Test fun `M call stopSession W stopSession()`() { // When diff --git a/packages/core/android/src/test/kotlin/com/datadog/tools/unit/MockRumMonitor.kt b/packages/core/android/src/test/kotlin/com/datadog/tools/unit/MockRumMonitor.kt index df0e8b5ad..5b52a9733 100644 --- a/packages/core/android/src/test/kotlin/com/datadog/tools/unit/MockRumMonitor.kt +++ b/packages/core/android/src/test/kotlin/com/datadog/tools/unit/MockRumMonitor.kt @@ -63,6 +63,9 @@ class MockRumMonitor : RumMonitor { @ExperimentalRumApi override fun addViewLoadingTime(overwrite: Boolean) {} + @ExperimentalRumApi + override fun reportAppFullyDisplayed() {} + override fun getCurrentSessionId(callback: (String?) -> Unit) {} override fun addViewAttributes(attributes: Map) {} @@ -172,7 +175,4 @@ class MockRumMonitor : RumMonitor { failureReason: OperationFailureReason, attributes: Map ) {} - - @ExperimentalRumApi - override fun reportAppFullyDisplayed() {} } diff --git a/packages/core/ios/Sources/DdRum.mm b/packages/core/ios/Sources/DdRum.mm index 58c9938cf..72ecff9c6 100644 --- a/packages/core/ios/Sources/DdRum.mm +++ b/packages/core/ios/Sources/DdRum.mm @@ -145,7 +145,15 @@ @implementation DdRum [self addViewLoadingTime:overwrite resolve:resolve reject:reject]; } -RCT_REMAP_METHOD(stopSession, withResolve:(RCTPromiseResolveBlock)resolve +RCT_EXPORT_METHOD(reportAppFullyDisplayed: + (RCTPromiseResolveBlock)resolve + withRejecter:(RCTPromiseRejectBlock)reject) +{ + [self reportAppFullyDisplayed: resolve reject:reject]; +} + +RCT_EXPORT_METHOD(stopSession: + (RCTPromiseResolveBlock)resolve withRejecter:(RCTPromiseRejectBlock)reject) { [self stopSession:resolve reject:reject]; @@ -262,6 +270,10 @@ - (void)addViewLoadingTime:(BOOL)overwrite resolve:(RCTPromiseResolveBlock)resol [self.ddRumImplementation addViewLoadingTimeWithOverwrite:overwrite resolve:resolve reject:reject]; } +- (void)reportAppFullyDisplayed:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { + [self.ddRumImplementation reportAppFullyDisplayedWithResolve:resolve reject: reject]; +} + - (void)startAction:(NSString *)type name:(NSString *)name context:(NSDictionary *)context timestampMs:(double)timestampMs resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { [self.ddRumImplementation startActionWithType:type name:name context:context timestampMs:timestampMs resolve:resolve reject:reject]; } diff --git a/packages/core/ios/Sources/DdRumImplementation.swift b/packages/core/ios/Sources/DdRumImplementation.swift index fec42b407..f37b51eb6 100644 --- a/packages/core/ios/Sources/DdRumImplementation.swift +++ b/packages/core/ios/Sources/DdRumImplementation.swift @@ -262,6 +262,12 @@ public class DdRumImplementation: NSObject { resolve(nil) } + @objc + public func reportAppFullyDisplayed(resolve:RCTPromiseResolveBlock, reject:RCTPromiseRejectBlock) -> Void { + nativeRUM.reportAppFullyDisplayed() + resolve(nil) + } + @objc public func stopSession(resolve:RCTPromiseResolveBlock, reject:RCTPromiseRejectBlock) -> Void { nativeRUM.stopSession() diff --git a/packages/core/ios/Tests/DdRumTests.swift b/packages/core/ios/Tests/DdRumTests.swift index 0ede8766d..58f0a2d82 100644 --- a/packages/core/ios/Tests/DdRumTests.swift +++ b/packages/core/ios/Tests/DdRumTests.swift @@ -466,6 +466,14 @@ internal class DdRumTests: XCTestCase { XCTAssertEqual(mockNativeRUM.receivedAttributes.count, 0) } + func testReportAppFullyDisplayed() throws { + rum.reportAppFullyDisplayed(resolve: mockResolve, reject: mockReject) + + XCTAssertEqual(mockNativeRUM.calledMethods.count, 1) + XCTAssertEqual(mockNativeRUM.calledMethods.last, .reportAppFullyDisplayed()) + XCTAssertEqual(mockNativeRUM.receivedAttributes.count, 0) + } + func testStopSession() throws { rum.stopSession(resolve: mockResolve, reject: mockReject) diff --git a/packages/core/ios/Tests/MockRUMMonitor.swift b/packages/core/ios/Tests/MockRUMMonitor.swift index ce1d2c6cd..0b7fc02bc 100644 --- a/packages/core/ios/Tests/MockRUMMonitor.swift +++ b/packages/core/ios/Tests/MockRUMMonitor.swift @@ -10,10 +10,6 @@ @testable import DatadogSDKReactNative internal class MockRUMMonitor: RUMMonitorProtocol { - func reportAppFullyDisplayed() { - // not implemented - } - func currentSessionID(completion: @escaping (String?) -> Void) { // not implemented } @@ -69,6 +65,7 @@ internal class MockRUMMonitor: RUMMonitorProtocol { case addViewAttributes(_: Int? = nil) // We need an attribute for the case to be Equatable case removeViewAttributes(keys: [String]) case addViewLoadingTime(overwrite: Bool) + case reportAppFullyDisplayed(_: Int? = nil) // We need an attribute for the case to be Equatable case stopSession(_: Int? = nil) // We need an attribute for the case to be Equatable case addResourceMetrics(resourceKey: String, fetch: Interval, @@ -151,6 +148,9 @@ internal class MockRUMMonitor: RUMMonitorProtocol { func addViewLoadingTime(overwrite: Bool) { calledMethods.append(.addViewLoadingTime(overwrite: overwrite)) } + func reportAppFullyDisplayed() { + calledMethods.append(.reportAppFullyDisplayed()) + } func stopSession() { calledMethods.append(.stopSession()) } diff --git a/packages/core/jest/mock.js b/packages/core/jest/mock.js index aadc79d27..4d91a73c4 100644 --- a/packages/core/jest/mock.js +++ b/packages/core/jest/mock.js @@ -143,6 +143,9 @@ module.exports = { addViewLoadingTime: jest .fn() .mockImplementation(() => new Promise(resolve => resolve())), + reportAppFullyDisplayed: jest + .fn() + .mockImplementation(() => new Promise(resolve => resolve())), addFeatureFlagEvaluation: jest .fn() .mockImplementation(() => new Promise(resolve => resolve())), diff --git a/packages/core/src/rum/DdRum.ts b/packages/core/src/rum/DdRum.ts index 9a7f15dae..7a3aecb9c 100644 --- a/packages/core/src/rum/DdRum.ts +++ b/packages/core/src/rum/DdRum.ts @@ -427,6 +427,16 @@ class DdRumWrapper implements DdRumType { ); }; + reportAppFullyDisplayed = (): Promise => { + InternalLog.log( + 'Reporting App Fully Displayed (TTFD)', + SdkVerbosity.DEBUG + ); + return bufferVoidNativeCall(() => + this.nativeRum.reportAppFullyDisplayed() + ); + }; + stopSession = (): Promise => { InternalLog.log('Stopping RUM Session', SdkVerbosity.DEBUG); clearCachedSessionId(); diff --git a/packages/core/src/rum/__tests__/DdRum.test.ts b/packages/core/src/rum/__tests__/DdRum.test.ts index 7d0a3688b..20c319f94 100644 --- a/packages/core/src/rum/__tests__/DdRum.test.ts +++ b/packages/core/src/rum/__tests__/DdRum.test.ts @@ -1884,6 +1884,16 @@ describe('DdRum', () => { }); }); + describe('DdRum.reportAppFullyDisplayed', () => { + it('calls the native API', async () => { + await DdRum.reportAppFullyDisplayed(); + + expect( + NativeModules.DdRum.reportAppFullyDisplayed + ).toHaveBeenCalledTimes(1); + }); + }); + describe('PropagatorTypes', () => { it('matches with the native name of propagators', () => { /** diff --git a/packages/core/src/rum/types.ts b/packages/core/src/rum/types.ts index b879010f7..8b173376a 100644 --- a/packages/core/src/rum/types.ts +++ b/packages/core/src/rum/types.ts @@ -181,6 +181,13 @@ export type DdRumType = { */ addViewLoadingTime(overwrite: boolean): Promise; + /** + * This method can be used to mark the moment in time when the UI of the app is considered fully displayed. + * The duration between the application launch and this moment of time will be shown as TTFD (time to full display) + * in the RUM session explorer. Only the first call to this method will have any effect for a given RUM session. + */ + reportAppFullyDisplayed(): Promise; + /** * Stops the current RUM Session. */ diff --git a/packages/core/src/specs/NativeDdRum.ts b/packages/core/src/specs/NativeDdRum.ts index dbe417f44..00950807a 100644 --- a/packages/core/src/specs/NativeDdRum.ts +++ b/packages/core/src/specs/NativeDdRum.ts @@ -170,6 +170,13 @@ export interface Spec extends TurboModule { */ addViewLoadingTime(overwrite: boolean): Promise; + /** + * This method can be used to mark the moment in time when the UI of the app is considered fully displayed. + * The duration between the application launch and this moment of time will be shown as TTFD (time to full display) + * in the RUM session explorer. Only the first call to this method will have any effect for a given RUM session. + */ + reportAppFullyDisplayed(): Promise; + /** * Stops the current RUM Session. */ diff --git a/packages/react-native-session-replay/android/build.gradle b/packages/react-native-session-replay/android/build.gradle index cdd0506b2..50f0f59b8 100644 --- a/packages/react-native-session-replay/android/build.gradle +++ b/packages/react-native-session-replay/android/build.gradle @@ -188,7 +188,6 @@ repositories { mavenCentral() google() maven { url "https://jitpack.io" } - mavenLocal() if (reactNativeMajorVersion == 0 && reactNativeMinorVersion < 71) { def androidSourcesDir = file("$reactNativeRootDir/android") @@ -216,8 +215,8 @@ dependencies { api "com.facebook.react:react-android:$reactNativeVersion" } implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" - implementation "com.datadoghq:dd-sdk-android-session-replay:3.12.1" - implementation "com.datadoghq:dd-sdk-android-internal:3.12.1" + implementation "com.datadoghq:dd-sdk-android-session-replay:3.13.1" + implementation "com.datadoghq:dd-sdk-android-internal:3.13.1" implementation project(path: ':datadog_mobile-react-native') testImplementation "org.junit.platform:junit-platform-launcher:1.6.2"