Skip to content

ref: migrate Cocoa bindings from PrivateSentrySDKOnly to SentryObjCSDK.internal#5409

Open
jamescrosswell wants to merge 26 commits into
mainfrom
migrate-private-sentrysdk-only-5331
Open

ref: migrate Cocoa bindings from PrivateSentrySDKOnly to SentryObjCSDK.internal#5409
jamescrosswell wants to merge 26 commits into
mainfrom
migrate-private-sentrysdk-only-5331

Conversation

@jamescrosswell

@jamescrosswell jamescrosswell commented Jul 20, 2026

Copy link
Copy Markdown
Collaborator

Migrates the iOS / Mac Catalyst hybrid-SDK bindings off the deprecated PrivateSentrySDKOnly (static methods, slated for removal in the next sentry-cocoa major) to the structured SentryObjCSDK.internal API introduced in sentry-cocoa 9.19. main already pins sentry-cocoa 9.22.0, so no dependency bump is required.

Key incremental/separate commits, in case this helps for review purposes:

  • Phase 1 — regenerate bindings against the SentryObjC headers (build-sentry-cocoa.sh, generate-cocoa-bindings.ps1, patch-cocoa-bindings.cs, ApiDefinitions.cs). PrivateSentrySDKOnly kept in parallel - e532a2f
  • Phase 2 — migrate the 5 call sites and the SentryCocoaHybridSdk alias to the new instance-based API cada275
  • Phase 3 — remove PrivateSentrySDKOnly from the binding, patch/generate scripts, and props 55ff0b8

Note: We build from source now

  • The .NET-consumed surface is only 5 call sites, via the SentryCocoaHybridSdk MSBuild alias (SetSdkName, SetTrace, StartProfilerForTrace, CollectProfileBetween, IgnoreNextSignal). Every one has a direct equivalent within [SentryObjCSDK internal].
  • ⚠️ The published SentryObjC-Dynamic.xcframework is not usable as-is. It is fully self-contained (~4.4 MB/slice): it defines SentryHubInternal, SentryClientInternal, SentryObjCSDK and the SentrySwift classes, and links no external Sentry.framework. Bundling it alongside the Sentry.framework we already ship would put two full copies of the SDK in the app, with split runtime state — the managed bindings would talk to one instance and the new internal calls to another.
  • sentry-cocoa exposes a buildable SentryObjC Xcode scheme; it builds cleanly and ships the SentryObjCSDK / SentryObjCInternalApi public headers.
  • Building SentryObjC + SentryObjCCompat from source produces thin two frameworks (136 KB + 1.2 MB) that only define the new additive SentryObjC* wrapper types and import the real SDK classes (_SentryScope, _SentryBreadcrumb, _SentryUser, …) as undefined symbols resolved at load time from the existing Sentry.framework via @rpath. No duplication; the new API shares the same SDK instance as the current bindings.

Issues

Closes #5331

jamescrosswell and others added 2 commits July 20, 2026 16:16
…ternal

Opens the branch/PR for the phased migration off the deprecated
PrivateSentrySDKOnly hybrid API (#5331). Phases land as subsequent commits.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Phase 1 of migrating the Cocoa hybrid API off the deprecated
PrivateSentrySDKOnly to the structured SentryObjCSDK.internal API.

- build-sentry-cocoa.sh now also builds the SentryObjC and SentryObjCCompat
  schemes from source into thin xcframeworks (iOS, iOS-sim, Mac Catalyst).
  These dynamically link the existing Sentry.framework rather than embedding
  their own copy of the SDK, so they don't duplicate it - unlike the
  self-contained released SentryObjC-Dynamic.xcframework.
- generate-cocoa-bindings.ps1 feeds the SentryObjC entry-point, internal-API,
  and id headers to Objective Sharpie.
- patch-cocoa-bindings.cs keeps the new interfaces and trims SentryObjCSDK to
  its `internal` accessor and SentryObjCInternalApi to the members the .NET
  wrappers use (sdk, profiling, setTrace, ignoreNextSignal).
- Sentry.Bindings.Cocoa.csproj bundles the two new frameworks via NativeReference.

PrivateSentrySDKOnly is kept in parallel; call sites migrate in phase 2.

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

codecov Bot commented Jul 20, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 74.58%. Comparing base (65c0c59) to head (1163b23).

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #5409   +/-   ##
=======================================
  Coverage   74.58%   74.58%           
=======================================
  Files         512      512           
  Lines       18666    18666           
  Branches     3659     3659           
=======================================
  Hits        13922    13922           
  Misses       3869     3869           
  Partials      875      875           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

jamescrosswell and others added 4 commits July 20, 2026 17:07
Phase 2: repoint the SentryCocoaHybridSdk alias from PrivateSentrySDKOnly to
SentryObjCSDK and move the five call sites onto the new instance-based API:

- SetSdkName        -> Internal.Sdk.Name =
- SetTrace          -> Internal.SetTrace (using the new SentryObjCId / SentryObjCSpanId)
- StartProfilerForTrace -> Internal.Profiling.StartFor
- CollectProfileBetween -> Internal.Profiling.CollectBetweenStartTime
- IgnoreNextSignal  -> Internal.IgnoreNextSignal

MiscExtensions gains ToCocoaObjCId / ToCocoaObjCSpanId for the new id types and
drops the now-unused ToCocoaSentryId / ToCocoaSpanId.

Sentry builds for net10.0-ios26 and net10.0-maccatalyst26 with no warnings.
PrivateSentrySDKOnly is still bound (removed in phase 3).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The 10.0.302 workload ships the iOS SDK pack 26.5.10301, which requires
Xcode 26.6. CI was pinning Xcode 26.5, causing iOS/MacCatalyst builds and
device tests to fail. The macos-26 runner already used by these jobs has
Xcode 26.6 available, so switch the pin to it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Dependabot bumped only codeql-action/init to 4.37.1, leaving analyze on
4.37.0. CodeQL requires all steps use the same version, so analyze failed
with "Loaded a configuration file for version '4.37.1', but running
version '4.37.0'". Pin analyze to the same v4.37.1 SHA.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@jamescrosswell
jamescrosswell changed the base branch from main to fix/5406-pin-xcode-26.6 July 21, 2026 01:06
Base automatically changed from fix/5406-pin-xcode-26.6 to main July 21, 2026 03:35
jamescrosswell and others added 5 commits July 21, 2026 15:41
xcodebuild embeds each framework's dynamic dependencies under
<Framework>.framework/Frameworks/, producing deeply nested paths
(SentryObjC.framework/Frameworks/SentryObjCCompat.framework/Frameworks/Sentry.framework)
that exceed NuGet's path-length limit and fail packing with NU5123. We bundle
Sentry, SentryObjCCompat and SentryObjC as separate NativeReferences (each
embedded into the consuming app and resolved via @rpath), so the nested copies
are redundant. Strip them after building the xcframeworks.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The new SentryObjCSDK.internal profiling API returns an immutable NSDictionary,
whereas the old PrivateSentrySDKOnly.collectProfileBetween returned a mutable
one. CocoaProfiler.Collect mutates the payload (adds transaction id/trace_id/
name/timestamp), which threw NotSupportedException on the immutable dictionary
and failed Profiler_RunningUnderFullClient_SendsProfileData. Copy it into an
NSMutableDictionary first.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The app bundle now contains the SentryObjC and SentryObjCCompat frameworks
alongside Sentry.framework, so sentry-cli uploads their debug symbols too.
Add them to the expected upload list.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Phase 3: all call sites migrated to SentryObjCSDK.internal in the previous
phase, so drop the deprecated PrivateSentrySDKOnly interface entirely - the
header no longer feeds Objective Sharpie, the patch rules that shaped it are
gone, and the regenerated ApiDefinitions.cs loses the interface (pure removal,
no other changes). sentry-cocoa removes the class in its next major.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Comment thread scripts/generate-cocoa-bindings.ps1
Comment thread scripts/generate-cocoa-bindings.ps1 Outdated
Comment thread scripts/patch-cocoa-bindings.cs Outdated
Comment thread scripts/patch-cocoa-bindings.cs Outdated
Comment thread src/Sentry/Platforms/Cocoa/CocoaProfiler.cs Outdated
Comment thread src/Sentry.Bindings.Cocoa/Sentry.Bindings.Cocoa.csproj Outdated
Co-authored-by: James Crosswell <jamescrosswell@users.noreply.github.com>
Comment thread scripts/build-sentry-cocoa.sh Outdated
jamescrosswell and others added 4 commits July 23, 2026 10:35
…entry/sentry-dotnet into migrate-private-sentrysdk-only-5331
The previous comment implied the SentryObjCCompat/SentryObjC order was a
requirement. These are dynamic frameworks whose inter-dependencies are recorded
in their own Mach-O load commands and resolved by dyld via @rpath at load time,
so the item order has no functional effect - it's dependency-first purely for
readability.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Comment thread src/Sentry.Bindings.Cocoa/Sentry.Bindings.Cocoa.csproj Outdated
Comment thread src/Sentry.Bindings.Cocoa/Sentry.Bindings.Cocoa.csproj Outdated
jamescrosswell and others added 2 commits July 23, 2026 10:47
Co-authored-by: James Crosswell <jamescrosswell@users.noreply.github.com>
The comment's closing --> was accidentally replaced with a Unicode arrow,
leaving the comment unterminated so the project file failed to load
(NETSDK: "An XML comment cannot contain '--'"), which broke every CI job
at environment setup.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
PowerShell terminates a backtick line-continuation at a comment line, so the
inline comment split the sharpie bind invocation in two and the script failed
to parse (ParserError at the next header argument), breaking bindings
generation. Keep the comment, but above the command.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@jamescrosswell
jamescrosswell marked this pull request as ready for review July 23, 2026 01:17
@github-actions github-actions Bot added the risk: medium PR risk score: medium label Jul 23, 2026
@jamescrosswell
jamescrosswell requested a review from philprime July 23, 2026 01:18
Comment thread src/Sentry.Bindings.Cocoa/Sentry.Bindings.Cocoa.csproj
Comment thread src/Sentry/Platforms/Cocoa/CocoaProfiler.cs
@jamescrosswell
jamescrosswell requested a review from jpnurmi July 23, 2026 01:25
The download path could only supply Sentry-Dynamic.xcframework - it had no way
to provide the SentryObjC/SentryObjCCompat frameworks the bindings now require
(there is no non-duplicating released artifact), so if ever activated it would
produce a build that fails at runtime on any hybrid-API use. It was already
dormant: modules/sentry-cocoa.properties does not exist, and CI checks out the
submodule, so the source build is the only path actually exercised.

Remove _DownloadCocoaSDK, the released-builds property group and the
SanitizeSentryCocoaFramework target (the source build already strips headers,
modules and dSYMs), simplify the bindings-generation script accordingly, and
fail with a clear error if the submodule is missing. Update docs, solution
items and workflow path filters that referenced sentry-cocoa.properties.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions github-actions Bot added risk: high PR risk score: high and removed risk: medium PR risk score: medium labels Jul 23, 2026
…5331)

buildTransitive targets are imported into consuming apps, where
ReferenceCopyLocalPaths spans every referenced package - the broadened
'.xcframework' match could strip other packages' simulator resources during
Hot Restart builds. Enumerate our three frameworks explicitly instead
(note 'Sentry.xcframework' is not a substring of 'SentryObjC.xcframework',
so all three clauses are required).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Comment thread src/Sentry.Bindings.Cocoa/Sentry.Bindings.Cocoa.csproj
Comment thread src/Sentry.Bindings.Cocoa/StructsAndEnums.cs Outdated
Comment thread src/Sentry.Bindings.Cocoa/buildTransitive/Sentry.Bindings.Cocoa.targets Outdated
jamescrosswell and others added 4 commits July 23, 2026 16:26
The check previously ran in the _SetupCocoaSDK body, after its dependencies.
It was still reached in practice (with no submodule the generation target is
skipped for having no inputs - verified empirically), but that relied on a
non-obvious MSBuild skip rule. Give the check its own target that runs first
in the dependency chain so the ordering is structural.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…entry/sentry-dotnet into migrate-private-sentrysdk-only-5331
Sharpie emits SentryObjCFeedbackSource / SentryObjCLastRunStatus because the
SentryObjC headers reference them, but the members that used them are trimmed
by the patch script, leaving dead enums. Add a RemoveEnum filter and drop all
SentryObjC* enums - the hybrid-API surface we bind uses none.

Co-Authored-By: Claude Opus 4.8 <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.

Reviewed by Cursor Bugbot for commit 247a9f0. Configure here.

Comment thread scripts/build-sentry-cocoa.sh
The early-exit stamp only keyed on the sentry-cocoa submodule SHA, so a
Carthage cache produced by an older version of this script (same submodule
SHA, but without the SentryObjC/SentryObjCCompat frameworks) would be treated
as up to date and the new frameworks would never be built. Key the stamp on
the submodule SHA plus this script's own checksum - mirroring the cache key
already used for sentry-native in CI - so any recipe change invalidates
cached output.

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

@philprime philprime left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM from a code-level review perspective.

Regarding the duplicate SDKs:

The published SentryObjC target is designed as a full replacement for the Sentry target. Therefore, bundling both published frameworks would result in duplicate SDK framework slices. Given that the .NET SDK still depends on Sentry, building SentryObjC and SentryObjCCompat from source as thin frameworks seems like a reasonable interim solution for this pull request.

As a follow-up, I propose migrating the remaining bindings from Sentry to SentryObjC. Most types should have one-to-one replacements, and this would allow the SDK to ship only SentryObjC. We plan to remove Objective-C compatibility from the Sentry target in the next major release later this year, so completing that migration will be important.

@jamescrosswell

Copy link
Copy Markdown
Collaborator Author

As a follow-up, I propose migrating the remaining bindings from Sentry to SentryObjC. Most types should have one-to-one replacements, and this would allow the SDK to ship only SentryObjC. We plan to remove Objective-C compatibility from the Sentry target in the next major release later this year, so completing that migration will be important.

Ah, great - thanks @philprime !

@jpnurmi jpnurmi left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I couldn't find anything blocking either. Just a couple of nitpicks. 😅

<ReferenceCopyLocalPaths Remove="@(ReferenceCopyLocalPaths)" Condition="$([System.String]::new('%(Identity)').Contains('Sentry.xcframework\ios-arm64_x86_64-simulator'))" />
<!-- Only strip from the frameworks bundled with this package - this file is
imported transitively into consuming apps -->
<ReferenceCopyLocalPaths Remove="@(ReferenceCopyLocalPaths)" Condition="$([System.String]::new('%(Identity)').Contains('Sentry.xcframework\ios-arm64_x86_64-simulator')) Or $([System.String]::new('%(Identity)').Contains('SentryObjC.xcframework\ios-arm64_x86_64-simulator')) Or $([System.String]::new('%(Identity)').Contains('SentryObjCCompat.xcframework\ios-arm64_x86_64-simulator'))" />

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

maybe worth something like Sentry(ObjC|ObjCCompat)?\.xcframework\\ios-arm64_x86_64-simulator pattern match?

Comment thread CONTRIBUTING.md
$ rm -rf modules/sentry-cocoa
$ dotnet build ... # downloads pre-built Cocoa SDK into modules/sentry-cocoa
$ cd modules/sentry-cocoa
$ git fetch origin && git checkout <tag-or-sha>

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Side-note: arbitrary checkouts worked with a standalone clone, but I recall the automatic submodule update in before.Sentry.sln.targets fights back when trying to do this with submodules:

<Project InitialTargets="RestoreSubmodule">
<!-- Always restore, to apply changes when we change branches. If no changes happened, this is pretty quick so no need to optimize by adding a Condition -->
<Target Name="RestoreSubmodule">
<Exec Command="git submodule update --init --recursive" />
</Target>
</Project>

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

Labels

risk: high PR risk score: high

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Migrate from PrivateSentrySDKOnly to SentryObjCSDK.internal

3 participants