ref: migrate Cocoa bindings from PrivateSentrySDKOnly to SentryObjCSDK.internal#5409
ref: migrate Cocoa bindings from PrivateSentrySDKOnly to SentryObjCSDK.internal#5409jamescrosswell wants to merge 26 commits into
Conversation
…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 Report✅ All modified and coverable lines are covered by tests. 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. 🚀 New features to boost your workflow:
|
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>
…grate-private-sentrysdk-only-5331
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>
Co-authored-by: James Crosswell <jamescrosswell@users.noreply.github.com>
…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>
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>
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>
…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>
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>
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.
Reviewed by Cursor Bugbot for commit 247a9f0. Configure here.
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
left a comment
There was a problem hiding this comment.
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.
Ah, great - thanks @philprime ! |
jpnurmi
left a comment
There was a problem hiding this comment.
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'))" /> |
There was a problem hiding this comment.
maybe worth something like Sentry(ObjC|ObjCCompat)?\.xcframework\\ios-arm64_x86_64-simulator pattern match?
| $ 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> |
There was a problem hiding this comment.
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:
sentry-dotnet/before.Sentry.sln.targets
Lines 1 to 6 in 65c0c59

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 structuredSentryObjCSDK.internalAPI introduced in sentry-cocoa 9.19.mainalready pins sentry-cocoa 9.22.0, so no dependency bump is required.Key incremental/separate commits, in case this helps for review purposes:
SentryObjCheaders (build-sentry-cocoa.sh, generate-cocoa-bindings.ps1, patch-cocoa-bindings.cs, ApiDefinitions.cs).PrivateSentrySDKOnlykept in parallel - e532a2fSentryCocoaHybridSdkalias to the new instance-based API cada275PrivateSentrySDKOnlyfrom the binding, patch/generate scripts, and props 55ff0b8Note: We build from source now
SentryCocoaHybridSdkMSBuild alias (SetSdkName,SetTrace,StartProfilerForTrace,CollectProfileBetween,IgnoreNextSignal). Every one has a direct equivalent within[SentryObjCSDK internal].SentryObjC-Dynamic.xcframeworkis not usable as-is. It is fully self-contained (~4.4 MB/slice): it definesSentryHubInternal,SentryClientInternal,SentryObjCSDKand the SentrySwift classes, and links no externalSentry.framework. Bundling it alongside theSentry.frameworkwe 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 newinternalcalls to another.SentryObjCXcode scheme; it builds cleanly and ships theSentryObjCSDK/SentryObjCInternalApipublic headers.SentryObjC+SentryObjCCompatfrom source produces thin two frameworks (136 KB + 1.2 MB) that only define the new additiveSentryObjC*wrapper types and import the real SDK classes (_SentryScope,_SentryBreadcrumb,_SentryUser, …) as undefined symbols resolved at load time from the existingSentry.frameworkvia@rpath. No duplication; the new API shares the same SDK instance as the current bindings.Issues
Closes #5331