Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
74600ce
feat(objc): Add SentryObjC wrapper SDK and API stability tracking
philprime Mar 4, 2026
2df1ab3
docs(objc): Add comprehensive documentation to SentryObjC wrapper SDK
philprime Mar 10, 2026
bb4bcf2
docs(objc): Document additional SentryObjC data model classes
philprime Mar 10, 2026
50e07e7
docs(objc): Document stack traces and event metadata classes
philprime Mar 10, 2026
2ac98e0
docs(objc): Document session replay and sampling classes
philprime Mar 10, 2026
434212c
wip
philprime Mar 10, 2026
4074c02
ci: Remove file-existence check for sdk_objc_api.json
philprime Mar 10, 2026
59fa2dc
docs(samples): Restore problem description in ObjC-NoModules README
philprime Mar 10, 2026
0e7e483
Merge branch 'main' into philprime/objc-wrapper-sdk-6342
philprime Mar 10, 2026
7b315e6
ref(objc): Rewrite API extraction using clang AST and bash
philprime Mar 10, 2026
96cd092
ci: Add iOS-ObjectiveCpp-NoModules sample to build matrix
philprime Mar 10, 2026
16d4dea
update public API
philprime Mar 10, 2026
bf8a253
Merge branch 'main' into philprime/objc-wrapper-sdk-6342
philprime Mar 10, 2026
e5e4882
feat(objc): Add SentryObjC product to Swift 6.1 package manifest
philprime Mar 10, 2026
ba08e46
docs(objc): Add missing documentation to 9 SentryObjC headers
philprime Mar 10, 2026
33dd2c7
fix(objc): Add SentryCppHelper to Swift 6.1 compile-from-source targets
philprime Mar 10, 2026
e4b4486
feat(objc): Implement SentrySDK wrapper for no-modules context
philprime Mar 10, 2026
913cdfd
fix(objc): Keep SentryCppHelper in initial targets array
philprime Mar 10, 2026
e1eebdf
ref(objc): Rename SentrySDK to SentryObjCSDK to avoid naming conflicts
philprime Mar 10, 2026
97f6f13
WIP
philprime Mar 10, 2026
ab571ff
Merge remote-tracking branch 'origin/main' into philprime/objc-wrappe…
philprime Mar 10, 2026
7a81302
WIP
philprime Mar 10, 2026
56bdb7c
WIP
philprime Mar 10, 2026
5cc3e0d
fix(objc): Add explicit @objc name to SentryObjCBridge
philprime Mar 10, 2026
e2a7aa0
fix(objc): Fix thread safety, replay API, and package manifest issues
philprime Mar 10, 2026
6ee408f
WIP
philprime Mar 10, 2026
82bdd16
Merge remote-tracking branch 'origin/main' into philprime/objc-wrappe…
philprime Mar 11, 2026
cff540f
fix(objc): Fix SentryObjC package resolution and CI failures
philprime Mar 11, 2026
8e6c132
Merge branch 'main' into philprime/objc-wrapper-sdk-6342
philprime Mar 11, 2026
5c6380c
ref: Extract getAppStartMeasurement into SentryAppStartMeasurementPro…
philipphofmann Mar 11, 2026
f4293bc
revert: Remove thread safety changes extracted to PR #7672
philprime Mar 11, 2026
9e207fa
fix(objc): Address critical review bot feedback
philprime Mar 11, 2026
1b9dab0
Merge remote-tracking branch 'origin/main' into philprime/objc-wrappe…
philprime Mar 11, 2026
9ecf30b
update sdk json
philprime Mar 11, 2026
74f68ad
update submodule
philprime Mar 11, 2026
beb048f
wip
philprime Mar 11, 2026
2d3b0ce
Merge branch 'main' into philprime/objc-wrapper-sdk-6342
philprime Mar 12, 2026
34ccdb8
Merge remote-tracking branch 'origin/main' into philprime/objc-wrappe…
philprime Mar 17, 2026
91d834c
ref: rename SentryObjC core headers to match SDK naming
philprime Mar 18, 2026
4b6bc65
ref: rename SentryObjC user and context headers
philprime Mar 18, 2026
42bf54e
ref: rename SentryObjC exception and stack headers
philprime Mar 18, 2026
0d1d853
ref: rename SentryObjC tracing headers
philprime Mar 18, 2026
e5e8c71
ref: rename remaining SentryObjC headers
philprime Mar 18, 2026
3b6f320
ref: update umbrella header imports to new names
philprime Mar 18, 2026
e479465
ref: update cross-header imports to new names
philprime Mar 18, 2026
fc356b3
ref: rename SentryObjCSDK class to SentrySDK
philprime Mar 18, 2026
dad81ef
build: update add-sentryobjc-target.rb to include bridge and Sentry d…
philprime Mar 18, 2026
6336858
build: add SentryObjC variant to xcframework build script
philprime Mar 18, 2026
8d92c5e
ref: rename SentryObjC implementation files
philprime Mar 18, 2026
22824e5
ref: rename SentryObjC class and type names
philprime Mar 18, 2026
d44c00f
fix: disambiguate SentryAttributeContent in Swift bridge
philprime Mar 18, 2026
fc4682e
build: move SentryObjCBridge to Sentry target
philprime Mar 18, 2026
acd8515
WIP
philprime Mar 20, 2026
abcc681
build: standalone SentryObjC xcframework via swiftc
philprime Mar 20, 2026
16f9238
feat: add new public headers for Sentry logging and envelope handling
philprime Mar 20, 2026
143a0d6
build: update framework handling in xcframework build script
philprime Mar 20, 2026
6189f81
ci: add SentryObjC xcframework to CI pipeline
philprime Mar 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/file-filters.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,13 @@ run_api_stability_for_prs: &run_api_stability_for_prs
- "scripts/build-xcframework-slice.sh"
- "scripts/assemble-xcframework.sh"
- "scripts/update-api.sh"
- "scripts/extract-objc-api.sh"
- "scripts/ci-diagnostics.sh"

# API files
- "sdk_api.json"
- "sdk_api_sentryswiftui.json"
- "sdk_api_objc.json"

# Build configuration
- "Makefile"
Expand Down
13 changes: 13 additions & 0 deletions .github/workflows/api-stability.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ jobs:
run: |
mv sdk_api.json sdk_api_base.json
mv sdk_api_sentryswiftui.json sdk_api_sentryswiftui_base.json
mv sdk_api_objc.json sdk_api_objc_base.json
./scripts/update-api.sh

- name: Diagnose breaking changes for Sentry
Expand Down Expand Up @@ -87,6 +88,18 @@ jobs:
cat sentryswiftui_result.json
exit 1
fi

- name: Diagnose breaking changes for SentryObjC
if: always()
run: |
if diff -q "sdk_api_objc_base.json" "sdk_api_objc.json" > /dev/null; then
echo "No SentryObjC API changes detected."
else
echo "❌ SentryObjC public API changes are detected. If they're intended run "make generate-public-api" and commit the changes."
diff "sdk_api_objc_base.json" "sdk_api_objc.json" || true
exit 1
fi

- name: Run CI Diagnostics
if: failure()
run: ./scripts/ci-diagnostics.sh
Expand Down
146 changes: 146 additions & 0 deletions .github/workflows/assemble-xcframework-sentryobjc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
name: Assemble SentryObjC XCFramework

on:
workflow_call:
inputs:
sdks:
description: |-
Comma-separated list of SDK slices to assemble.
required: false
type: string
default: "iphoneos,iphonesimulator,macosx,maccatalyst,appletvos,appletvsimulator,watchos,watchsimulator,xros,xrsimulator"

signed:
description: |-
Whether or not the assembled XCFramework should be signed.
required: false
type: boolean
default: false

release-version:
description: |-
For release workflows, the version to inject into the SDK.
required: false
type: string

jobs:
assemble-xcframework-sentryobjc:
name: SentryObjC
runs-on: macos-15
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- run: ./scripts/ci-select-xcode.sh 16.4
shell: bash

- name: Setup Ruby
uses: ruby/setup-ruby@4eb9f110bac952a8b68ecf92e3b5c7a987594ba6 # v1.292.0
if: ${{ inputs.signed }}
with:
bundler-cache: true

- name: "Download Fastlane Certificate"
if: ${{ inputs.signed }}
run: bundle exec fastlane prepare_xcframework_signing
env:
FASTLANE_KEYCHAIN_PASSWORD: ${{ secrets.FASTLANE_KEYCHAIN_PASSWORD }}
MATCH_GIT_PRIVATE_KEY: ${{ secrets.MATCH_GIT_PRIVATE_KEY }}
MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
MATCH_USERNAME: ${{ secrets.MATCH_USERNAME }}

# Download all three sets of static library slices.
# Each artifact contains a {sdk}.xcarchive.zip for one platform.
- name: Download Sentry static slices
uses: actions/download-artifact@v8
with:
pattern: xcframework-sentry-static-slice-*
path: xcframework-slices/sentry-static

- name: Download SentryObjCBridge slices
uses: actions/download-artifact@v8
with:
pattern: xcframework-sentryobjc-bridge-slice-*
path: xcframework-slices/sentryobjc-bridge

- name: Download SentryObjC slices
uses: actions/download-artifact@v8
with:
pattern: xcframework-sentryobjc-objc-slice-*
path: xcframework-slices/sentryobjc-objc

# Unzip slices into the directory layout expected by
# build-xcframework-sentryobjc-standalone.sh:
# XCFrameworkBuildPath/archive/Sentry/{sdk}.xcarchive/...
# XCFrameworkBuildPath/archive/SentryObjCBridge/{sdk}.xcarchive/...
# XCFrameworkBuildPath/archive/SentryObjC/{sdk}.xcarchive/...
- name: Arrange slice archives
shell: bash
env:
SDKS: ${{ inputs.sdks }}
run: |
set -euo pipefail
mkdir -p XCFrameworkBuildPath/archive

arrange_slices() {
local variant_id="$1"
local slice_dir="$2"
local archive_name="$3"

IFS=',' read -r -a sdk_list <<< "$SDKS"
for sdk in "${sdk_list[@]}"; do
artifact_dir="${slice_dir}/xcframework-${variant_id}-slice-${sdk}"
zip_file=$(find "$artifact_dir" -name "*.xcarchive.zip" -type f | head -1)
if [ -z "$zip_file" ]; then
echo "ERROR: No xcarchive.zip found in $artifact_dir"
exit 1
fi
# Unzip into a temp location, then move the xcarchive into place
unzip_dir="/tmp/sentryobjc-unzip-${variant_id}-${sdk}"
rm -rf "$unzip_dir"
mkdir -p "$unzip_dir"
unzip -q "$zip_file" -d "$unzip_dir"
# The zip contains {sdk}.xcarchive/ (created with --keepParent)
mkdir -p "XCFrameworkBuildPath/archive/${archive_name}"
mv "$unzip_dir/${sdk}.xcarchive" "XCFrameworkBuildPath/archive/${archive_name}/${sdk}.xcarchive"
rm -rf "$unzip_dir"
done
}

arrange_slices "sentry-static" "xcframework-slices/sentry-static" "Sentry"
arrange_slices "sentryobjc-bridge" "xcframework-slices/sentryobjc-bridge" "SentryObjCBridge"
arrange_slices "sentryobjc-objc" "xcframework-slices/sentryobjc-objc" "SentryObjC"

echo "Archive layout:"
find XCFrameworkBuildPath/archive -maxdepth 3 -type d | head -30

- name: Link and assemble SentryObjC XCFramework
env:
SDKS: ${{ inputs.sdks }}
run: ./scripts/build-xcframework-sentryobjc-standalone.sh "$SDKS"
shell: bash

- name: Validate XCFramework structure
run: ./scripts/validate-xcframework-format.sh "SentryObjC.xcframework"
shell: bash

- name: Zip XCFramework
env:
SIGNED: ${{ inputs.signed }}
run: |
if [ "$SIGNED" = "true" ]; then
./scripts/compress-xcframework.sh --sign SentryObjC
else
./scripts/compress-xcframework.sh --not-signed SentryObjC
fi
shell: bash

- name: Upload XCFramework
uses: actions/upload-artifact@v7
with:
overwrite: true
name: xcframework-${{github.sha}}-sentryobjc
if-no-files-found: error
path: SentryObjC.xcframework.zip

- name: Run CI Diagnostics
if: failure()
run: ./scripts/ci-diagnostics.sh
17 changes: 14 additions & 3 deletions .github/workflows/build-xcframework-variant-slices.yml
Original file line number Diff line number Diff line change
Expand Up @@ -100,16 +100,27 @@ jobs:
run: ./scripts/build-xcframework-slice.sh "$MATRIX_SDK" "$INPUT_NAME" "$INPUT_SUFFIX" "$INPUT_MACHO_TYPE" "$INPUT_CONFIG_SUFFIX"
shell: bash

# The SentrySwiftUI archive build also builds Sentry.framework as a byproduct of the dependency. We need to remove that to avoid downstream assembly tasks from tripping on these extra files. In the future we could investigate using this byproduct instead of running a separate task for Sentry.framework, or use the one already built by that other task instead of rebuilding it here.
- name: Remove Sentry.framework from SentrySwiftUI build
if: inputs.name == 'SentrySwiftUI'
# Targets that depend on Sentry also build Sentry.framework as a byproduct.
# Remove it to avoid downstream assembly tasks from tripping on extra files.
- name: Remove Sentry.framework byproduct
if: inputs.name == 'SentrySwiftUI' || inputs.name == 'SentryObjCBridge' || inputs.name == 'SentryObjC'
env:
GITHUB_WORKSPACE: ${{ github.workspace }}
run: |
find "$GITHUB_WORKSPACE/XCFrameworkBuildPath/archive" -name "Sentry.framework" -print0 | xargs -t0 rm -rf
find "$GITHUB_WORKSPACE/XCFrameworkBuildPath/archive" -name "Sentry.framework.dSYM" -print0 | xargs -t0 rm -rf
shell: bash

# SentryObjC depends on SentryObjCBridge, which gets built as a byproduct.
- name: Remove SentryObjCBridge.framework byproduct
if: inputs.name == 'SentryObjC'
env:
GITHUB_WORKSPACE: ${{ github.workspace }}
run: |
find "$GITHUB_WORKSPACE/XCFrameworkBuildPath/archive" -name "SentryObjCBridge.framework" -print0 | xargs -t0 rm -rf
find "$GITHUB_WORKSPACE/XCFrameworkBuildPath/archive" -name "SentryObjCBridge.framework.dSYM" -print0 | xargs -t0 rm -rf
shell: bash

# the upload action broke symlinks in the mac sdk slice's xcarchive
- name: Zip xcarchive
env:
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@ jobs:
config: Debug
- scheme: iOS-ObjectiveC
config: Debug
- scheme: iOS-ObjectiveCpp-NoModules
config: Debug
- scheme: SPM
config: Debug
- scheme: DistributionSample
Expand Down
14 changes: 14 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,19 @@ jobs:
matrix:
variant: ${{ fromJson(needs.setup-matrix.outputs.variants) }}

assemble-sentryobjc:
needs: [files-changed, build-xcframework-variant-slices, setup-matrix]
# Run the job only for PRs with related changes or non-PR events.
if: github.event_name != 'pull_request' || needs.files-changed.outputs.run_release_for_prs == 'true'
name: Assemble SentryObjC XCFramework
uses: ./.github/workflows/assemble-xcframework-sentryobjc.yml
secrets: inherit
with:
# Only sign the XCFramework on releases
signed: ${{ github.event_name != 'pull_request' }}
release-version: ${{ github.event.inputs.version }}
sdks: ${{ needs.setup-matrix.outputs.sdk-list-string }}

validate-xcframework:
name: Validate XCFramework
runs-on: macos-15
Expand Down Expand Up @@ -414,6 +427,7 @@ jobs:
files-changed,
build-xcframework-variant-slices,
assemble-xcframework-variant,
assemble-sentryobjc,
validate-xcframework,
validate-spm,
validate-spm-dynamic,
Expand Down
7 changes: 1 addition & 6 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -105,12 +105,7 @@ Samples/watchOS-Swift/watchOS-Swift.xcodeproj
TestSamples/SwiftUICrashTest/SwiftUICrashTest.xcodeproj
TestSamples/SwiftUITestSample/SwiftUITestSample.xcodeproj

Sentry.xcframework*
Sentry-Dynamic.xcframework*
Sentry-Dynamic-WithARM64e.xcframework*
SentrySwiftUI.xcframework*
Sentry-WithoutUIKitOrAppKit.xcframework*
Sentry-WithoutUIKitOrAppKit-WithARM64e.xcframework*
*.xcframework*

current_package_diff.patch

Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## Unreleased

- Add SentryObjC wrapper SDK to provide pure Objective-C compatibility layer that wraps the main Sentry SDK with stable, documented Objective-C interfaces. (#7598)
This SDK is designed for projects that require strict Objective-C compatibility without Swift dependencies.

### Features

- Add `SentrySDK.lastRunStatus` to distinguish unknown, no-crash and crash (#7469)
Expand Down
31 changes: 28 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,31 @@ build-signed-xcframework:
build-xcframework-sample:
xcodebuild -project "Samples/XCFramework-Validation/XCFramework.xcodeproj" -configuration Release CODE_SIGNING_ALLOWED="NO" build

## Build SentryObjC framework for iOS Simulator
#
# Builds the SentryObjC framework target for iOS Simulator.
# This is the Objective-C wrapper framework that provides a stable ABI for ObjC++ consumers.
# The target must first be added to the Xcode project using: bundle exec ruby scripts/add-sentryobjc-target.rb
.PHONY: build-sentryobjc
build-sentryobjc:
@echo "--> Building SentryObjC for iOS Simulator"
set -o pipefail && xcodebuild build \
-project Sentry.xcodeproj \
-scheme SentryObjC \
-destination 'platform=iOS Simulator,OS=$(IOS_SIMULATOR_OS),name=$(IOS_DEVICE_NAME)' \
-configuration Release \
CODE_SIGNING_ALLOWED="NO" 2>&1 | xcbeautify --preserve-unbeautified

## Build SentryObjC XCFramework for distribution (iOS only)
#
# Creates SentryObjC XCFramework for iOS platforms (device + simulator).
# Uses the existing xcframework build infrastructure.
# Outputs to XCFrameworkBuildPath/SentryObjC.xcframework.
.PHONY: build-sentryobjc-xcframework
build-sentryobjc-xcframework:
@echo "--> Creating SentryObjC xcframework (iOS only)"
./scripts/build-xcframework-variant.sh SentryObjC '' mh_dylib '' iOSOnly ''

# ============================================================================
# SAMPLE APPS
# ============================================================================
Expand All @@ -230,6 +255,7 @@ build-xcframework-sample:
build-samples: \
build-sample-DistributionSample \
build-sample-iOS-ObjectiveC \
build-sample-iOS-ObjectiveCpp-NoModules \
build-sample-iOS-Swift \
build-sample-iOS-Swift6 \
build-sample-iOS-SwiftUI \
Expand Down Expand Up @@ -324,9 +350,8 @@ build-sample-visionOS-SwiftUI-SPM:

## Build the iOS-ObjectiveCpp-NoModules sample app
#
# Builds the ObjC++ without-modules sample that reproduces #4543.
# This target is expected to FAIL until the pure ObjC SDK wrapper (#6342)
# is implemented. Use it to verify the fix.
# Builds the ObjC++ without-modules sample that uses SentryObjC (#6342).
# Uses #import <SentryObjC/SentryObjC.h> for ObjC++ without -fmodules.
.PHONY: build-sample-iOS-ObjectiveCpp-NoModules
build-sample-iOS-ObjectiveCpp-NoModules:
xcodegen --spec Samples/iOS-ObjectiveCpp-NoModules/iOS-ObjectiveCpp-NoModules.yml
Expand Down
36 changes: 35 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,19 @@ targets += [
name: "SentryObjCInternal",
dependencies: ["SentrySwift"],
path: "Sources",
exclude: ["Sentry/SentryDummyPublicEmptyClass.m", "Sentry/SentryDummyPrivateEmptyClass.m", "Swift", "SentrySwiftUI", "Resources", "Configuration", "SentryCppHelper", "SentryDistribution", "SentryDistributionTests"],
exclude: [
"Sentry/SentryDummyPublicEmptyClass.m",
"Sentry/SentryDummyPrivateEmptyClass.m",
"Swift",
"SentrySwiftUI",
"Resources",
"Configuration",
"SentryCppHelper",
"SentryDistribution",
"SentryDistributionTests",
"SentryObjC",
"SentryObjCBridge"
],
cSettings: [
.headerSearchPath("Sentry"),
.headerSearchPath("SentryCrash/Recording"),
Expand All @@ -107,6 +119,28 @@ targets += [
.headerSearchPath("SentryCrash/Reporting/Filters/Tools")])
]

// Swift bridge that exposes SDK functionality to pure ObjC code (no modules)
products.append(.library(name: "SentryObjC", targets: ["SentryObjCInternal", "SentryObjCBridge", "SentryObjC"]))
targets += [
.target(
name: "SentryObjCBridge",
dependencies: ["SentryObjCInternal"],
path: "Sources/SentryObjCBridge",
swiftSettings: [
.unsafeFlags(["-enable-library-evolution"])
]),

.target(
name: "SentryObjC",
dependencies: ["SentryObjCBridge"],
path: "Sources/SentryObjC",
publicHeadersPath: "Public",
cSettings: [
.headerSearchPath("Public")
]
)
]

let package = Package(
name: "Sentry",
platforms: [.iOS(.v15), .macOS(.v10_14), .tvOS(.v15), .watchOS(.v8), .visionOS(.v1)],
Expand Down
Loading
Loading