diff --git a/.github/file-filters.yml b/.github/file-filters.yml index 26164ed47a5..efeefd3a580 100644 --- a/.github/file-filters.yml +++ b/.github/file-filters.yml @@ -77,11 +77,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" @@ -271,6 +273,7 @@ run_release_for_prs: &run_release_for_prs - ".github/workflows/release-comment-issues.yml" - ".github/workflows/build-xcframework-variant-slices.yml" - ".github/workflows/assemble-xcframework-variant.yml" + - ".github/workflows/assemble-xcframework-sentryobjc.yml" - ".github/workflows/ui-tests-common.yml" - ".github/workflows/fast-pr-checks.yml" - ".github/file-filters.yml" @@ -285,6 +288,8 @@ run_release_for_prs: &run_release_for_prs - "scripts/build-xcframework-slice.sh" - "scripts/build-xcframework-local.sh" - "scripts/assemble-xcframework.sh" + - "scripts/build-xcframework-sentryobjc-standalone.sh" + - "scripts/ci-arrange-xcframework-slices.sh" - "scripts/generate_release_matrix.sh" - "scripts/xcframework-generated-run.sh" - "scripts/prepare-package.sh" diff --git a/.github/workflows/api-stability.yml b/.github/workflows/api-stability.yml index be5516f96dc..a811a78225c 100644 --- a/.github/workflows/api-stability.yml +++ b/.github/workflows/api-stability.yml @@ -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 @@ -56,7 +57,7 @@ jobs: if diff -q "sdk_api_base.json" "sdk_api.json" > /dev/null; then echo "No Sentry API changes detected." else - echo "❌ Sentry public API changes are detected. If they're intended run "make generate-public-api" and commit the changes." + echo "❌ Sentry public API changes are detected. If they're intended run 'make generate-public-api' and commit the changes." diff "sdk_api_base.json" "sdk_api.json" || true xcrun --sdk iphoneos swift-api-digester \ -diagnose-sdk \ @@ -75,7 +76,7 @@ jobs: if diff -q "sdk_api_sentryswiftui_base.json" "sdk_api_sentryswiftui.json" > /dev/null; then echo "No SentrySwiftUI API changes detected." else - echo "❌ SentrySwiftUI public API changes are detected. If they're intended run "make generate-public-api" and commit the changes." + echo "❌ SentrySwiftUI public API changes are detected. If they're intended run 'make generate-public-api' and commit the changes." diff "sdk_api_sentryswiftui_base.json" "sdk_api_sentryswiftui.json" || true xcrun --sdk iphoneos swift-api-digester \ -diagnose-sdk \ @@ -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 uses: ./.github/actions/ci-diagnostics if: failure() diff --git a/.github/workflows/assemble-xcframework-sentryobjc.yml b/.github/workflows/assemble-xcframework-sentryobjc.yml new file mode 100644 index 00000000000..629ed4591cc --- /dev/null +++ b/.github/workflows/assemble-xcframework-sentryobjc.yml @@ -0,0 +1,136 @@ +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 + - uses: ./.github/actions/setup-xcode + with: + version: "16.4" + + - 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 four sets of static library slices. + # Each artifact contains a {sdk}.xcarchive.zip for one platform. + - name: Download Sentry static slices + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 + with: + pattern: xcframework-sentry-static-slice-* + path: xcframework-slices/sentry-static + + - name: Download SentryObjCTypes slices + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 + with: + pattern: xcframework-sentryobjc-types-slice-* + path: xcframework-slices/sentryobjc-types + + - name: Download SentryObjCBridge slices + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 + with: + pattern: xcframework-sentryobjc-bridge-slice-* + path: xcframework-slices/sentryobjc-bridge + + - name: Download SentryObjC slices + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # 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/SentryObjCTypes/{sdk}.xcarchive/... + # XCFrameworkBuildPath/archive/SentryObjCBridge/{sdk}.xcarchive/... + # XCFrameworkBuildPath/archive/SentryObjC/{sdk}.xcarchive/... + - name: Arrange slice archives + shell: bash + env: + SDKS: ${{ inputs.sdks }} + run: ./scripts/ci-arrange-xcframework-slices.sh --sdks "$SDKS" + + - name: Link and assemble SentryObjC XCFrameworks + env: + SDKS: ${{ inputs.sdks }} + run: | + sdk_args=() + IFS=',' read -r -a sdk_list <<< "$SDKS" + for s in "${sdk_list[@]}"; do sdk_args+=(--sdk "$s"); done + ./scripts/build-xcframework-sentryobjc-standalone.sh "${sdk_args[@]}" + shell: bash + + - name: Validate XCFramework structure + run: | + ./scripts/validate-xcframework-format.sh "SentryObjC-Static.xcframework" + ./scripts/validate-xcframework-format.sh "SentryObjC-Dynamic.xcframework" + shell: bash + + - name: Zip XCFrameworks + env: + SIGNED: ${{ inputs.signed }} + run: | + if [ "$SIGNED" = "true" ]; then + ./scripts/compress-xcframework.sh --sign SentryObjC-Static + ./scripts/compress-xcframework.sh --sign SentryObjC-Dynamic + else + ./scripts/compress-xcframework.sh --not-signed SentryObjC-Static + ./scripts/compress-xcframework.sh --not-signed SentryObjC-Dynamic + fi + shell: bash + + - name: Upload SentryObjC-Static XCFramework + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + with: + overwrite: true + name: xcframework-${{github.sha}}-sentryobjc-static + if-no-files-found: error + path: SentryObjC-Static.xcframework.zip + + - name: Upload SentryObjC-Dynamic XCFramework + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + with: + overwrite: true + name: xcframework-${{github.sha}}-sentryobjc-dynamic + if-no-files-found: error + path: SentryObjC-Dynamic.xcframework.zip + + - name: Run CI Diagnostics + if: failure() + run: ./scripts/ci-diagnostics.sh diff --git a/.github/workflows/build-xcframework-variant-slices.yml b/.github/workflows/build-xcframework-variant-slices.yml index 52187156c13..645a5f3cace 100644 --- a/.github/workflows/build-xcframework-variant-slices.yml +++ b/.github/workflows/build-xcframework-variant-slices.yml @@ -101,9 +101,10 @@ 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: | @@ -111,6 +112,26 @@ jobs: find "$GITHUB_WORKSPACE/XCFrameworkBuildPath/archive" -name "Sentry.framework.dSYM" -print0 | xargs -t0 rm -rf shell: bash + # SentryObjCBridge and SentryObjC depend on SentryObjCTypes, which gets built as a byproduct. + - name: Remove SentryObjCTypes.framework byproduct + if: inputs.name == 'SentryObjCBridge' || inputs.name == 'SentryObjC' + env: + GITHUB_WORKSPACE: ${{ github.workspace }} + run: | + find "$GITHUB_WORKSPACE/XCFrameworkBuildPath/archive" -name "SentryObjCTypes.framework" -print0 | xargs -t0 rm -rf + find "$GITHUB_WORKSPACE/XCFrameworkBuildPath/archive" -name "SentryObjCTypes.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: diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9039526ed06..f8b7da94fbb 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -107,6 +107,8 @@ jobs: config: Debug - scheme: iOS-ObjectiveC config: Debug + - scheme: iOS-ObjectiveCpp-NoModules + config: Debug - scheme: SPM config: Debug - scheme: DistributionSample @@ -122,6 +124,7 @@ jobs: # sample projects don't use SPM for including Sentry. Only the DistributionSample uses local SPM. # Therefore, we only keep the local DistributionSample reference in the Package.swift as a workaround. - name: Only keep distribution lib and target in Package.swift + if: matrix.scheme == 'DistributionSample' run: ./scripts/prepare-package.sh --remove-binary-targets true - name: Setup Xcode diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 63a06e4f5ab..45f33848f5f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -115,6 +115,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 @@ -451,6 +464,7 @@ jobs: files-changed, build-xcframework-variant-slices, assemble-xcframework-variant, + assemble-sentryobjc, validate-xcframework, validate-spm, validate-spm-dynamic, diff --git a/.gitignore b/.gitignore index 77ab5876bf4..0458fc01b2c 100644 --- a/.gitignore +++ b/.gitignore @@ -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 diff --git a/AGENTS.md b/AGENTS.md index f5c6a08fc77..c19e2a463cb 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -54,6 +54,11 @@ SentrySDK (public entry point) | `SentryCrash/` | C/C++ crash reporting (KSCrash fork) | | `SentryCppHelper/` | C++ helpers (backtrace, sampling profiler, thread handle) | | `SentrySwiftUI/` | SwiftUI tracing (`TracedView`) | +| `SentryObjC/` | Pure ObjC facade — behavior classes consumers invoke | +| `SentryObjCBridge/` | Swift bridge — maps `SentryObjCTypes` ⇄ internal Swift types | +| `SentryObjCTypes/` | Frozen public ObjC ABI — pure data carriers, Foundation-only | + +> **Before touching `SentryObjC*` targets** (headers, types, bridge, build config), read [`develop-docs/SENTRY-OBJC.md`](develop-docs/SENTRY-OBJC.md). It defines the four-tier architecture, type placement rules, naming conventions, and stability contract. Violations (e.g., leaking SDK types into `SentryObjCTypes`) cause linker failures or ABI breaks. ## Skills & MCP (dotagents) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e833847ca3..e7d85ba4d89 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,9 +2,14 @@ ## Unreleased +> [!IMPORTANT] +> The new SentryObjC SDK introduced in this release should be considered experimental and may be subject to breaking changes. + ### Features - Add Set conformance to SentryAttributeValue (#7876) +- 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. It ships as two xcframework variants — `SentryObjC-Static.xcframework.zip` and `SentryObjC-Dynamic.xcframework.zip` — and as a compile-from-source SPM library under the `SentryObjC` product. ## 9.12.1 diff --git a/Makefile b/Makefile index cf88f252e02..220ec15aa43 100644 --- a/Makefile +++ b/Makefile @@ -227,6 +227,44 @@ 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. +.PHONY: build-framework-objc +build-framework-objc: + @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 XCFrameworks locally for one or more SDKs +# +# Builds the four staticlib slices (Sentry, SentryObjCTypes, SentryObjCBridge, +# SentryObjC) and runs the standalone merger to produce SentryObjC-Static and +# SentryObjC-Dynamic xcframeworks. Output lands in XCFrameworkBuildPath/. +# +# SDKS accepts either an SDK preset (iOSOnly, macOSOnly, macCatalystOnly, +# AllSDKs) or a comma-separated list of SDK names. Required — no default, +# to keep local iteration fast. +# +# Examples: +# make build-sentryobjc-xcframework-local SDKS=iphonesimulator +# make build-sentryobjc-xcframework-local SDKS=iphoneos,iphonesimulator +# make build-sentryobjc-xcframework-local SDKS=iOSOnly +.PHONY: build-sentryobjc-xcframework-local +build-sentryobjc-xcframework-local: + @if [ -z "$(SDKS)" ]; then \ + echo "error: SDKS is required."; \ + echo " example: make $@ SDKS=iphonesimulator"; \ + exit 1; \ + fi + @echo "--> Creating SentryObjC xcframeworks (SDKs: $(SDKS))" + ./scripts/build-xcframework-local.sh "$(SDKS)" SentryObjCOnly + # ============================================================================ # SAMPLE APPS # ============================================================================ @@ -238,6 +276,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 \ @@ -332,9 +371,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 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 diff --git a/Package.swift b/Package.swift index bfa1c4faadb..dc282f78f93 100644 --- a/Package.swift +++ b/Package.swift @@ -96,7 +96,20 @@ 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", + "SentryObjCTypes" + ], cSettings: [ .headerSearchPath("Sentry"), .headerSearchPath("SentryCrash/Recording"), @@ -107,6 +120,41 @@ targets += [ .headerSearchPath("SentryCrash/Reporting/Filters/Tools")]) ] +// BEGIN:OBJC_WRAPPER +// Swift bridge that exposes SDK functionality to pure ObjC code (no modules) +products.append(.library(name: "SentryObjC", targets: ["SentryObjCInternal", "SentryObjCTypes", "SentryObjCBridge", "SentryObjC"])) +targets += [ + // Frozen public ObjC ABI — pure data carriers, depends only on Foundation. + // Both SentryObjCBridge and SentryObjC depend on this so they reference + // the same authoritative type declarations. + .target( + name: "SentryObjCTypes", + path: "Sources/SentryObjCTypes", + publicHeadersPath: "Public", + cSettings: [ + .headerSearchPath("Public") + ]), + .target( + name: "SentryObjCBridge", + dependencies: ["SentryObjCInternal", "SentryObjCTypes"], + path: "Sources/SentryObjCBridge"), + .testTarget( + name: "SentryObjCBridgeTests", + dependencies: ["SentryObjCBridge", "SentryObjCTypes", "SentrySwift"], + path: "Tests/SentryObjCBridgeTests"), + + .target( + name: "SentryObjC", + dependencies: ["SentryObjCInternal", "SentryObjCBridge", "SentryObjCTypes"], + path: "Sources/SentryObjC", + publicHeadersPath: "Public", + cSettings: [ + .headerSearchPath("Public") + ] + ) +] +// END:OBJC_WRAPPER + let package = Package( name: "Sentry", platforms: [.iOS(.v15), .macOS(.v10_14), .tvOS(.v15), .watchOS(.v8), .visionOS(.v1)], diff --git a/Package@swift-6.1.swift b/Package@swift-6.1.swift index 7c387095e92..db37e2fa6b4 100644 --- a/Package@swift-6.1.swift +++ b/Package@swift-6.1.swift @@ -97,7 +97,20 @@ 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", + "SentryObjCTypes" + ], cSettings: [ .headerSearchPath("Sentry"), .headerSearchPath("SentryCrash/Recording"), @@ -110,6 +123,42 @@ targets += [ ]) ] +// BEGIN:OBJC_WRAPPER +// Swift bridge that exposes SDK functionality to pure ObjC code (no modules) +products.append(.library(name: "SentryObjC", targets: ["SentryObjCInternal", "SentryObjCTypes", "SentryObjCBridge", "SentryObjC"])) +targets += [ + // Frozen public ObjC ABI — pure data carriers, depends only on Foundation. + // Both SentryObjCBridge and SentryObjC depend on this so they reference + // the same authoritative type declarations. + .target( + name: "SentryObjCTypes", + path: "Sources/SentryObjCTypes", + publicHeadersPath: "Public", + cSettings: [ + .headerSearchPath("Public") + ]), + .target( + name: "SentryObjCBridge", + dependencies: ["SentryObjCInternal", "SentryObjCTypes"], + path: "Sources/SentryObjCBridge"), + .testTarget( + name: "SentryObjCBridgeTests", + dependencies: ["SentryObjCBridge", "SentryObjCTypes", "SentrySwift"], + path: "Tests/SentryObjCBridgeTests"), + + .target( + name: "SentryObjC", + dependencies: ["SentryObjCInternal", "SentryObjCBridge", "SentryObjCTypes"], + path: "Sources/SentryObjC", + publicHeadersPath: "Public", + cSettings: [ + .headerSearchPath("Public"), + .define("SENTRY_NO_UI_FRAMEWORK", to: "1", .when(traits: ["NoUIFramework"])) + ] + ) +] +// END:OBJC_WRAPPER + let package = Package( name: "Sentry", platforms: [.iOS(.v15), .macOS(.v10_14), .tvOS(.v15), .watchOS(.v8), .visionOS(.v1)], diff --git a/Package@swift-6.2.swift b/Package@swift-6.2.swift index cc0e467d6ae..450fa02ff0c 100644 --- a/Package@swift-6.2.swift +++ b/Package@swift-6.2.swift @@ -97,7 +97,20 @@ 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", + "SentryObjCTypes" + ], cSettings: [ .headerSearchPath("Sentry"), .headerSearchPath("SentryCrash/Recording"), @@ -110,6 +123,42 @@ targets += [ ]) ] +// BEGIN:OBJC_WRAPPER +// Swift bridge that exposes SDK functionality to pure ObjC code (no modules) +products.append(.library(name: "SentryObjC", targets: ["SentryObjCInternal", "SentryObjCTypes", "SentryObjCBridge", "SentryObjC"])) +targets += [ + // Frozen public ObjC ABI — pure data carriers, depends only on Foundation. + // Both SentryObjCBridge and SentryObjC depend on this so they reference + // the same authoritative type declarations. + .target( + name: "SentryObjCTypes", + path: "Sources/SentryObjCTypes", + publicHeadersPath: "Public", + cSettings: [ + .headerSearchPath("Public") + ]), + .target( + name: "SentryObjCBridge", + dependencies: ["SentryObjCInternal", "SentryObjCTypes"], + path: "Sources/SentryObjCBridge"), + .testTarget( + name: "SentryObjCBridgeTests", + dependencies: ["SentryObjCBridge", "SentryObjCTypes", "SentrySwift"], + path: "Tests/SentryObjCBridgeTests"), + + .target( + name: "SentryObjC", + dependencies: ["SentryObjCInternal", "SentryObjCBridge", "SentryObjCTypes"], + path: "Sources/SentryObjC", + publicHeadersPath: "Public", + cSettings: [ + .headerSearchPath("Public"), + .define("SENTRY_NO_UI_FRAMEWORK", to: "1", .when(traits: ["NoUIFramework"])) + ] + ) +] +// END:OBJC_WRAPPER + let package = Package( name: "Sentry", platforms: [.iOS(.v15), .macOS(.v10_14), .tvOS(.v15), .watchOS(.v8), .visionOS(.v1)], diff --git a/Plans/Sentry_Base.xctestplan b/Plans/Sentry_Base.xctestplan index cd5fef8c64c..be2e19985ab 100644 --- a/Plans/Sentry_Base.xctestplan +++ b/Plans/Sentry_Base.xctestplan @@ -72,6 +72,14 @@ "name" : "SentryTestUtilsTests" } }, + { + "parallelizable" : false, + "target" : { + "containerPath" : "container:Sentry.xcodeproj", + "identifier" : "D4E0C0712F80000000B64C01", + "name" : "SentryObjCBridgeTests" + } + }, { "parallelizable" : false, "skippedTests" : [ diff --git a/Samples/iOS-ObjectiveC/App/Resources/Base.lproj/Main.storyboard b/Samples/iOS-ObjectiveC/App/Resources/Base.lproj/Main.storyboard index b46f141f02b..3aee06d383d 100644 --- a/Samples/iOS-ObjectiveC/App/Resources/Base.lproj/Main.storyboard +++ b/Samples/iOS-ObjectiveC/App/Resources/Base.lproj/Main.storyboard @@ -1,8 +1,9 @@ - + - + + @@ -17,13 +18,13 @@ - + -