Skip to content

feat(objc): Add SentryObjC wrapper SDK#7598

Draft
philprime wants to merge 57 commits intomainfrom
philprime/objc-wrapper-sdk-6342
Draft

feat(objc): Add SentryObjC wrapper SDK#7598
philprime wants to merge 57 commits intomainfrom
philprime/objc-wrapper-sdk-6342

Conversation

@philprime
Copy link
Copy Markdown
Member

@philprime philprime commented Mar 4, 2026

📜 Description

Adds a pure Objective-C SDK wrapper (SentryObjC) that enables Sentry usage in Objective-C++ projects with CLANG_ENABLE_MODULES=NO. This solves the long-standing issue where Swift SDK APIs are inaccessible without Clang modules, affecting React Native, Haxe, and other custom build systems.

What's Included

  • SentryObjC module: Pure Objective-C headers that mirror the Swift SDK public API
  • SentryObjCBridge: Swift bridge layer that forwards calls from ObjC to the Swift SDK
  • Type wrappers: ObjC implementations for Swift-only types (Metrics API, AttributeContent, Units)
  • API stability tracking: Automated extraction and CI checks via sdk_objc_api.json
  • Sample application: iOS-ObjectiveCpp-NoModules demonstrating real-world usage
  • Session Replay support: Full replay API exposed via bridge

💡 Motivation and Context

Closes #6342

The Problem

Since SDK 8.54.0, the Swift SDK's public API requires Clang modules to be imported. When CLANG_ENABLE_MODULES=NO:

  • #import <Sentry/Sentry.h> only exposes Objective-C APIs
  • Swift types like SentrySDK, SentryOptions.sessionReplay, and the Metrics API are unavailable
  • Build errors: use of undeclared identifier 'SentrySDK'

This breaks projects that cannot enable modules, particularly:

  • React Native (uses ObjC++ extensively)
  • Haxe-based applications
  • Custom build systems with strict compiler settings

Implementation Approach & Thought Process

Initial Considerations

Option 1: Make Swift SDK importable without modules

  • ❌ Extremely difficult - would require rewriting core SDK architecture
  • ❌ Breaks existing Swift API design patterns
  • ❌ Not backwards compatible

Option 2: Pure ObjC wrapper (chosen approach)

  • ✅ Preserves existing SDK architecture
  • ✅ Allows Swift and ObjC to coexist
  • ✅ Minimal maintenance burden
  • ✅ Clean separation of concerns

Architecture Decision

The wrapper uses a three-layer architecture:

┌─────────────────────────────────────┐
│   SentryObjC (Pure ObjC Headers)    │  ← Public API for no-modules context
│  Sources/SentryObjC/Public/*.h      │
└──────────────┬──────────────────────┘
               │
               ▼
┌─────────────────────────────────────┐
│   SentryObjCBridge (Swift)          │  ← Forwards to Swift SDK
│  Sources/SentryObjCBridge/*.swift   │
└──────────────┬──────────────────────┘
               │
               ▼
┌─────────────────────────────────────┐
│     SentrySwift (Main SDK)          │  ← Actual implementation
└─────────────────────────────────────┘

Why this design?

  1. Forward declarations avoid circular dependencies: SentryObjCSDK.m forward-declares SentrySDKInternal without importing headers, letting the linker resolve at build time
  2. Bridge handles Swift-ObjC impedance: Complex Swift types (generics, enums with associated values) are converted in the bridge layer
  3. Type safety preserved: Bridge validates attribute types and silently fails on invalid input rather than crashing

Key Implementation Decisions

1. Metrics API Type Conversion

Challenge: Swift's SentryAttributeContent enum with associated values cannot be directly bridged to ObjC.

Solution: Created SentryObjCAttributeContent as a class with factory methods:

[SentryObjCAttributeContent stringWithValue:@"endpoint"]
[SentryObjCAttributeContent integerWithValue:200]

Bridge uses KVC to extract values and convert to Swift enums. This avoids circular imports while maintaining type safety.

2. Session Replay API

Initial approach: Tried forward-declaring SentrySDKInternal.replay property

  • ❌ Failed: Class properties in ObjC forward declarations are not recognized by the compiler

Final solution: Exposed via bridge

// SentryObjCBridge.swift
@objc public static var replay: AnyObject {
    return SentrySDK.replay
}
// SentryObjCSDK.m
+ (SentryReplayApi *)replay {
    return [SentryObjCBridge replay];
}

This pattern proved more reliable and consistent with the metrics/logger APIs.

3. Lazy Initialization Pattern

Original: Metrics API initialized in +initialize

+ (void)initialize {
    _metricsApi = [[SentryObjCMetricsApiImpl alloc] init];
}

Problem: Runs before SDK initialization, could cause issues if bridge calls Swift before SDK is ready.

Fixed: Switched to dispatch_once lazy initialization:

+ (id<SentryObjCMetricsApi>)metrics {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _metricsApi = [[SentryObjCMetricsApiImpl alloc] init];
    });
    return _metricsApi;
}

Guarantees thread-safe initialization only when first accessed.

4. Package Manifest Consistency

Bug: Swift 6.1 manifest (Package@swift-6.1.swift) was missing SentryObjCBridge in product targets:

// ❌ Missing bridge
.library(name: "SentryObjC", targets: ["SentryObjCInternal", "SentryObjC", "SentryCppHelper"])

// ✅ Fixed
.library(name: "SentryObjC", targets: ["SentryObjCInternal", "SentryObjCBridge", "SentryObjC", "SentryCppHelper"])

This would cause linker errors on Swift 6.1 since the bridge symbols wouldn't be included.

5. Package Resolution for Compile-from-Source Builds

Problem: SentryObjC product included SentryCppHelper, which isn't available in SPM compile-from-source context, causing package resolution failures in CI.

Solution: Removed SentryCppHelper from SentryObjC product to match SentrySPM pattern:

// Before
.library(name: "SentryObjC", targets: ["SentryObjCInternal", "SentryObjCBridge", "SentryObjC", "SentryCppHelper"])

// After
.library(name: "SentryObjC", targets: ["SentryObjCInternal", "SentryObjCBridge", "SentryObjC"])

SentryCppHelper is only needed for binary distribution products, not compile-from-source products.

Validation Strategy

Robust validation without logging overhead:

// Original approach: Verbose logging for each failure
guard let attr = value as? NSObject else {
    SentrySDK.logger.log("Invalid attribute", level: .warning)
    continue
}

// Final approach: Silent failure, cleaner code
objcAttributes.compactMapValues { value in
    guard let attr = value as? NSObject,
          let type = attr.value(forKey: "type") as? Int,
          let converted = convert(attr, type)
    else { return nil }
    return converted
}

Invalid attributes are silently skipped - this is intentional since:

  • Keeps metrics API performant (no logging overhead)
  • Prevents log spam from user mistakes
  • Matches Swift SDK's behavior for invalid attributes

🧪 Testing Strategy

Unit Tests

  • ✅ Metrics API shape and parameter variants
  • ✅ Attribute type conversion (string, bool, int, double, arrays)
  • ✅ Nil/empty attribute handling
  • ✅ Invalid attribute graceful degradation
  • ✅ Singleton pattern for metrics API
  • ✅ Replay API availability on supported platforms

Integration Tests

  • ✅ iOS-ObjectiveCpp-NoModules sample app builds successfully
  • ✅ SDK initialization with SentryObjCSDK
  • ✅ Session replay configuration (on supported platforms)
  • ✅ Metrics recording via ObjC API

Build Verification

make format      # ✅ SwiftLint + clang-format
make analyze     # ✅ 0 violations
make build-ios   # ✅ Compiles for iOS Simulator
make build-sample-iOS-ObjectiveCpp-NoModules  # ✅ Sample builds

API Stability

  • Automated extraction via extract-objc-api.sh (uses clang AST parsing)
  • CI checks for breaking changes in sdk_objc_api.json
  • Prevents accidental API modifications

🔖 Breaking Changes & Compatibility

No Breaking Changes

  • Existing SDK users unaffected
  • SentryObjC is an additive feature
  • Swift SDK API unchanged
  • ObjC projects with modules still use the main SDK

Hybrid SDK Impact

  • React Native: Can now use SentryObjC for ObjC++ code
  • Flutter/Dart: No impact (uses Cocoa SDK via platform channels)
  • Unity/Unreal: No impact (uses PrivateSentrySDKOnly SPI)

📝 Checklist

  • I added tests to verify the changes
  • No new PII added
  • Docs updated (sample README, AGENTS.md)
  • Wizard update (not applicable - advanced use case)
  • Review from native team
  • No breaking changes
  • No breaking changes for hybrid SDKs

🔗 Related Issues & Context

📦 XCFramework CI Pipeline

The standalone SentryObjC.xcframework build is integrated into the release CI workflow:

  • Reuses existing sentry-static slices — no redundant Sentry static builds
  • 2 new slice entries: SentryObjCBridge and SentryObjC (staticlib), built in parallel across all platform SDKs
  • Custom assembly workflow (assemble-xcframework-sentryobjc.yml): downloads all 3 static slice sets, merges via libtool, links via swiftc into a dynamic framework per SDK, assembles into xcframework
  • Dynamic framework detection: instead of hardcoded per-platform framework lists, checks SDK sysroot at link time — works correctly on all platforms including watchOS and tvOS
build-xcframework-variant-slices (matrix: slices × SDKs)
  → sentry-static slices (reused)
  → sentryobjc-bridge slices (new)
  → sentryobjc-objc slices (new)
assemble-xcframework-sentryobjc (custom)
  → libtool + swiftc per SDK → SentryObjC.xcframework

🚀 Future Improvements

Potential follow-ups (not blocking this PR):

  1. E2E integration tests: Verify metrics actually reach Sentry backend
  2. Performance benchmarks: Measure bridge overhead for metrics API
  3. Documentation site: Add guide to docs.sentry.io for ObjC-only users
  4. Feedback API: Expose user feedback API via ObjC wrapper
  5. Profiling API: Add continuous profiling controls to ObjC wrapper

Add a pure Objective-C SDK wrapper that mirrors the Sentry public API so it can be used from ObjC++ without modules (e.g. for React Native, Haxe, custom build systems). Includes:

- SentryObjC product and target in Package.swift
- Re-declared headers for all public types in Sources/SentryObjC/Public/
- Wrapper implementations for Swift-only types (Unit, Metric, MetricValue, AttributeContent, RedactRegionType)
- iOS-ObjectiveCpp-NoModules sample using SentryObjC
- sdk_objc_api.json generation via extract-objc-api.py for API stability CI
- Makefile targets: build-spm-objc, verify-objc, generate-objc-api

Refs GH-6342
@philprime philprime self-assigned this Mar 4, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 4, 2026

Semver Impact of This PR

🟡 Minor (new features)

📋 Changelog Preview

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


New Features ✨

  • (objc) Add SentryObjC wrapper SDK by philprime in #7598

Documentation 📚

  • Add SentryCrash analysis and improvement plan document by itaybre in #7528

Internal Changes 🔧

  • (deps) Bump json from 2.18.1 to 2.19.2 by dependabot in #7709

🤖 This preview updates automatically when you update the PR.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 4, 2026

Messages
📖 Do not forget to update Sentry-docs with your feature once the pull request gets approved.

Generated by 🚫 dangerJS against 6189f81

@codecov
Copy link
Copy Markdown

codecov bot commented Mar 4, 2026

Codecov Report

❌ Patch coverage is 0% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 85.111%. Comparing base (08e4b17) to head (6189f81).
⚠️ Report is 7 commits behind head on main.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
...ources/Swift/Protocol/SentryAttributeContent.swift 0.000% 2 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@              Coverage Diff              @@
##              main     #7598       +/-   ##
=============================================
- Coverage   85.919%   85.111%   -0.809%     
=============================================
  Files          486       487        +1     
  Lines        28947     28988       +41     
  Branches     12551     12556        +5     
=============================================
- Hits         24871     24672      -199     
- Misses        4028      4269      +241     
+ Partials        48        47        -1     
Files with missing lines Coverage Δ
Sources/Swift/Core/Helper/Log/SentryLevel.swift 100.000% <ø> (ø)
...ources/Swift/Protocol/SentryAttributeContent.swift 97.000% <0.000%> (-1.980%) ⬇️

... and 27 files with indirect coverage changes


Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 08e4b17...6189f81. Read the comment docs.

Add detailed documentation to core SentryObjC public APIs following
Objective-C documentation best practices:
- Document all properties with their purpose and behavior
- Document all methods with parameters and return values
- Add class-level documentation explaining usage context
- Include notes about automatic behavior and warnings where applicable

Files documented:
- SentryObjCSDK: Main SDK entry point
- SentryObjCOptions: Configuration options
- SentryObjCEvent: Event data structure
- SentryObjCScope: Contextual data container
- SentryObjCBreadcrumb: Breadcrumb trail
- SentryObjCUser: User identification
- SentryObjCSpanProtocol: Performance tracing protocol

Also adds changelog entry explaining the purpose of the SentryObjC
wrapper SDK.
Add comprehensive documentation to exception, attachment, message,
and tracing-related classes:
- SentryObjCException: Exception information
- SentryObjCAttachment: File attachments
- SentryObjCMessage: Log messages
- SentryObjCSpanContext: Span trace context
- SentryObjCTransactionContext: Transaction context

All classes now include detailed property and method documentation
following Objective-C best practices.
Add comprehensive documentation to:
- SentryObjCFrame: Stack frame with source location and context
- SentryObjCStacktrace: Stack trace with frames and registers
- SentryObjCThread: Thread information and crash state
- SentryObjCMechanism: Error mechanism and handling context
- SentryObjCDebugMeta: Debug symbols and binary metadata
- SentryObjCRequest: HTTP request information
- SentryObjCGeo: Geographical location data

All classes now include detailed property and method documentation.
Add comprehensive documentation to:
- SentryObjCReplayOptions: Session replay configuration with privacy controls
- SentryObjCReplayApi: Runtime replay control and masking API
- SentryObjCSamplingContext: Context for dynamic trace sampling decisions

All properties and methods now include detailed documentation explaining
their purpose, behavior, and usage.
Remove the conditional check for sdk_objc_api.json existence since an
empty baseline file will be added to main in a follow-up PR. This
simplifies the workflow logic.
Keep the original problem description explaining why modules don't work
in ObjC++ projects, then show how SentryObjC solves this issue. This
provides better context for readers to understand why SentryObjC exists.

- Restore "Problem" section describing module import failures
- Add "Solution: SentryObjC" section explaining how it solves the issue
- List key differences from the main Sentry framework
- Reference original issue #4543 and solution PR #6342
Sync with main to include latest changes and adopt new sample
structure using projectReferences instead of SPM packages.
philprime and others added 6 commits March 10, 2026 12:49
Replace Python-based regex parsing with clang AST dump and jq
processing. The new approach:

- Uses xcrun clang -ast-dump=json for reliable parsing
- Extracts declarations via jq queries on intermediate files
- Outputs structured JSON objects instead of string signatures
- Migrates from Python to pure bash/jq pipeline

Also standardize filename to sdk_api_objc.json to match the
sdk_api.json and sdk_api_sentryswiftui.json naming convention.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Include the iOS-ObjectiveCpp-NoModules sample in CI build verification
to ensure it continues to build successfully with the SentryObjC wrapper.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add the SentryObjC product and target to Package@swift-6.1.swift so
the sample can reference it. Also revert iOS-ObjectiveCpp-NoModules
sample to use SPM packages instead of projectReferences since
SentryObjC is an SPM product, not an Xcode project target.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Complete documentation for:
- SentryObjCAppStartMeasurement (app start types and timestamps)
- SentryObjCAttributeContent (typed attribute values)
- SentryObjCBaggage (distributed tracing propagation)
- SentryObjCError (SDK error codes and helpers)
- SentryObjCLogger (structured logging interface)
- SentryObjCMechanismContext (crash metadata)
- SentryObjCMetric (custom performance metrics)
- SentryObjCMetricValue (metric value types)
- SentryObjCNSError (serializable error representation)

All public types, properties, methods, and enum values now have
comprehensive documentation following Objective-C best practices.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@philprime
Copy link
Copy Markdown
Member Author

@sentry review

@philprime philprime added the ready-to-merge Use this label to trigger all PR workflows label Mar 10, 2026
@sentry
Copy link
Copy Markdown

sentry bot commented Mar 10, 2026

Sentry Build Distribution

App Name App ID Version Configuration Install Page
SDK-Size io.sentry.sample.SDK-Size 9.8.0 (1) Release Install Build

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 10, 2026

Performance metrics 🚀

  Plain With Sentry Diff
Startup time 1227.13 ms 1254.47 ms 27.34 ms
Size 24.14 KiB 1.13 MiB 1.10 MiB

Baseline results on branch: main

Startup times

Revision Plain With Sentry Diff
c9e5b2d 1216.67 ms 1247.04 ms 30.38 ms
dbfeb41 1215.17 ms 1237.41 ms 22.23 ms
b5c1b24 1217.94 ms 1248.76 ms 30.82 ms
ee272e8 1210.98 ms 1245.10 ms 34.12 ms
87074ac 1217.81 ms 1255.55 ms 37.74 ms
69a0c94 1217.85 ms 1246.98 ms 29.13 ms
6e4c642 1222.90 ms 1258.15 ms 35.25 ms
1364456 1217.73 ms 1250.33 ms 32.59 ms
09a80f2 1214.78 ms 1237.85 ms 23.07 ms
1d0feed 1213.31 ms 1247.44 ms 34.14 ms

App size

Revision Plain With Sentry Diff
c9e5b2d 24.14 KiB 1.12 MiB 1.10 MiB
dbfeb41 24.14 KiB 1.04 MiB 1.02 MiB
b5c1b24 24.14 KiB 1.06 MiB 1.04 MiB
ee272e8 24.14 KiB 1.10 MiB 1.08 MiB
87074ac 24.14 KiB 1.12 MiB 1.10 MiB
69a0c94 24.14 KiB 1.11 MiB 1.09 MiB
6e4c642 24.14 KiB 1.12 MiB 1.10 MiB
1364456 24.14 KiB 1.12 MiB 1.10 MiB
09a80f2 24.14 KiB 1.10 MiB 1.08 MiB
1d0feed 24.14 KiB 1.05 MiB 1.03 MiB

Previous results on branch: philprime/objc-wrapper-sdk-6342

Startup times

Revision Plain With Sentry Diff
197530f 1234.94 ms 1261.72 ms 26.79 ms
664430d 1225.83 ms 1256.84 ms 31.01 ms
39ba3ef 1230.17 ms 1264.98 ms 34.81 ms
bb809e8 1229.33 ms 1262.54 ms 33.21 ms
1fdc116 1215.71 ms 1243.67 ms 27.96 ms
97b6c3d 1214.02 ms 1241.32 ms 27.30 ms
d8c9a46 1225.63 ms 1247.76 ms 22.13 ms
a1f5242 1222.28 ms 1245.53 ms 23.25 ms
f042c2d 1217.49 ms 1232.57 ms 15.08 ms
2105a77 1213.57 ms 1225.68 ms 12.12 ms

App size

Revision Plain With Sentry Diff
197530f 24.14 KiB 1.13 MiB 1.10 MiB
664430d 24.14 KiB 1.12 MiB 1.10 MiB
39ba3ef 24.14 KiB 1.13 MiB 1.10 MiB
bb809e8 24.14 KiB 1.12 MiB 1.10 MiB
1fdc116 24.14 KiB 1.13 MiB 1.10 MiB
97b6c3d 24.14 KiB 1.13 MiB 1.10 MiB
d8c9a46 24.14 KiB 1.12 MiB 1.10 MiB
a1f5242 24.14 KiB 1.12 MiB 1.10 MiB
f042c2d 24.14 KiB 1.12 MiB 1.10 MiB
2105a77 24.14 KiB 1.13 MiB 1.10 MiB

philprime and others added 2 commits March 10, 2026 14:05
The SentryObjC product depends on SentryCppHelper, but it was only
defined in the binary targets section. Add it to the compile-from-source
targets array so it's available when building SentryObjC from source.

Fixes SPM package resolution error:
target 'SentryCppHelper' referenced in product 'SentryObjC' could not be found

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add SentryObjCSDK.m implementation that forwards all method calls to
SentrySDKInternal. This enables SentryObjC to work in projects with
CLANG_ENABLE_MODULES=NO, where Swift's @objc bridging is unavailable.

The wrapper provides a pure Objective-C implementation of the SentrySDK
class, making all SDK methods accessible via #import <SentryObjC.h>
without requiring modules or Swift bridging.

Update iOS-ObjectiveCpp-NoModules sample to use the corrected import
style (#import <SentryObjC.h> instead of <SentryObjC/SentryObjC.h>)
and add module.modulemap for SPM module resolution.

Refs #6342
@sentry
Copy link
Copy Markdown

sentry bot commented Mar 10, 2026

Sentry Build Distribution

App Version Configuration
App 9.6.0 (1) Release

SentryCppHelper must remain in the initial targets array because the
binary distribution products (Sentry, SentrySwiftUI, etc.) depend on it.

Moving it to the compile-from-source section broke those binary products.
The target can be safely referenced by both binary and source products.
@philprime philprime force-pushed the philprime/objc-wrapper-sdk-6342 branch from 7abca39 to 913cdfd Compare March 10, 2026 13:37
@sentry
Copy link
Copy Markdown

sentry bot commented Mar 10, 2026

Sentry Build Distribution

App Version Configuration
App 9.6.0 (1) Release

Revert atomic operations changes to SentryNSExceptionCaptureHelper.m
that were extracted to a separate PR #7672 for independent review.

This keeps our PR focused on the SentryObjC wrapper SDK functionality.

Refs #6342
Refs #7672
Fix multiple issues identified by automated code review:

1. **Critical: Fix SentryAttributeContent protocol conformance**
   - Make SentryAttributeContent conform to SentryAttributeValue
   - Prevents all ObjC metrics attributes from being silently dropped
   - Bug reported by Sentry bot at SentryObjCBridge.swift:92

2. **High: Fix filename mismatch in file-filters.yml**
   - Change sdk_objc_api.json -> sdk_api_objc.json to match workflow
   - Ensures API stability checks trigger correctly
   - Bug reported by Cursor bot

3. **Medium: Fix Makefile script reference**
   - Change extract-objc-api.py -> extract-objc-api.sh (actual file)
   - Fix output filename: sdk_objc_api.json -> sdk_api_objc.json
   - Bug reported by Cursor bot at Makefile:825

4. **High: Remove NSObject category causing infinite recursion**
   - Delete NSObject (SentryObjCMetricsApiDefaults) category
   - Category declared protocol conformance on all NSObjects
   - Caused infinite recursion when convenience methods called
   - Bug reported by Cursor bot at SentryObjCMetricsApi.m:28

Users should call the full method signatures directly with nil for
optional parameters instead of using convenience methods.

Refs #6342
philprime and others added 20 commits March 17, 2026 16:32
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Use typealias SDKAttributeContent to explicitly reference Sentry module's
SentryAttributeContent, avoiding ambiguity with SentryObjC wrapper type.
Move SentryObjCBridge.swift from SentryObjC target to Sentry target
to avoid module conflicts. When Swift code was in SentryObjC, it
could see both the SentryObjC module and Sentry module definitions
of the same types (SentryUser, SentryOptions, etc.), causing
compilation errors.

Architecture is now:
- Sentry.framework: SDK + SentrySDKInternal + SentryObjCBridge
- SentryObjC.framework: pure ObjC with forward declarations

At link time, SentryObjC calls resolve to implementations in Sentry.

Also:
- Fix bridge imports (can't import Sentry when inside Sentry module)
- Add SentryObjC.xcframework to gitignore
- Update Ruby script to not include bridge in SentryObjC target
Use swiftc -emit-library to link all three static archives
(Sentry, SentryObjCBridge, SentryObjC) into a single standalone
dynamic binary. swiftc handles Swift runtime linking automatically,
eliminating the need for manual Swift compatibility library paths.

Build flow:
1. xcodebuild each target as staticlib
2. libtool -static to merge into one archive
3. swiftc -emit-library -force_load to create dynamic framework
4. Copy SentryObjC public headers and module map

Also update develop-docs/SENTRY-OBJC.md with xcframework build
documentation.

Refs #6342
This commit introduces several new public headers to enhance the SentryObjC SDK, including:
- `PrivateSentrySDKOnly.h`: SPI for hybrid SDK wrappers.
- `SentryAttribute.h`: Represents typed attribute values for structured logging.
- `SentryEnvelope.h`, `SentryEnvelopeHeader.h`, `SentryEnvelopeItem.h`: Define the structure of Sentry envelopes.
- `SentryFeedback.h` and `SentryFeedbackSource.h`: Facilitate user feedback submissions.
- `SentryLog.h` and `SentryLogLevel.h`: Introduce structured logging capabilities.

Additionally, the `project.pbxproj` file has been updated to include these new headers in the public headers section.
Refactor the xcframework build script to define platform-specific framework lists for required and weak frameworks. This change enhances the script's flexibility by allowing different frameworks to be linked based on the target SDK, improving compatibility across platforms.
Add SentryObjCBridge and SentryObjC static slice entries to the
release matrix, reusing existing sentry-static slices for Sentry.
Create a custom assembly workflow that downloads all three sets of
slices, links them via libtool+swiftc, and produces a standalone
SentryObjC.xcframework.

Remove -ForEmbedding suffix — the static builds are identical to
the normal ones. Replace hardcoded per-platform framework lists
with dynamic SDK detection to avoid link failures on platforms
that lack certain frameworks (e.g. WebKit on watchOS).
@github-actions
Copy link
Copy Markdown
Contributor

🚨 Detected changes in high risk code 🚨

High-risk code can easily blow up and is hard to test. We had severe bugs in the past. Be extra careful when changing these files, and have an extra careful look at these:

  • .github/file-filters.yml

@philprime
Copy link
Copy Markdown
Member Author

CI: SentryObjC XCFramework Pipeline

Added CI support for building the standalone SentryObjC.xcframework as part of the release workflow.

What changed

  • 2 new slice entries in generate_release_matrix.sh: SentryObjCBridge and SentryObjC (both as staticlib). The existing sentry-static slices are reused for the Sentry component — no redundant builds.
  • New assembly workflow (assemble-xcframework-sentryobjc.yml): downloads all 3 sets of static slices, arranges them into the expected directory layout, then runs build-xcframework-sentryobjc-standalone.sh which does libtool merge + swiftc dynamic link per SDK.
  • Byproduct cleanup in slice builds: SentryObjCBridge and SentryObjC slice builds now remove Sentry.framework byproducts (same pattern as SentrySwiftUI).
  • Removed -ForEmbedding suffix — investigation confirmed the -ForEmbedding static builds were identical to the normal static builds (same scheme, config, Mach-O type). The suffix was only a directory naming convention from development, not a different build configuration.
  • Dynamic framework detection in the standalone script: instead of hardcoded per-platform framework lists (which broke on watchOS/tvOS due to missing WebKit etc.), the script now checks which frameworks actually exist in each SDK's System/Library/Frameworks/ at link time.

CI flow

generate_release_matrix.sh
  → build-xcframework-variant-slices.yml (matrix: 6 slices × N SDKs)
      includes: sentry-static, sentryobjc-bridge, sentryobjc-objc
  → assemble-xcframework-sentryobjc.yml (custom assembly)
      downloads sentry-static + sentryobjc-bridge + sentryobjc-objc slices
      libtool + swiftc per SDK → SentryObjC.xcframework

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

Labels

ready-to-merge Use this label to trigger all PR workflows

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Create an ObjC SDK

2 participants