fix(ios): Re-land SentrySDK.internal migration, bump Cocoa SDK to 9.24.0 - #6541
fix(ios): Re-land SentrySDK.internal migration, bump Cocoa SDK to 9.24.0#6541alwx wants to merge 4 commits into
Conversation
Semver Impact of This PR⚪ None (no version bump detected) 📋 Changelog PreviewThis is how your changes will appear in the changelog.
🤖 This preview updates automatically when you update the PR. |
Reapplies #6380 (reverted in 8.20.0 by #6491) now that the underlying sentry-cocoa bug is fixed. #6380 migrated the iOS code off the deprecated PrivateSentrySDKOnly SPI onto the SentrySDK.internal Swift API. It shipped in 8.19.0 and broke every iOS screenshot (Feedback Widget screenshot, attachScreenshot, Sentry.captureScreenshot) — #6497. Root cause was in sentry-cocoa: constructing SentryInternalApi eagerly reads SentryDependencyContainer.screenshotSource, a lazy var whose builder returns nil while startOptions is unset. Being lazy, that nil was cached for the process lifetime, and RN reads SentrySDK.internal before SentrySDK.start (from RNSentryStart, and from JS integrations calling fetchNativeAppStart / fetchNativeSdkInfo during init). getsentry/sentry-cocoa#8578 makes screenshotSource a computed property so the builder re-runs until startOptions is available; it shipped in 9.24.0, which this bumps to. Adds RNSentryScreenshotSourceTests as a regression guard: it reads SentrySDK.internal before starting the SDK and asserts screenshot capture still works. Verified to fail against 9.19.1 and pass against 9.24.0. RNSentry+fetchNativeStack.m was the last production file still reading options through the hand-rolled SentrySDKInternal redeclaration in RNSentry.h. It now goes through SentrySDKWrapper.debug like the rest of RNSentry.mm, and the redeclaration is gone. Re-landing also restores the two improvements the revert removed: the fetchViewHierarchy nil-guard (returns null instead of a zero-byte attachment on capture failure) and the RNSentryTimeToDisplay extern linkage. Fixes #6507.
|
|
||
| Re-lands [#6380](https://github.com/getsentry/sentry-react-native/pull/6380), which was reverted in 8.20.0 because it broke iOS screenshot capture ([#6497](https://github.com/getsentry/sentry-react-native/issues/6497)). The underlying sentry-cocoa bug is fixed in 9.24.0. | ||
|
|
||
| The `RNSentry` pod now contains Swift code. On React Native versions where RN pods are not modularized by default (e.g. RN 0.71), add `use_modular_headers!` to your `ios/Podfile`. |
There was a problem hiding this comment.
It would be nice to add a follow-up PR on Sentry Docs troubleshooting area, with the error users on old React Native will face with it and how to fix it.
lucas-zimerman
left a comment
There was a problem hiding this comment.
left some notes on the changelog file, overall the code looks good! lets do the final nits on the changelog.md and ship it!
📲 Install BuildsAndroid
|
Android (legacy) Performance metrics 🚀
|
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| bc0d8cf+dirty | 412.37 ms | 466.26 ms | 53.89 ms |
| c823bb5+dirty | 409.87 ms | 478.57 ms | 68.70 ms |
| 774257e+dirty | 407.09 ms | 447.46 ms | 40.37 ms |
| ae37560+dirty | 470.40 ms | 564.12 ms | 93.72 ms |
| a3265b6+dirty | 406.86 ms | 449.84 ms | 42.98 ms |
| 5125c43+dirty | 497.18 ms | 543.78 ms | 46.60 ms |
| 1e5d96d+dirty | 519.43 ms | 543.62 ms | 24.19 ms |
| 94af3bd+dirty | 503.48 ms | 542.37 ms | 38.89 ms |
| 3ce5254+dirty | 410.57 ms | 448.48 ms | 37.91 ms |
| 68672fc+dirty | 425.02 ms | 487.56 ms | 62.54 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| bc0d8cf+dirty | 48.30 MiB | 53.48 MiB | 5.18 MiB |
| c823bb5+dirty | 48.30 MiB | 53.58 MiB | 5.28 MiB |
| 774257e+dirty | 48.30 MiB | 53.58 MiB | 5.28 MiB |
| ae37560+dirty | 48.30 MiB | 53.60 MiB | 5.29 MiB |
| a3265b6+dirty | 48.30 MiB | 53.58 MiB | 5.28 MiB |
| 5125c43+dirty | 48.30 MiB | 53.54 MiB | 5.24 MiB |
| 1e5d96d+dirty | 49.74 MiB | 54.81 MiB | 5.07 MiB |
| 94af3bd+dirty | 48.30 MiB | 53.57 MiB | 5.26 MiB |
| 3ce5254+dirty | 43.75 MiB | 48.12 MiB | 4.37 MiB |
| 68672fc+dirty | 48.30 MiB | 53.61 MiB | 5.31 MiB |
Previous results on branch: alwx/fix/6507
Startup times
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| d119841+dirty | 463.53 ms | 497.50 ms | 33.97 ms |
| 415b9ce+dirty | 436.80 ms | 510.10 ms | 73.30 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| d119841+dirty | 49.74 MiB | 55.44 MiB | 5.70 MiB |
| 415b9ce+dirty | 49.74 MiB | 55.44 MiB | 5.70 MiB |
iOS (legacy) Performance metrics 🚀
|
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 21a1e70+dirty | 3834.15 ms | 1218.43 ms | -2615.73 ms |
| 882f8ae+dirty | 3840.30 ms | 1224.41 ms | -2615.88 ms |
| 15d4514+dirty | 3840.17 ms | 1225.79 ms | -2614.38 ms |
| 0b5a379+dirty | 3828.91 ms | 1214.12 ms | -2614.79 ms |
| f3215d3+dirty | 3842.73 ms | 1219.33 ms | -2623.40 ms |
| ab203f9+dirty | 3848.07 ms | 1219.71 ms | -2628.35 ms |
| 6177334+dirty | 3834.85 ms | 1217.58 ms | -2617.28 ms |
| 5257d80+dirty | 3854.39 ms | 1234.28 ms | -2620.11 ms |
| 9474ead+dirty | 3864.29 ms | 1223.55 ms | -2640.74 ms |
| 1122a96+dirty | 3823.10 ms | 1218.64 ms | -2604.46 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 21a1e70+dirty | 4.98 MiB | 6.46 MiB | 1.49 MiB |
| 882f8ae+dirty | 5.15 MiB | 6.70 MiB | 1.54 MiB |
| 15d4514+dirty | 5.15 MiB | 6.70 MiB | 1.55 MiB |
| 0b5a379+dirty | 5.15 MiB | 6.70 MiB | 1.54 MiB |
| f3215d3+dirty | 5.15 MiB | 6.67 MiB | 1.52 MiB |
| ab203f9+dirty | 4.98 MiB | 6.51 MiB | 1.53 MiB |
| 6177334+dirty | 5.15 MiB | 6.68 MiB | 1.53 MiB |
| 5257d80+dirty | 5.15 MiB | 6.69 MiB | 1.54 MiB |
| 9474ead+dirty | 5.15 MiB | 6.71 MiB | 1.55 MiB |
| 1122a96+dirty | 5.15 MiB | 6.68 MiB | 1.53 MiB |
iOS (new) Performance metrics 🚀
|
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 64630e5+dirty | 3845.49 ms | 1215.19 ms | -2630.30 ms |
| b0d3373+dirty | 3842.49 ms | 1218.49 ms | -2624.00 ms |
| b04af96+dirty | 3830.54 ms | 1206.11 ms | -2624.44 ms |
| f9c1ed4+dirty | 3842.09 ms | 1220.70 ms | -2621.40 ms |
| 09a902f+dirty | 3847.65 ms | 1221.31 ms | -2626.34 ms |
| 44abcc2+dirty | 3841.42 ms | 1214.77 ms | -2626.65 ms |
| acd838e+dirty | 3835.94 ms | 1215.87 ms | -2620.07 ms |
| bfba737+dirty | 3834.18 ms | 1222.80 ms | -2611.38 ms |
| ce7b368+dirty | 3851.41 ms | 1222.37 ms | -2629.04 ms |
| 4e0ba9c+dirty | 3856.39 ms | 1234.44 ms | -2621.95 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 64630e5+dirty | 4.98 MiB | 6.46 MiB | 1.49 MiB |
| b0d3373+dirty | 5.15 MiB | 6.68 MiB | 1.53 MiB |
| b04af96+dirty | 4.98 MiB | 6.54 MiB | 1.56 MiB |
| f9c1ed4+dirty | 4.98 MiB | 6.50 MiB | 1.53 MiB |
| 09a902f+dirty | 4.98 MiB | 6.46 MiB | 1.49 MiB |
| 44abcc2+dirty | 4.98 MiB | 6.55 MiB | 1.57 MiB |
| acd838e+dirty | 5.15 MiB | 6.70 MiB | 1.55 MiB |
| bfba737+dirty | 4.98 MiB | 6.51 MiB | 1.53 MiB |
| ce7b368+dirty | 4.98 MiB | 6.51 MiB | 1.53 MiB |
| 4e0ba9c+dirty | 5.15 MiB | 6.67 MiB | 1.51 MiB |
Previous results on branch: alwx/fix/6507
Startup times
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| d119841+dirty | 3847.66 ms | 1218.17 ms | -2629.49 ms |
| 415b9ce+dirty | 3839.34 ms | 1217.42 ms | -2621.92 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| d119841+dirty | 5.08 MiB | 6.72 MiB | 1.64 MiB |
| 415b9ce+dirty | 5.08 MiB | 6.72 MiB | 1.64 MiB |
Android (new) Performance metrics 🚀
|
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 244f6e8+dirty | 445.89 ms | 463.32 ms | 17.43 ms |
| c2e182c+dirty | 468.50 ms | 545.44 ms | 76.94 ms |
| 5fe1c6c+dirty | 365.84 ms | 408.62 ms | 42.78 ms |
| 3d377b5+dirty | 425.38 ms | 440.67 ms | 15.30 ms |
| 3a829f0+dirty | 410.78 ms | 454.22 ms | 43.44 ms |
| 9c84b9a+dirty | 429.26 ms | 448.90 ms | 19.64 ms |
| 40c9884+dirty | 453.76 ms | 478.98 ms | 25.22 ms |
| bc0d8cf+dirty | 407.66 ms | 461.35 ms | 53.69 ms |
| 7d6fd3a+dirty | 435.06 ms | 458.78 ms | 23.72 ms |
| 68672fc+dirty | 407.55 ms | 442.96 ms | 35.41 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| 244f6e8+dirty | 49.74 MiB | 55.38 MiB | 5.63 MiB |
| c2e182c+dirty | 49.74 MiB | 54.85 MiB | 5.11 MiB |
| 5fe1c6c+dirty | 43.94 MiB | 49.00 MiB | 5.06 MiB |
| 3d377b5+dirty | 43.94 MiB | 49.00 MiB | 5.06 MiB |
| 3a829f0+dirty | 48.30 MiB | 53.58 MiB | 5.28 MiB |
| 9c84b9a+dirty | 49.74 MiB | 55.36 MiB | 5.62 MiB |
| 40c9884+dirty | 49.74 MiB | 55.09 MiB | 5.34 MiB |
| bc0d8cf+dirty | 48.30 MiB | 53.48 MiB | 5.18 MiB |
| 7d6fd3a+dirty | 43.94 MiB | 49.00 MiB | 5.06 MiB |
| 68672fc+dirty | 48.30 MiB | 53.61 MiB | 5.31 MiB |
Previous results on branch: alwx/fix/6507
Startup times
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| d119841+dirty | 431.41 ms | 477.02 ms | 45.61 ms |
| 415b9ce+dirty | 428.77 ms | 475.12 ms | 46.35 ms |
App size
| Revision | Plain | With Sentry | Diff |
|---|---|---|---|
| d119841+dirty | 49.74 MiB | 55.44 MiB | 5.70 MiB |
| 415b9ce+dirty | 49.74 MiB | 55.44 MiB | 5.70 MiB |
lucas-zimerman
left a comment
There was a problem hiding this comment.
Lets fix this test before merging https://github.com/getsentry/sentry-react-native/actions/runs/30867551749/job/91862651186?pr=6541
The `sentry-consumption: cocoapods` sample build failed on this branch with "None of your spec sources contain a spec satisfying the dependency: Sentry (= 9.24.0)". sentry-cocoa deleted `Sentry.podspec` and removed the `cocoapods` craft publishing target in 9.20.0, so 9.19.1 is the last version ever pushed to the CocoaPods trunk (verified: trunk serves 9.19.1 but 404s on 9.24.0). That makes `SENTRY_USE_XCFRAMEWORK=0` -> `s.dependency 'Sentry', <version>` unresolvable for every version this SDK will ship from now on. A podspec cannot point `s.dependency` at a git source, so the fallback cannot be repaired. It stayed green on main only because main still pins 9.19.1. Replace the fallback with a raise explaining why it is gone and pointing at SENTRY_XCFRAMEWORK_CACHE_DIR for builds without GitHub Releases access, and drop the CI matrix entry that exercised it. Also apply review feedback on the changelog: move the entry to the top of Unreleased and turn the modular-headers note into a [!WARNING] callout so RN < 0.75 users see the required Podfile change immediately.
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 3e6eef7. Configure here.

📢 Type of change
📜 Description
Re-lands #6380 (the
PrivateSentrySDKOnly→SentrySDK.internalmigration), which shipped in 8.19.0 and was reverted in 8.20.0 by #6491, now that the underlying sentry-cocoa bug is fixed.Three parts:
scripts/update-cocoa.sh set-version 9.24.0).packages/core/iossince the revert were the two release commits.RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryScreenshotSourceTests.swift.Re-landing also restores the two improvements #6491 removed along with the migration: the
fetchViewHierarchynil-guard (returnsnullinstead of a zero-byte attachment when capture fails) and theRNSentryTimeToDisplayexternlinkage change.Important
This re-introduces the RN < 0.75 requirement from 8.19.0: on React Native versions where
React-hermes(or another RN pod) is not modularized by default (e.g. RN 0.71), users must adduse_modular_headers!to theirios/Podfile. CocoaPods refuses to integrate a Swift pod against non-modular ObjC dependencies, andRNSentryInternal.swiftmakesRNSentrya Swift pod. Called out in the CHANGELOG.💡 Motivation and Context
Fixes #6507.
#6380 broke all iOS screenshot capture — Feedback Widget screenshot,
attachScreenshot, andSentry.captureScreenshot()(#6497).Root cause was in sentry-cocoa, not in RN: constructing
SentryInternalApieagerly readsSentryDependencyContainer.screenshotSource, which was alazy varwhose builder returnsnilwhilestartOptionsis unset. Beinglazy, thatnilwas cached for the process lifetime. RN readsSentrySDK.internalbeforeSentrySDK.start— fromRNSentryStartitself, and from JS integrations calling native methods likefetchNativeAppStart/fetchNativeSdkInfoduring init — so the source was reliably poisoned. A targeted RN-side fix wasn't possible because JS controls the timing of those calls, hence the full revert.getsentry/sentry-cocoa#8578 makes
screenshotSourcea computed property sogetOptionalLazyVarre-runs the builder untilstartOptionsis available, and only then caches. It shipped in 9.24.0.I also confirmed:
SentrySDK.internalis a computed property that builds a freshSentryInternalApiper access, so the eager read inSentryInternalScreenshotApi.initis harmless oncescreenshotSourcerebuilds.viewHierarchyProvideris still alazy var, but its builder never touchesstartOptions, so it cannot be poisoned the same way.Sources/Swift/HybridSDK/between 9.19.1 and 9.24.0 — the only diffs are@_implementationOnly import→internal import. Every symbolRNSentryInternal.swiftbridges still exists with the same signature.enableReplayNetworkDetailsCapturingwas removed in 9.22.0 but RN never set it.💚 How did you test it?
New regression test (
RNSentryScreenshotSourceTests): readsSentrySDK.internalbeforeSentrySDK.start, then starts viaRNSentryStart.startwithattachScreenshotand assertsSentrySDK.internal.screenshot.capture()is non-nil. Verified it is not vacuous:XCTAssertNotNil failed— reproduces #6497Full native suite —
RNSentryCocoaTester, Release config, iPhone simulator, Xcode 26.1: 163 tests, 0 failures.Linters:
swiftlint --strictclean (13 files, 0 violations),clang-formatclean.No JS/TS source changed, so no api-report or JS test impact.
📝 Checklist
sendDefaultPIIis enabled.🔮 Next steps
Needs the
ready-to-mergelabel before merging so the native / E2E / sample-app workflows run — the iOSfeedbackE2E flow is what surfaced #6497 in the first place and should be confirmed green.Two pre-existing problems found while writing the regression test, both unrelated to this change and left for follow-up issues:
RNSentryStartTests.swiftandRNSentryStartFromFileTests.swiftare not in the Xcode test target. They were dropped fromproject.pbxprojaround the v7 merge (6ab6b160) and have not compiled or run since. They no longer build (Options.enableTracingwas removed in cocoa v9), and once that's fixed every test in them crashes — see below. I intentionally did not re-enable them here; that's why the new regression test lives in its own file.RNSentrySDK.startproceeds withoptions == nilwhensentry.options.jsonis absent or unparseable (packages/core/ios/RNSentrySDK.mL64-72). The@{}fallback also fails validation ("Invalid DSN URL") and returnsnil, but the code carries on intoupdateWithReactDefaults:/configureOptions(...)/startWithOptions:. Identical before and after refactor(ios): Migrate from PrivateSentrySDKOnly to SentrySDK.internal #6380 — bothPrivateSentrySDKOnly.optionsWithDictionary:didFailWithError:andSentrySDK.internal.options(fromDictionary:)funnel into the sameSentryOptionsInternal initWithDict:, which returnsnilon failure. From ObjC it silently no-ops; from Swift (options.dsn = …on an implicitly-unwrappedSentryOptions!) it segfaults.