refactor(ios): Migrate from PrivateSentrySDKOnly to SentrySDK.internal#6380
Conversation
Semver Impact of This PR⚪ None (no version bump detected) 📋 Changelog PreviewThis is how your changes will appear in the changelog.
Plus 8 more 🤖 This preview updates automatically when you update the PR. |
|
@cursor review |
b850f46 to
330236b
Compare
📲 Install BuildsAndroid
|
iOS (legacy) Performance metrics 🚀
|
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| d0e3b3e+dirty | 3854.77 ms | 1218.58 ms | -2636.19 ms |
| 5125c43+dirty | 3846.45 ms | 1221.12 ms | -2625.32 ms |
| 580fb5c+dirty | 3836.13 ms | 1218.72 ms | -2617.41 ms |
| 7887847+dirty | 3849.83 ms | 1227.35 ms | -2622.48 ms |
| a216cb9+dirty | 3839.33 ms | 1225.26 ms | -2614.07 ms |
| 40c9884+dirty | 3837.72 ms | 1226.61 ms | -2611.11 ms |
| a5d243c+dirty | 3842.35 ms | 1214.29 ms | -2628.06 ms |
| f170ec3+dirty | 3822.26 ms | 1218.33 ms | -2603.93 ms |
| 68672fc+dirty | 3841.58 ms | 1228.89 ms | -2612.69 ms |
| ae37560+dirty | 3832.10 ms | 1219.09 ms | -2613.02 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| d0e3b3e+dirty | 4.98 MiB | 6.51 MiB | 1.53 MiB |
| 5125c43+dirty | 5.15 MiB | 6.68 MiB | 1.53 MiB |
| 580fb5c+dirty | 4.98 MiB | 6.46 MiB | 1.48 MiB |
| 7887847+dirty | 4.98 MiB | 6.46 MiB | 1.48 MiB |
| a216cb9+dirty | 4.98 MiB | 6.51 MiB | 1.53 MiB |
| 40c9884+dirty | 4.98 MiB | 6.51 MiB | 1.53 MiB |
| a5d243c+dirty | 5.15 MiB | 6.68 MiB | 1.53 MiB |
| f170ec3+dirty | 5.15 MiB | 6.69 MiB | 1.53 MiB |
| 68672fc+dirty | 5.15 MiB | 6.71 MiB | 1.55 MiB |
| ae37560+dirty | 5.15 MiB | 6.70 MiB | 1.54 MiB |
iOS (new) Performance metrics 🚀
|
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 580fb5c+dirty | 3835.45 ms | 1218.61 ms | -2616.84 ms |
| d0e3b3e+dirty | 3846.64 ms | 1226.27 ms | -2620.38 ms |
| a216cb9+dirty | 3853.25 ms | 1224.77 ms | -2628.48 ms |
| 37a2091+dirty | 3865.27 ms | 1223.92 ms | -2641.35 ms |
| 40c9884+dirty | 3826.11 ms | 1217.04 ms | -2609.07 ms |
| 4e0ba9c+dirty | 3856.39 ms | 1234.44 ms | -2621.95 ms |
| 0b5a379+dirty | 3857.69 ms | 1230.34 ms | -2627.35 ms |
| 68672fc+dirty | 3832.22 ms | 1228.29 ms | -2603.93 ms |
| 2c735cc+dirty | 1223.33 ms | 1224.38 ms | 1.04 ms |
| 6acdf1d+dirty | 3835.35 ms | 1218.30 ms | -2617.06 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 580fb5c+dirty | 4.98 MiB | 6.46 MiB | 1.48 MiB |
| d0e3b3e+dirty | 4.98 MiB | 6.51 MiB | 1.53 MiB |
| a216cb9+dirty | 4.98 MiB | 6.51 MiB | 1.53 MiB |
| 37a2091+dirty | 5.15 MiB | 6.70 MiB | 1.54 MiB |
| 40c9884+dirty | 4.98 MiB | 6.51 MiB | 1.53 MiB |
| 4e0ba9c+dirty | 5.15 MiB | 6.67 MiB | 1.51 MiB |
| 0b5a379+dirty | 5.15 MiB | 6.70 MiB | 1.54 MiB |
| 68672fc+dirty | 5.15 MiB | 6.71 MiB | 1.55 MiB |
| 2c735cc+dirty | 3.38 MiB | 4.74 MiB | 1.35 MiB |
| 6acdf1d+dirty | 4.98 MiB | 6.51 MiB | 1.53 MiB |
antonis
left a comment
There was a problem hiding this comment.
Overall looks good. I think a conditional import like should fix the build issues 🤞
#if __has_include(<RNSentry/RNSentry-Swift.h>)
#import <RNSentry/RNSentry-Swift.h>
#else
#import "RNSentry-Swift.h"
#endif
Android (legacy) Performance metrics 🚀
|
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| f3215d3+dirty | 411.11 ms | 454.38 ms | 43.27 ms |
| d2eadf8+dirty | 414.64 ms | 454.56 ms | 39.92 ms |
| b0d3373+dirty | 557.66 ms | 579.42 ms | 21.76 ms |
| 27d9693+dirty | 419.08 ms | 469.12 ms | 50.04 ms |
| 4e0b819+dirty | 420.56 ms | 470.08 ms | 49.52 ms |
| 9474ead+dirty | 411.45 ms | 446.80 ms | 35.35 ms |
| 0bd8916+dirty | 412.77 ms | 451.31 ms | 38.54 ms |
| f9c1ed4+dirty | 431.00 ms | 466.22 ms | 35.22 ms |
| 3d536d1+dirty | 524.34 ms | 547.32 ms | 22.98 ms |
| 04207c4+dirty | 459.19 ms | 518.54 ms | 59.35 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| f3215d3+dirty | 48.30 MiB | 53.49 MiB | 5.19 MiB |
| d2eadf8+dirty | 48.30 MiB | 53.48 MiB | 5.18 MiB |
| b0d3373+dirty | 48.30 MiB | 53.58 MiB | 5.28 MiB |
| 27d9693+dirty | 49.74 MiB | 55.09 MiB | 5.34 MiB |
| 4e0b819+dirty | 49.74 MiB | 54.81 MiB | 5.07 MiB |
| 9474ead+dirty | 48.30 MiB | 53.61 MiB | 5.30 MiB |
| 0bd8916+dirty | 48.30 MiB | 53.57 MiB | 5.26 MiB |
| f9c1ed4+dirty | 49.74 MiB | 54.86 MiB | 5.12 MiB |
| 3d536d1+dirty | 49.74 MiB | 55.26 MiB | 5.52 MiB |
| 04207c4+dirty | 43.75 MiB | 48.12 MiB | 4.37 MiB |
Android (new) Performance metrics 🚀
|
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| a50b33d+dirty | 353.21 ms | 398.48 ms | 45.27 ms |
| d038a14+dirty | 405.08 ms | 444.36 ms | 39.28 ms |
| 68672fc+dirty | 407.55 ms | 442.96 ms | 35.41 ms |
| ad66da3+dirty | 411.49 ms | 449.38 ms | 37.89 ms |
| f170ec3+dirty | 505.96 ms | 551.88 ms | 45.92 ms |
| 27d9693+dirty | 438.63 ms | 514.08 ms | 75.46 ms |
| 41d6254+dirty | 406.20 ms | 445.52 ms | 39.32 ms |
| 68ae91b+dirty | 515.04 ms | 578.08 ms | 63.04 ms |
| 5ee78d6+dirty | 411.18 ms | 437.83 ms | 26.65 ms |
| ae37560+dirty | 428.96 ms | 456.86 ms | 27.90 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| a50b33d+dirty | 43.94 MiB | 48.94 MiB | 5.00 MiB |
| d038a14+dirty | 48.30 MiB | 53.49 MiB | 5.19 MiB |
| 68672fc+dirty | 48.30 MiB | 53.61 MiB | 5.31 MiB |
| ad66da3+dirty | 48.30 MiB | 53.49 MiB | 5.19 MiB |
| f170ec3+dirty | 48.30 MiB | 53.57 MiB | 5.26 MiB |
| 27d9693+dirty | 49.74 MiB | 55.09 MiB | 5.34 MiB |
| 41d6254+dirty | 48.30 MiB | 53.60 MiB | 5.30 MiB |
| 68ae91b+dirty | 49.74 MiB | 54.79 MiB | 5.05 MiB |
| 5ee78d6+dirty | 48.30 MiB | 53.58 MiB | 5.28 MiB |
| ae37560+dirty | 48.30 MiB | 53.60 MiB | 5.29 MiB |
b5e317f to
67f363b
Compare
67f363b to
23f1729
Compare
Antonis review nit: the use_modular_headers! requirement is a user-facing Podfile change on older RN versions, not internal-only — promote it from ### Internal into ### Changes alongside the visionOS setCurrentScreen note. Also reorder the Unreleased sections to the usual Features / Changes / Fixes / Internal layout used elsewhere in this file. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Two Lucas review nits: 1. `RNSentryInternal.currentScreenFrames` had a `nil`-returning stub in the non-UIKit `#else` branch that still referenced the `SentryScreenFrames` type in its return signature. sentry-cocoa doesn't compile `SentryScreenFrames` on macOS/watchOS, so the pod's Swift source failed to type-check there — CI reproduced with `cannot find type 'SentryScreenFrames' in scope`. Every ObjC caller is already gated to `TARGET_OS_IPHONE || TARGET_OS_MACCATALYST`, so we can just omit the property entirely on non-UIKit platforms. 2. CHANGELOG entries pointed to the issue (#6370) instead of the PR (#6380). Repo convention links the PR. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
f0f4bdf to
a3f38d4
Compare
Adding Swift to the RNSentry pod (via `RNSentryInternal.swift`) turned RNSentry into a Swift module. Swift's ObjC header import through modules doesn't inline `static const int` at use sites — it emits a reference to an external symbol. Because `static const int` at file scope has internal linkage, the symbol never exists at link time and RNSentryTimeToDisplayTests.swift fails to link: Undefined symbol: _TIME_TO_DISPLAY_ENTRIES_MAX_SIZE Change the header to `extern const int` and define the value in RNSentryTimeToDisplay.m so it gets a single exported symbol that both ObjC and Swift consumers can bind to. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
CI reported the iOS test bundle hung at ~14 min with \`IDETestOperationsObserverDebug: Failure collecting diagnostics from simulator: Timed out after 600.0 seconds\`. Calling \`SentrySDK.close()\` in tearDown races with sentry-cocoa's background workers (frame tracker CADisplayLink, session tracker, etc.), and the simulator process becomes unresponsive between tests. Match the lifecycle pattern from \`RNSentryStartTests\` — no explicit setUp/tearDown SDK management. Each test that needs a live SDK starts it via a helper; tests that only exercise stateless bridge methods (nil-guard, factory, mutation of process-global flags) don't touch lifecycle at all. Also drop \`testSetSdkNameAndAddPackageRoundTrip\` — it mutated process-global SDK metadata, which would leak across tests running after it in the same process. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The new smoke suite hung the iOS test bundle at test-run time on CI (`IDETestOperationsObserverDebug: Failure collecting diagnostics from simulator: Timed out after 600.0 seconds`), even after removing the `SentrySDK.close()` call. Best guess: the mutations of `framesTrackingHybridSDKMode` / `appStartMeasurementHybridSDKMode` leak into the shared XCTest process and trip up cocoa's UIApplication- observer path in a way we don't see on main. The bridge is already exercised end-to-end by `RNSentryStartTests` (which starts the SDK through `RNSentryStart.start`, i.e. the exact `RNSentryInternal.*` path) and `RNSentryReplayOptionsTests` (which calls `SentrySDK.internal.options(fromDictionary:)`), so we're not losing meaningful coverage by dropping the dedicated file. Revisit with a proper investigation instead of gambling more CI cycles. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…onOS
sentry-cocoa gates the new `SentryInternalScreen/Screenshot/ViewHierarchyApi`
sub-APIs to iOS/tvOS only. Straight-mapping the bridge to them left three
behaviour regressions on visionOS relative to pre-migration:
* `captureScreenshots` returned an empty array (no screenshots on
error events)
* `captureViewHierarchy` returned nil (no view-hierarchy attachments)
* `setCurrentScreen` was a no-op (no current-screen breadcrumb
enrichment)
The deprecated `PrivateSentrySDKOnly` still exposes those three APIs
under `SENTRY_HAS_UIKIT` (which does cover visionOS), so route the
visionOS bridge through it as a narrow, temporary fallback. Everywhere
else the migration still uses `SentrySDK.internal.*` — visionOS is the
only platform that keeps a `PrivateSentrySDKOnly` reference, and it
goes away as soon as sentry-cocoa either exposes these APIs on visionOS
in the hybrid surface or drops `PrivateSentrySDKOnly` in its next major.
With this fallback the PR becomes non-breaking on visionOS, so the
Changes-section note is no longer accurate — dropped from the CHANGELOG.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
@lucas-zimerman good catch. I've added a |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Want reviews to match your repository better? Bugbot Learning can learn team-specific rules from PR activity. A team admin can enable Learning in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit acf4112. Configure here.
|
@alwx tests seems to be failing but the same issues appear on main too. |
lucas-zimerman
left a comment
There was a problem hiding this comment.
Overall looks solid! we can patch here or on a follow-up PR the diffMax in order to match the changes.
|
@lucas-zimerman I think I will dedicate some time working on tests stability this week. |
| **Warning** | ||
|
|
||
| **This may be a breaking change for some setups.** `pod install` now downloads `Sentry.xcframework` from sentry-cocoa's GitHub release (SHA256-verified) and vendors it, instead of building Sentry from source as a CocoaPod. If your iOS build breaks after upgrading (e.g. when another pod also depends on the `Sentry` CocoaPod), or if your `pod install` environment cannot reach `github.com`, set `SENTRY_USE_XCFRAMEWORK=0` before `pod install` to restore the previous source-build behavior. | ||
| - **iOS:** On React Native versions where `React-hermes` (or another RN pod) is not modularized by default (e.g. RN 0.71), add `use_modular_headers!` to your `ios/Podfile` above the `target` block. This is required because the `RNSentry` pod now contains Swift code (the new `RNSentryInternal` bridge over `SentrySDK.internal`) and CocoaPods refuses to integrate a Swift pod against non-modular ObjC dependencies. Newer React Native versions require no change ([#6380](https://github.com/getsentry/sentry-react-native/pull/6380)). |
There was a problem hiding this comment.
@alwx Should we move this note to 8.19.0 and also add it in the release notes?
…nshot capture #6380 made RNSentryStart call SentrySDK.internal (optionsFromDictionary, sdkVersionString/setSdkName/addSdkPackage, appStart/framesTracking hybrid-mode setters) before SentrySDK.start. Constructing SentrySDK.internal eagerly reads SentryDependencyContainer.screenshotSource — a lazy var whose builder returns nil while startOptions is still nil — permanently caching nil and breaking all iOS screenshot capture (Feedback Widget screenshot, attachScreenshot, Sentry.captureScreenshot). Route those pre-start calls back through PrivateSentrySDKOnly, which does not touch screenshotSource, so options can be set before start without poisoning the lazy var. Post-start SentrySDK.internal usage is unchanged. Also reverts the earlier ineffective fix + diagnostics on this branch. See #6497. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…nternal (#6380)" This reverts #6380 (eae9020), restoring the pre-8.19.0 iOS native behavior. #6380 made RNSentry access SentrySDK.internal before SentrySDK.start (during init, from RNSentryStart and from JS integrations calling native methods like fetchNativeAppStart/fetchNativeSdkInfo). Constructing SentrySDK.internal eagerly reads SentryDependencyContainer.screenshotSource — a lazy var that returns and permanently caches nil while startOptions is unset — breaking all iOS screenshot capture (Feedback Widget screenshot, attachScreenshot, Sentry.captureScreenshot). A targeted RN-side revert is unreliable (any pre-start SentrySDK.internal access poisons the lazy var, and JS controls the timing), so revert the whole migration as the interim fix. The migration can be re-landed once the underlying sentry-cocoa issue is fixed (screenshotSource should not permanently cache nil). Fixes #6497. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…nternal (#6380)" (#6491) This reverts #6380 (eae9020), restoring the pre-8.19.0 iOS native behavior. #6380 made RNSentry access SentrySDK.internal before SentrySDK.start (during init, from RNSentryStart and from JS integrations calling native methods like fetchNativeAppStart/fetchNativeSdkInfo). Constructing SentrySDK.internal eagerly reads SentryDependencyContainer.screenshotSource — a lazy var that returns and permanently caches nil while startOptions is unset — breaking all iOS screenshot capture (Feedback Widget screenshot, attachScreenshot, Sentry.captureScreenshot). A targeted RN-side revert is unreliable (any pre-start SentrySDK.internal access poisons the lazy var, and JS controls the timing), so revert the whole migration as the interim fix. The migration can be re-landed once the underlying sentry-cocoa issue is fixed (screenshotSource should not permanently cache nil). Fixes #6497. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

📢 Type of change
📜 Description
Replace deprecated
PrivateSentrySDKOnlySPI andSentrySwizzle.hmacro usage in our iOS code with the newSentrySDK.internalSwift API exposed by sentry-cocoa 9.19.0, via a thin in-pod ObjC↔Swift bridge (RNSentryInternal.swift).The bridge uses
@_spi(Private) import Sentryto reach SPI-gated sub-APIs (performance.currentScreenFrames,replay.configure,envelope.{store,capture,deserialize}). Existing.m/.mmcallers route through[RNSentryInternal …]via the auto-generatedRNSentry-Swift.h. TheperformSelector:@selector(getReplayIntegration)workaround incaptureReplayWithReturnValueis gone —SentrySDK.internal.replay.capture()returnsBooldirectly.Notably, we do not use sentry-cocoa's new
SentryObjCumbrella module (which the issue suggested) — that module isn't shipped via theSentryCocoaPod in 9.19.0, only via SPM as a separate xcframework. The Swift bridge works equally on both consumption paths.💡 Motivation and Context
Closes #6370.
PrivateSentrySDKOnlyis deprecated in sentry-cocoa 9.19.0 and slated for removal in the next major. Migrating now avoids future churn and drops the private header search path /performSelector:reliance.💚 How did you test it?
yarn build,yarn test,yarn lint,yarn circularDepCheck— all greenxcodebuildfor theRNSentrypod target (iphonesimulator) — builds cleanxcodebuild testforRNSentryCocoaTester— 158/158 native Cocoa tests pass📝 Checklist
sendDefaultPIIis enabled🔮 Next steps