Skip to content

refactor(ios): Migrate from PrivateSentrySDKOnly to SentrySDK.internal#6380

Open
alwx wants to merge 17 commits into
mainfrom
alwx/refactor/migrate-private-sentry-sdk-only
Open

refactor(ios): Migrate from PrivateSentrySDKOnly to SentrySDK.internal#6380
alwx wants to merge 17 commits into
mainfrom
alwx/refactor/migrate-private-sentry-sdk-only

Conversation

@alwx

@alwx alwx commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

📢 Type of change

  • Refactoring

📜 Description

Replace deprecated PrivateSentrySDKOnly SPI and SentrySwizzle.h macro usage in our iOS code with the new SentrySDK.internal Swift API exposed by sentry-cocoa 9.19.0, via a thin in-pod ObjC↔Swift bridge (RNSentryInternal.swift).

The bridge uses @_spi(Private) import Sentry to reach SPI-gated sub-APIs (performance.currentScreenFrames, replay.configure, envelope.{store,capture,deserialize}). Existing .m/.mm callers route through [RNSentryInternal …] via the auto-generated RNSentry-Swift.h. The performSelector:@selector(getReplayIntegration) workaround in captureReplayWithReturnValue is gone — SentrySDK.internal.replay.capture() returns Bool directly.

Notably, we do not use sentry-cocoa's new SentryObjC umbrella module (which the issue suggested) — that module isn't shipped via the Sentry CocoaPod 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. PrivateSentrySDKOnly is 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 green
  • xcodebuild for the RNSentry pod target (iphonesimulator) — builds clean
  • xcodebuild test for RNSentryCocoaTester — 158/158 native Cocoa tests pass

📝 Checklist

  • I added tests to verify changes
  • No new PII added or SDK only sends newly added PII if sendDefaultPII is enabled
  • I updated the docs if needed.
  • I updated the wizard if needed.
  • All tests passing
  • No breaking changes

🔮 Next steps

@github-actions

github-actions Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Semver Impact of This PR

None (no version bump detected)

📋 Changelog Preview

This is how your changes will appear in the changelog.
Entries from this PR are highlighted with a left border (blockquote style).


  • refactor(ios): Migrate from PrivateSentrySDKOnly to SentrySDK.internal by alwx in #6380
  • chore(deps): bump github/codeql-action/autobuild from 4.36.2 to 4.36.3 by dependabot in #6401
  • chore(deps): bump getsentry/craft/.github/workflows/changelog-preview.yml from 2.26.13 to 2.26.14 by dependabot in #6400
  • chore(deps): bump getsentry/craft from 2.26.13 to 2.26.14 by dependabot in #6402
  • chore(deps): bump github/codeql-action/analyze from 4.36.2 to 4.36.3 by dependabot in #6403
  • docs: Warn about possible Android new architecture build failures by antonis in #6408

🤖 This preview updates automatically when you update the PR.

@alwx

alwx commented Jul 1, 2026

Copy link
Copy Markdown
Contributor Author

@cursor review

Comment thread packages/core/ios/RNSentryInternal.swift
alwx and others added 3 commits July 2, 2026 09:24
Replace the deprecated PrivateSentrySDKOnly SPI and SentrySwizzle.h macro
with the new SentrySDK.internal Swift API exposed by sentry-cocoa 9.19.0,
via a thin in-pod ObjC<->Swift bridge (RNSentryInternal.swift). Imports
Sentry with @_spi(Private) for SPI-gated sub-APIs (performance, replay,
envelope). Drops the performSelector workaround around getReplayIntegration
since SentrySDK.internal.replay.capture() returns Bool directly.

Closes #6370

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Move RNSentryStartTests, RNSentryStartFromFileTests, and RNSentryReplayOptionsTests
to SentrySDK.internal.{options, options(fromDictionary:), appStart.hybridSDKMode,
performance.framesTrackingHybridSDKMode}.

The ObjC RNSentryTests.m keeps PrivateSentrySDKOnly for now — the test target
is a separate consumer of the RNSentry static-lib pod and cannot see
RNSentry-Swift.h without modulemap surgery. Worth revisiting when sentry-cocoa
removes PrivateSentrySDKOnly in the next major.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
`SentryInternalSwizzleApi` in sentry-cocoa has no platform gating, and
`SENTRY_HAS_UIKIT` (which guards the `[RNSentryRNSScreen swizzleViewDidAppear]`
call in RNSentry.mm) covers visionOS. The Swift bridge was gated to
`iOS/tvOS/macCatalyst` only, silently no-oping the swizzle on visionOS
where the deprecated `SentrySwizzle` macro used to work.

Also documents why `setCurrentScreen` remains a visionOS no-op: sentry-cocoa's
`SentryInternalScreenApi` is intentionally gated to iOS/tvOS, so the new API
surface itself doesn't expose the setter on visionOS.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@alwx alwx force-pushed the alwx/refactor/migrate-private-sentry-sdk-only branch from b850f46 to 330236b Compare July 2, 2026 07:25
@alwx alwx marked this pull request as ready for review July 2, 2026 07:26
@antonis antonis added the ready-to-merge Triggers the full CI test suite label Jul 2, 2026
@sentry

sentry Bot commented Jul 2, 2026

Copy link
Copy Markdown

📲 Install Builds

Android

🔗 App Name App ID Version Configuration
Sentry RN io.sentry.reactnative.sample 8.17.2 (97) Release

⚙️ sentry-react-native Build Distribution Settings

@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

iOS (legacy) Performance metrics 🚀

  Plain With Sentry Diff
Startup time 3831.43 ms 1211.85 ms -2619.58 ms
Size 4.98 MiB 6.51 MiB 1.54 MiB

Baseline results on branch: main

Startup times

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

@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

iOS (new) Performance metrics 🚀

  Plain With Sentry Diff
Startup time 3832.67 ms 1213.43 ms -2619.24 ms
Size 4.98 MiB 6.51 MiB 1.54 MiB

Baseline results on branch: main

Startup times

Revision Plain With Sentry Diff
3b6e9f9+dirty 3822.77 ms 1208.00 ms -2614.77 ms
71abba0+dirty 3852.70 ms 1224.53 ms -2628.16 ms
7a89652+dirty 3827.11 ms 1211.49 ms -2615.62 ms
0b1b5e3+dirty 3820.72 ms 1207.94 ms -2612.78 ms
3ce5254+dirty 1217.70 ms 1224.69 ms 6.99 ms
5a23c47+dirty 3843.54 ms 1226.05 ms -2617.50 ms
44c8b3f+dirty 3849.24 ms 1209.94 ms -2639.31 ms
4953e94+dirty 1217.41 ms 1223.53 ms 6.12 ms
5789645+dirty 3841.36 ms 1214.81 ms -2626.55 ms
04207c4+dirty 1228.55 ms 1226.04 ms -2.51 ms

App size

Revision Plain With Sentry Diff
3b6e9f9+dirty 5.15 MiB 6.68 MiB 1.53 MiB
71abba0+dirty 5.15 MiB 6.67 MiB 1.52 MiB
7a89652+dirty 5.15 MiB 6.70 MiB 1.55 MiB
0b1b5e3+dirty 5.15 MiB 6.70 MiB 1.54 MiB
3ce5254+dirty 3.38 MiB 4.76 MiB 1.38 MiB
5a23c47+dirty 4.98 MiB 6.46 MiB 1.49 MiB
44c8b3f+dirty 5.15 MiB 6.66 MiB 1.51 MiB
4953e94+dirty 3.38 MiB 4.73 MiB 1.35 MiB
5789645+dirty 4.98 MiB 6.50 MiB 1.52 MiB
04207c4+dirty 3.38 MiB 4.76 MiB 1.38 MiB

@antonis antonis left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Comment thread packages/core/ios/RNSentryInternal.swift Outdated
`withUnsafePointer(to:)` only guarantees the pointer stays valid inside
the closure body. Capturing it in `keyPtr` and using it outside the
closure was undefined behaviour by contract (even though `static var`
storage happens to be stable in practice). Wrap the entire
`instanceMethod` call inside `withUnsafePointer` so the pointer is
always used within its documented lifetime; the `static var` backing
storage keeps the address itself stable across calls, so sentry-cocoa's
`oncePerClass` dedup keeps working.

Flagged by Cursor Bugbot.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Comment thread packages/core/ios/RNSentry.mm
alwx and others added 2 commits July 6, 2026 11:47
Handle both static-lib and framework-style Pod integrations by falling
back from `<RNSentry/RNSentry-Swift.h>` (frameworks path) to the local
`"RNSentry-Swift.h"` (static-lib path) via `__has_include`. Applied to
every `.m`/`.mm` in packages/core/ios that consumes the Swift bridge.

Suggested by @antonis.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@alwx alwx requested a review from antonis July 6, 2026 09:59
Two fixes flagged by Warden:

1. `RNSentryInternal.envelope(fromData:)` accepted a non-optional Swift
   `Data`. If the ObjC caller passed a nil `NSData*` (e.g. from a failed
   base64 decode of the envelope payload), the ObjC→Swift bridge would
   force-unwrap it and crash before the method body ran. Change the
   parameter to `Data?` with an internal `guard let` — matches the
   nil-tolerant behaviour of the deprecated
   `PrivateSentrySDKOnly.envelopeWithData:`.

2. Swift Cocoa tests accessed `SentrySDK.internal.*` with plain
   `import Sentry`. The `.internal` accessor is public today, but the
   sub-APIs the tests touch (`options`, `appStart`, `performance`) sit
   next to `@_spi(Private)`-gated siblings on the same struct. Add
   `@_spi(Private) import Sentry` to `RNSentryStartTests.swift`,
   `RNSentryStartFromFileTests.swift`, and `RNSentryReplayOptionsTests.swift`
   so they keep compiling if the surface is ever tightened.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Comment thread packages/core/ios/RNSentry.mm
alwx and others added 2 commits July 6, 2026 12:26
When `captureViewHierarchy` returned nil the ObjC code still constructed
an empty `NSMutableArray` and resolved with it. In JS, `[]` is truthy —
the caller would treat the failure as a successful (empty) attachment.
Bail out with `resolve(nil)` up front so the JS side sees the actual
failure signal.

Pre-existing since 2023; flagged by Seer while reviewing this PR.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Comment thread packages/core/ios/RNSentryInternal.swift
alwx and others added 2 commits July 6, 2026 14:16
Cover the bridge's own contract — nil-guard on `envelope(fromData:)`,
metadata accessors, options factory, hybrid-SDK-mode flags, and the
`swizzleRNSScreenViewDidAppear` early-return when RNSScreen is
unavailable. sentry-cocoa owns the underlying `SentrySDK.internal.*`
behaviour; we just assert the wrapper forwards correctly and honours
the documented nil / platform guards.

Registers the new file in the RNSentryCocoaTester project explicitly
(the target does not use file-system-synchronized groups yet).

Flagged by Warden.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adding Swift to the RNSentry pod means CocoaPods refuses to integrate it
against non-modular ObjC dependencies. On older React Native versions
(e.g. 0.71 with Hermes) the React-hermes pod does not define modules, so
`pod install` fails with:

  The Swift pod `RNSentry` depends upon `React-hermes`, which does not
  define modules.

Inject `use_modular_headers!` into the Podfile via the existing e2e patch
script, and document the same knob for downstream users in the CHANGELOG.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ 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 2cb3360. Configure here.

Comment thread dev-packages/e2e-tests/patch-scripts/rn.patch.podfile.js Outdated
Cherry-picked from #6410. Dependabot bumped `codeql-action/analyze` and
`codeql-action/autobuild` to v4.36.3 but left `init` on v4.36.2, so
`init` writes a config stamped 4.36.2 that `analyze` (4.36.3) rejects:

  Loaded a configuration file for version '4.36.2', but running version '4.36.3'

Pull this fix into the PR branch so CI stops failing while #6410 is
still open on main.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Comment thread packages/core/ios/RNSentryStart.m
Previous version unconditionally set `modularPatched = true` inside the
`use_modular_headers!` branch, so a Podfile without a
`prepare_react_native_project!` anchor would be reported as successfully
patched even though `content.replace` returned it unchanged.

Compare replace output against the input and log a warning instead when
the anchor is missing.

Flagged by Cursor Bugbot.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Comment thread packages/core/ios/RNSentryInternal.swift
The migration to `SentrySDK.internal.screen.setCurrent` drops the
current-screen breadcrumb enrichment on visionOS because sentry-cocoa's
new `SentryInternalScreenApi` is gated to iOS/tvOS only. Already
documented in a code comment; call it out for downstream users too.

Flagged by Seer.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Android (legacy) Performance metrics 🚀

  Plain With Sentry Diff
Startup time 424.23 ms 464.74 ms 40.51 ms
Size 49.74 MiB 55.09 MiB 5.34 MiB

Baseline results on branch: main

Startup times

Revision Plain With Sentry Diff
d2eadf8+dirty 414.64 ms 454.56 ms 39.92 ms
4966363+dirty 400.04 ms 431.08 ms 31.04 ms
0307fa4+dirty 454.16 ms 518.35 ms 64.18 ms
038a6d7+dirty 524.82 ms 531.92 ms 7.10 ms
4e0b819+dirty 420.56 ms 470.08 ms 49.52 ms
1a5721e+dirty 424.07 ms 482.32 ms 58.25 ms
a0d8cf8+dirty 411.71 ms 467.57 ms 55.87 ms
9474ead+dirty 411.45 ms 446.80 ms 35.35 ms
ad66da3+dirty 468.46 ms 533.56 ms 65.10 ms
0b1b5e3+dirty 416.42 ms 470.58 ms 54.16 ms

App size

Revision Plain With Sentry Diff
d2eadf8+dirty 48.30 MiB 53.48 MiB 5.18 MiB
4966363+dirty 48.30 MiB 53.54 MiB 5.24 MiB
0307fa4+dirty 49.74 MiB 54.81 MiB 5.07 MiB
038a6d7+dirty 48.30 MiB 53.60 MiB 5.30 MiB
4e0b819+dirty 49.74 MiB 54.81 MiB 5.07 MiB
1a5721e+dirty 49.74 MiB 55.09 MiB 5.34 MiB
a0d8cf8+dirty 48.30 MiB 53.49 MiB 5.19 MiB
9474ead+dirty 48.30 MiB 53.61 MiB 5.30 MiB
ad66da3+dirty 48.30 MiB 53.49 MiB 5.19 MiB
0b1b5e3+dirty 48.30 MiB 53.60 MiB 5.29 MiB

`RNSentryInternal` is a Swift type compiled into the `RNSentry` pod
module, not the `Sentry` module. Without `@_spi(Private) import RNSentry`
the test target cannot resolve `RNSentryInternal.*` and fails to build.

Flagged by Warden.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Android (new) Performance metrics 🚀

  Plain With Sentry Diff
Startup time 415.10 ms 449.00 ms 33.90 ms
Size 49.74 MiB 55.09 MiB 5.34 MiB

Baseline results on branch: main

Startup times

Revision Plain With Sentry Diff
5b7e8a7+dirty 601.58 ms 634.98 ms 33.40 ms
eb93136+dirty 500.37 ms 532.58 ms 32.21 ms
4e0b819+dirty 599.31 ms 654.31 ms 55.00 ms
1a5721e+dirty 433.44 ms 462.80 ms 29.36 ms
3b6e9f9+dirty 442.39 ms 486.44 ms 44.05 ms
c823bb5+dirty 468.26 ms 516.16 ms 47.90 ms
3817909+dirty 357.52 ms 391.52 ms 34.00 ms
ecf47a2+dirty 457.21 ms 498.10 ms 40.89 ms
88735e9+dirty 427.04 ms 487.37 ms 60.33 ms
bc0d8cf+dirty 407.66 ms 461.35 ms 53.69 ms

App size

Revision Plain With Sentry Diff
5b7e8a7+dirty 48.30 MiB 53.58 MiB 5.28 MiB
eb93136+dirty 48.30 MiB 53.58 MiB 5.28 MiB
4e0b819+dirty 49.74 MiB 54.81 MiB 5.07 MiB
1a5721e+dirty 49.74 MiB 55.09 MiB 5.34 MiB
3b6e9f9+dirty 48.30 MiB 53.54 MiB 5.23 MiB
c823bb5+dirty 48.30 MiB 53.58 MiB 5.28 MiB
3817909+dirty 43.94 MiB 48.94 MiB 5.00 MiB
ecf47a2+dirty 49.74 MiB 54.82 MiB 5.07 MiB
88735e9+dirty 49.74 MiB 54.82 MiB 5.07 MiB
bc0d8cf+dirty 48.30 MiB 53.48 MiB 5.18 MiB

Comment thread CHANGELOG.md
Comment on lines +42 to +43
## 8.16.0

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit changelog merge issue

Suggested change
## 8.16.0

Comment thread CHANGELOG.md

- Migrate iOS code from the deprecated `PrivateSentrySDKOnly` SPI (and `SentrySwizzle.h` macro) to the new `SentrySDK.internal` Swift API exposed by sentry-cocoa 9.19.0, via a thin in-pod ObjC↔Swift bridge ([#6370](https://github.com/getsentry/sentry-react-native/issues/6370))

Adding Swift to the `RNSentry` pod means CocoaPods needs modular headers for its ObjC dependencies. 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. Newer React Native versions require no change.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the use_modular_headers! in those cases is needed it is a breaking change for some users and we should communicate it on the changes and not the internal section

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-to-merge Triggers the full CI test suite

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Migrate from PrivateSentrySDKOnly to [SentryObjCSDK internal]

2 participants