diff --git a/CHANGELOG.md b/CHANGELOG.md index 090a346215..51cb9e25b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ - Add `textComponentNames` option to `annotateReactComponents` for custom text components ([#6169](https://github.com/getsentry/sentry-react-native/pull/6169)) - Expose `addConsoleInstrumentationFilter` from `@sentry/core` ([#6180](https://github.com/getsentry/sentry-react-native/pull/6180)) - Expose experimental `captureSurfaceViews` option for Android Session Replay ([#6175](https://github.com/getsentry/sentry-react-native/pull/6175)) +- Add OTA SDK version to native `sdk.packages` when JS bundle version differs from built-in version ([#6191](https://github.com/getsentry/sentry-react-native/pull/6191)) ### Fixes diff --git a/packages/core/android/src/main/java/io/sentry/react/RNSentryStart.java b/packages/core/android/src/main/java/io/sentry/react/RNSentryStart.java index cb4cae4309..4f792521ac 100644 --- a/packages/core/android/src/main/java/io/sentry/react/RNSentryStart.java +++ b/packages/core/android/src/main/java/io/sentry/react/RNSentryStart.java @@ -68,8 +68,10 @@ static void startWithOptions( @Nullable Activity currentActivity, @NotNull Sentry.OptionsConfiguration configuration, @NotNull ILogger logger) { + @Nullable + String jsSdkVersion = rnOptions.hasKey("sdkVersion") ? rnOptions.getString("sdkVersion") : null; Sentry.OptionsConfiguration defaults = - options -> updateWithReactDefaults(options, currentActivity); + options -> updateWithReactDefaults(options, currentActivity, jsSdkVersion); Sentry.OptionsConfiguration rnConfigurationOptions = options -> getSentryAndroidOptions(options, rnOptions, logger); RNSentryCompositeOptionsConfiguration compositeConfiguration = @@ -319,6 +321,13 @@ private static void configureAndroidProfiling( */ static void updateWithReactDefaults( @NotNull SentryAndroidOptions options, @Nullable Activity currentActivity) { + updateWithReactDefaults(options, currentActivity, null); + } + + static void updateWithReactDefaults( + @NotNull SentryAndroidOptions options, + @Nullable Activity currentActivity, + @Nullable String jsSdkVersion) { @Nullable SdkVersion sdkVersion = options.getSdkVersion(); if (sdkVersion == null) { sdkVersion = new SdkVersion(RNSentryVersion.ANDROID_SDK_NAME, BuildConfig.VERSION_NAME); @@ -328,6 +337,10 @@ static void updateWithReactDefaults( sdkVersion.addPackage( RNSentryVersion.REACT_NATIVE_SDK_PACKAGE_NAME, RNSentryVersion.REACT_NATIVE_SDK_PACKAGE_VERSION); + if (jsSdkVersion != null + && !jsSdkVersion.equals(RNSentryVersion.REACT_NATIVE_SDK_PACKAGE_VERSION)) { + sdkVersion.addPackage(RNSentryVersion.REACT_NATIVE_SDK_PACKAGE_NAME + ":ota", jsSdkVersion); + } options.setSentryClientName(sdkVersion.getName() + "/" + sdkVersion.getVersion()); options.setNativeSdkName(RNSentryVersion.NATIVE_SDK_NAME); diff --git a/packages/core/ios/RNSentryStart.m b/packages/core/ios/RNSentryStart.m index 6114f57f62..fa463f116e 100644 --- a/packages/core/ios/RNSentryStart.m +++ b/packages/core/ios/RNSentryStart.m @@ -16,16 +16,31 @@ + (void)startWithOptions:(NSDictionary *_Nonnull)javascriptOptions error:errorPointer]; [self updateWithReactDefaults:options]; [self updateWithReactFinals:options]; - [self startWithOptions:options]; + NSString *jsSdkVersion = nil; + id jsSdkVersionValue = javascriptOptions[@"sdkVersion"]; + if ([jsSdkVersionValue isKindOfClass:[NSString class]]) { + jsSdkVersion = jsSdkVersionValue; + } + [self startWithOptions:options jsSdkVersion:jsSdkVersion]; } + (void)startWithOptions:(SentryOptions *)options NS_SWIFT_NAME(start(options:)) +{ + [self startWithOptions:options jsSdkVersion:nil]; +} + ++ (void)startWithOptions:(SentryOptions *)options jsSdkVersion:(NSString *_Nullable)jsSdkVersion { NSString *sdkVersion = [PrivateSentrySDKOnly getSdkVersionString]; [PrivateSentrySDKOnly setSdkName:NATIVE_SDK_NAME andVersionString:sdkVersion]; [PrivateSentrySDKOnly addSdkPackage:REACT_NATIVE_SDK_PACKAGE_NAME version:REACT_NATIVE_SDK_PACKAGE_VERSION]; + if (jsSdkVersion != nil && ![jsSdkVersion isEqualToString:REACT_NATIVE_SDK_PACKAGE_VERSION]) { + NSString *otaPackageName = [REACT_NATIVE_SDK_PACKAGE_NAME stringByAppendingString:@":ota"]; + [PrivateSentrySDKOnly addSdkPackage:otaPackageName version:jsSdkVersion]; + } + [SentrySDK startWithOptions:options]; #if SENTRY_TARGET_REPLAY_SUPPORTED diff --git a/packages/core/src/js/wrapper.ts b/packages/core/src/js/wrapper.ts index c9d5236610..5117996a8f 100644 --- a/packages/core/src/js/wrapper.ts +++ b/packages/core/src/js/wrapper.ts @@ -35,6 +35,7 @@ import { isTurboModuleEnabled } from './utils/environment'; import { convertToNormalizedObject } from './utils/normalize'; import { ReactNativeLibraries } from './utils/rnlibraries'; import { base64StringFromByteArray } from './vendor'; +import { SDK_VERSION } from './version'; /** * Returns the RNSentry module. Dynamically resolves if NativeModule or TurboModule is used. @@ -60,6 +61,7 @@ export type NativeSdkOptions = Partial & { ignoreErrorsRegex?: string[] | undefined; } & { mobileReplayOptions: MobileReplayOptions | undefined; + sdkVersion?: string | undefined; profilingOptions?: ProfilingOptions | undefined; /** @deprecated Use `profilingOptions` instead. */ androidProfilingOptions?: ProfilingOptions | undefined; @@ -317,6 +319,8 @@ export const NATIVE: SentryNativeWrapper = { }; } + filteredOptions.sdkVersion = SDK_VERSION; + const nativeIsReady = await RNSentry.initNativeSdk(filteredOptions); this.nativeIsReady = nativeIsReady; diff --git a/packages/core/test/wrapper.test.ts b/packages/core/test/wrapper.test.ts index e7a3f164cd..a5d3b327fb 100644 --- a/packages/core/test/wrapper.test.ts +++ b/packages/core/test/wrapper.test.ts @@ -245,6 +245,23 @@ describe('Tests Native Wrapper', () => { expect(NATIVE.enableNative).toBe(true); }); + test('passes sdkVersion to native SDK', async () => { + await NATIVE.initNativeSdk({ + dsn: VALID_DSN, + enableNative: true, + autoInitializeNativeSdk: true, + devServerUrl: undefined, + defaultSidecarUrl: undefined, + mobileReplayOptions: undefined, + }); + + expect(RNSentry.initNativeSdk).toHaveBeenCalled(); + // @ts-expect-error mock value + const initParameter = RNSentry.initNativeSdk.mock.calls[0][0]; + expect(initParameter).toHaveProperty('sdkVersion'); + expect(typeof initParameter.sdkVersion).toBe('string'); + }); + test('passes attachAllThreads to native SDK', async () => { await NATIVE.initNativeSdk({ dsn: VALID_DSN,