Skip to content

[RUM-18631] Consume dd-sdk-ios through Swift Package Manager - #1455

Open
saraSr5 wants to merge 24 commits into
developfrom
sara/RUM-18631/spm-migration
Open

saraSr5 wants to merge 24 commits into
developfrom
sara/RUM-18631/spm-migration

Conversation

@saraSr5

@saraSr5 saraSr5 commented Sep 29, 2026 •

Copy link
Copy Markdown

What does this PR do?

Builds on @sbarrio's sbarrio/test/spm-dependency-support spike and validates it end to end.

The native iOS SDK is now resolved through Swift Package Manager via React Native's spm_dependency helper, replacing the seven dd-sdk-ios pods. All three sample apps build and run with no Datadog* CocoaPods installed: example (old arch, SDK confirmed live in console), example-new-architecture (Fabric, RN 0.76.9) and benchmarks.

Three fixes on top of the spike:

React-RCTText missing from the session replay podspec. RCTTextExtractor.mm references the RCTText classes directly, but the dependency was only declared on the test spec. Static linking deferred the undefined symbols to the app link and hid it; dynamic linking, which SPM resolution requires, exposes it. Pre-existing bug, surfaced not caused by this change.

Duplicate OpenTelemetryApi module in benchmarks. DatadogTrace resolves opentelemetry-swift-core through SwiftPM while the Podfile pulled OpenTelemetry-Swift-Sdk from CocoaPods, so two copies entered the build and the module scanner warned across every target touching it. Both products now come from the same SwiftPM package.

Native test suites restored. The spike dropped the test_spec blocks, orphaning 18 test files and breaking the three CI jobs that run xcodebuild … test. The stated blockers did not hold: no test uses anything DD_SDK_COMPILED_FOR_TESTING guards (and its injection was broken anyway — targets.detect returns one target, not six), and @testable resolves against SwiftPM modules unchanged. The only real breakage was 16 files using Date/URL/URLRequest without importing Foundation, which used to arrive transitively through the CocoaPods modules. Session replay and webview also link DatadogInternal explicitly, since their tests reference its protocol descriptors and it is not one of the SPM products those pods request. Now at 184 tests in core on both architectures, plus session replay and webview.

Motivation

RUM-18631. The CocoaPods & Carthage deprecation RFC gates stopping publication of dd-sdk-ios to Trunk on React Native having an SPM path, as the last consumer without one. This shows it exists today, with no changes required in dd-sdk-ios.

Only the native SDK changes. React Native and our wrapper pods still install through CocoaPods, resolved from node_modules via autolinking — a path Trunk going read-only does not affect.

Additional Notes

Two calls for a reviewer:

  • No dual path for RN < 0.75. The podspecs raise instead of falling back to s.dependency, but all four packages still declare react-native: ">=0.63.4 <1.0", so a user on RN 0.72 installs cleanly from npm and only fails at pod install. If the raise stays, that range should become >=0.75.0 <1.0 — a breaking change
  • ~25 lines of SPM scaffolding duplicated across the four podspecs. No shared .rb: each package publishes only its own directory to npm, so require_relative across packages breaks once installed. The require.resolve pattern would work, but two satellite packages do not declare @datadog/mobile-react-native in package.json.

Requires dynamic linking, which the sample Podfiles now set unconditionally. DatadogInternal is still reached through an explicit FRAMEWORK_SEARCH_PATHS entry into PackageFrameworks/; a proper @_spi(Internal) surface is separate, larger work.

Review checklist

  • Feature or bugfix MUST have appropriate tests
  • Make sure you discussed the feature or bugfix with the maintaining team in an Issue
  • Make sure each commit and the PR mention the Issue number (cf the CONTRIBUTING doc)
  • If this PR is auto-generated, please make sure also to manually update the code related to the change

@datadog-prod-us1-3

datadog-prod-us1-3 Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

Pipelines  Tests

⏳ PR checks are still running. This summary will update when all results arrive.

🎉 All green!

🧪 All tests passed

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: 619d526 | Docs | View more details | Give us feedback!

@saraSr5

saraSr5 commented Sep 29, 2026

Copy link
Copy Markdown
Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

@saraSr5
saraSr5 marked this pull request as ready for review September 29, 2026 14:55
@saraSr5
saraSr5 requested a review from a team as a code owner September 29, 2026 14:55
Copilot AI balanced review requested due to automatic review settings September 29, 2026 14:55

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

Session Replay asset lookup breaks under dynamic linkage, and the advertised React Native support range and internal native test target remain unresolved.

Review effort: Balanced
Findings: 1 High severity · 2 Medium severity · 1 Low severity

Open (4)
What changed in this PR

This PR moves the React Native wrapper’s native iOS SDK dependencies from CocoaPods to Swift Package Manager, supporting the planned end of CocoaPods publication for dd-sdk-ios.

Changes:

  • Replace native SDK pod dependencies with Swift Package Manager products and update the three sample apps for dynamic framework linkage.
  • Restore native test targets and add imports and link settings needed by the new dependency layout.
  • Adjust Session Replay resources, WebView headers, and benchmark OpenTelemetry dependencies.
File Description
packages/​react-native-webview/​ios/​Sources/​RCTDatadogWebViewManager.h Supports framework header imports.
packages/​react-native-webview/​ios/​Sources/​RCTDatadogWebView.h Supports framework header imports.
packages/​react-native-webview/​ios/​Sources/​DatadogSDKReactNativeWebView.h Supports framework header imports.
packages/​react-native-webview/​DatadogSDKReactNativeWebView.podspec Requests the native Swift package product.
packages/​react-native-session-replay/​ios/​Tests/​RCTTextViewRecorderTests.swift Imports Foundation explicitly.
packages/​react-native-session-replay/​ios/​Tests/​DdSessionReplayTests.swift Imports Foundation explicitly.
packages/​react-native-session-replay/​ios/​Sources/​Utils/​Bundle+SessionReplay.swift Adapts asset-bundle lookup.
packages/​react-native-session-replay/​DatadogSDKReactNativeSessionReplay.podspec Updates resources and Swift package linkage.
packages/​internal-testing-tools/​DatadogInternalTesting.podspec Requests DatadogCore through SwiftPM.
packages/​core/​ios/​Tests/​RUMMocks.swift Imports Foundation explicitly.
packages/​core/​ios/​Tests/​RNDdSdkConfigurationTests.swift Imports Foundation explicitly.
packages/​core/​ios/​Tests/​ModulesTest.swift Imports Foundation explicitly.
packages/​core/​ios/​Tests/​MockRUMMonitor.swift Imports Foundation explicitly.
packages/​core/​ios/​Tests/​MockDatadogCore.swift Imports Foundation explicitly.
packages/​core/​ios/​Tests/​GlobalStateTests.swift Imports Foundation explicitly.
packages/​core/​ios/​Tests/​DdTraceTests.swift Imports Foundation explicitly.
packages/​core/​ios/​Tests/​DdSdkTests.swift Imports Foundation explicitly.
packages/​core/​ios/​Tests/​DdSdkSessionStartedListenerTests.swift Imports Foundation explicitly.
packages/​core/​ios/​Tests/​DdSdkNativeInitializationTests.swift Imports Foundation explicitly.
packages/​core/​ios/​Tests/​DdRumTests.swift Imports Foundation explicitly.
packages/​core/​ios/​Tests/​DdLogsTests.swift Imports Foundation explicitly.
packages/​core/​ios/​Tests/​DdFlagsTests.swift Imports Foundation explicitly.
packages/​core/​ios/​Tests/​DatadogSdkWrapperTests.swift Imports Foundation explicitly.
packages/​core/​ios/​Tests/​AnyEncodableTests.swift Imports Foundation explicitly.
packages/​core/​DatadogSDKReactNative.podspec Replaces native pods with SwiftPM products.
example/​ios/​Podfile.lock Records the revised pod graph.
example/​ios/​Podfile Enables dynamic frameworks.
example/​ios/​ddSdkReactnativeExample/​PrivacyInfo.xcprivacy Reorders existing privacy entries.
example/​ios/​DdSdkReactNativeExample.xcworkspace/​xcshareddata/​swiftpm/​Package.resolved Pins Swift packages.
example/​ios/​DdSdkReactNativeExample.xcodeproj/​project.pbxproj Updates framework linkage and header paths.
example-new-architecture/​ios/​Podfile.lock Records the revised pod graph.
example-new-architecture/​ios/​Podfile Enables dynamic frameworks.
example-new-architecture/​ios/​DdSdkReactNativeExample/​PrivacyInfo.xcprivacy Reorders existing privacy entries.
example-new-architecture/​ios/​DdSdkReactNativeExample.xcworkspace/​xcshareddata/​swiftpm/​Package.resolved Pins Swift packages.
example-new-architecture/​ios/​DdSdkReactNativeExample.xcodeproj/​project.pbxproj Updates framework linkage and header paths.
benchmarks/​ios/​Podfile.lock Removes native SDK and OpenTelemetry pods.
benchmarks/​ios/​Podfile Enables dynamic frameworks and removes the OpenTelemetry pod.
benchmarks/​ios/​BenchmarkRunner/​PrivacyInfo.xcprivacy Reorders existing privacy entries.
benchmarks/​ios/​BenchmarkRunner.xcworkspace/​xcshareddata/​swiftpm/​Package.resolved Pins Swift packages.
benchmarks/​ios/​BenchmarkRunner.xcodeproj/​project.pbxproj Links OpenTelemetry Swift package products.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread packages/core/DatadogSDKReactNative.podspec
Comment thread packages/internal-testing-tools/DatadogInternalTesting.podspec Outdated
Comment thread packages/core/DatadogSDKReactNative.podspec Outdated
@saraSr5
saraSr5 marked this pull request as draft September 29, 2026 15:08
@saraSr5
saraSr5 marked this pull request as ready for review September 29, 2026 15:14
@sbarrio
sbarrio self-requested a review September 30, 2026 07:10
…ls test spec

The webview podspec only requested DatadogWebViewTracking via spm_dependency, relying on
FRAMEWORK_SEARCH_PATHS to make DatadogInternal importable. That's enough to compile against it,
but not to link it: unlike DatadogCore and DatadogSessionReplay, DatadogWebViewTracking's own
autolink metadata doesn't pull DatadogInternal onto this target's link line, so
RCTDatadogWebViewTracking.swift's direct references to it were left unresolved at link time.
Verified with a full DerivedData wipe + clean build, not just a retry.

Also documents the missing use_frameworks! :linkage => :dynamic requirement in the core,
session-replay, and webview READMEs, and restores internal-testing-tools' test spec following
the same pattern as the other three packages -- though unlike those, it could not be verified
against a real build: no app in this repo installs this pod, and a local CocoaPods/Xcode
compatibility issue corrupts Pods.xcodeproj when adding it as a fourth SPM-consuming target.
Copilot AI balanced review requested due to automatic review settings September 30, 2026 07:38
@saraSr5
saraSr5 requested a review from a team as a code owner September 30, 2026 07:38

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot review overview

🔵 Needs a closer look

The cross-package linkage migration has an unresolved benchmark target dependency issue, and its tvOS path remains unverified.

Review effort: Balanced
Findings: 1 Low severity

Open (1)
Resolved since last review (3)
Previously missed (1)

In code that hasn't changed since last review

Medium severity Declare OpenTelemetry products as BenchmarkRunner dependencies

benchmarks/​ios/​BenchmarkRunner.xcodeproj/​project.pbxproj:21

The two OpenTelemetry products have framework-phase entries and a project-level package reference, but the BenchmarkRunner target has no packageProductDependencies list (its target definition is at lines 164–184). Xcode needs the product IDs on the target to establish its package build dependencies; otherwise clean builds may fail to resolve or link the Swift imports. Add 10520E8B306BAEDB00BBFBFF (OpenTelemetryApi) and 10520E8D306BAEDB00BBFBFF (OpenTelemetrySdk) to BenchmarkRunner's packageProductDependencies, while retaining their framework-phase entries.

…cies

The Frameworks build phase and the project's packageReferences already referenced
OpenTelemetryApi/OpenTelemetrySdk, but the BenchmarkRunner PBXNativeTarget itself never listed
them in packageProductDependencies -- the field Xcode actually uses to resolve and order the
package build. Verified with a full DerivedData wipe.
Copilot AI balanced review requested due to automatic review settings September 30, 2026 08:31

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot review overview

🔵 Needs a closer look

The cross-package linking migration leaves tvOS unverified, and the restored internal-testing subspec is not run by an iOS test host.

Review effort: Balanced
Findings: 1 Low severity

Open (1)
Previously missed (2)

In code that hasn't changed since last review

Medium severity Update tvOS dependency compatibility test and verify framework resolution

packages/​core/​DatadogSDKReactNative.podspec:39

The core pod still supports tvOS, but this change requests DatadogWebViewTracking on tvOS too. ios/Tests/TvOSCompatibilityTests.swift:10-15 still says that product is unavailable there and cites the removed s.ios.dependency; its source-guard checks do not exercise SwiftPM resolution or linking. Please update the test's stated contract and verify a tvOS install/build (or keep the dependency platform-specific) before relying on that test for tvOS compatibility.

Medium severity Run restored internal testing subspec regression tests in CI

packages/​internal-testing-tools/​DatadogInternalTesting.podspec:45

Restoring this Tests subspec does not yet run its logging regression test. Neither example Podfile selects DatadogInternalTesting/Tests, the generated sample lockfiles omit the pod, and the iOS CI test jobs only run the core and Session Replay schemes. Add the subspec to an iOS test host and run its test scheme in CI so DdInternalTestingTests.swift is compiled and executed.

Copilot AI balanced review requested due to automatic review settings September 30, 2026 09:25

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot review overview

🔵 Needs a closer look

The migration relies on internal SwiftPM framework paths, and end-to-end tvOS linkage remains unverified.

Review effort: Balanced
Findings: 1 Low severity

Open (1)

@saraSr5

saraSr5 commented Sep 30, 2026

Copy link
Copy Markdown
Author

Copilot review overview

🔵 Needs a closer look

The migration relies on internal SwiftPM framework paths, and end-to-end tvOS linkage remains unverified.

Review effort: Balanced Findings: 1 Low severity

Open (1)

Quick update on this and the tvOS thread from before:

Linkage docs: added. The core, session-replay, and webview READMEs now mention use_frameworks! :linkage => :dynamic. This thread is anchored to the podspec line, so it's probably still showing open even though the docs are there.

tvOS: fixed the stale comment. I also tried checking if DatadogWebViewTracking itself still builds for tvOS and it does. What I couldn't check is whether our pod builds for tvOS end to end, as far as I can tell, mainline React Native 0.76.9 doesn't declare tvOS support at all here, so I'm not sure it's even possible without switching to react-native-tvos.

@sbarrio do you know if there's a way to test this that I'm missing? Happy to run it if so.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔵 Needs a closer look

The custom CocoaPods embedding hook and Release/archive runtime linking require final native-iOS human validation.

3 open issues

Review effort: Balanced

Copilot AI balanced review requested due to automatic review settings October 21, 2026 14:06

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔵 Needs a closer look

The local SDK override still installs native CocoaPods modules alongside the newly unconditional remote Swift package dependencies.

3 open issues
1 previously missed issue

In code that hasn't changed since last review

Medium severity Avoid mixing local Datadog pods with remote SPM SDK

packages/​core/​DatadogSDKReactNative.podspec:108

Setting DD_NATIVE_IOS_SDK_PATH in example/ios/PodfileForSRTests:18–27 still installs the native Datadog pods from a local checkout. This unconditional remote SPM dependency, and Session Replay's equivalent, now resolve the released SDK independently of those pods. The override therefore brings both SDK distributions into the build instead of selecting only the local checkout. Migrate the override to a local Swift package and remove its native pod declarations so session-replay testing uses a single SDK source.

Review effort: Balanced

Copilot AI balanced review requested due to automatic review settings October 26, 2026 09:06

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

Mixed-linkage target detection and the local native-SDK override still introduce dependency conflicts.

4 open issues
1 previously missed issue

In code that hasn't changed since last review

Medium severity Prevent duplicate native SDK dependencies in local Session Replay tests

packages/​core/​DatadogSDKReactNative.podspec:149

When DD_NATIVE_IOS_SDK_PATH is set, example/ios/PodfileForSRTests:20–30 still installs the native SDK through local CocoaPods declarations, while this unconditional SwiftPM dependency resolves the pinned release. This introduces duplicate native modules instead of making the wrappers use only the requested checkout. Migrate the fixture's override to a local Swift package and remove its native-pod declarations, coordinating the core and Session Replay package registrations.

Review effort: Balanced

Comment thread packages/react-native-session-replay/DatadogSDKReactNativeSessionReplay.podspec Outdated
Copilot AI balanced review requested due to automatic review settings October 26, 2026 11:10

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

Unresolved linking, framework-embedding, and local-SDK override issues can break consumer builds or package the wrong SDK artifacts.

4 open issues
2 previously missed issues

In code that hasn't changed since last review

Medium severity Declare framework copies as embed phase dependencies

packages/​core/​DatadogSDKReactNative.podspec:117

These framework copies are added to the script but not to the embed phase's input/output file lists. Xcode can therefore skip the phase when only an SPM framework changes or its embedded copy is missing, leaving a stale or missing framework in the app. Register the additional sources and destinations as build dependencies, or use a separate embedding phase with its own dependency declarations.

Medium severity Avoid installing duplicate local and remote SDK dependencies

packages/​core/​DatadogSDKReactNative.podspec:149

When DD_NATIVE_IOS_SDK_PATH is set, example/ios/PodfileForSRTests:20–29 still installs eight native Datadog pods, while this call unconditionally requests the remote Swift package. That installs both SDK copies rather than replacing the dependency with the local checkout, introducing duplicate modules and making local-SDK testing unreliable. Migrate the override to a SwiftPM local-package workflow or remove the obsolete CocoaPods override.

1 resolved since last review

Review effort: Balanced

# requests all of their products, and the others keep only the package reference and the
# include path they compile against.
def datadog_request_static_products_from_core(installer)
core = installer.pod_targets.find { |pod| pod.name == 'DatadogSDKReactNative' }
Copilot AI balanced review requested due to automatic review settings October 26, 2026 11:19

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

The local-SDK override installs conflicting dependency graphs, and mixed-linkage Podfiles can apply incorrect framework linker settings to internal tests.

5 open issues
1 previously missed issue

In code that hasn't changed since last review

Medium severity Derive testing framework linkage from consuming targets

packages/​internal-testing-tools/​DatadogInternalTesting.podspec:23

This becomes true when any unrelated target uses dynamic frameworks, even if the target consuming DatadogInternalTesting and its tests uses static linkage. The test spec then receives -framework DatadogInternal, but the static core path incorporates DatadogInternal into its archive rather than producing that framework, introducing a framework-not-found linker failure. Derive this setting from the actual consuming pod target instead of all Podfile target definitions.

Review effort: Balanced

Comment on lines +147 to +149
spm_dependency(s,
url: datadog_ios_spm_url,
requirement: { kind: 'exactVersion', version: datadog_ios_version },
Copilot AI balanced review requested due to automatic review settings October 26, 2026 13:22

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔵 Needs a closer look

Custom archive rewriting and framework embedding need human validation across supported Xcode versions, architectures, and linkage modes.

5 open issues
1 resolved since last review

Review effort: Balanced

Comment thread packages/core/DatadogSDKReactNative.podspec Outdated
Copilot AI balanced review requested due to automatic review settings October 26, 2026 14:07

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

Universal static archive reassembly breaks when build paths contain spaces, as confirmed by a focused shell check.

5 open issues
1 resolved since last review

Review effort: Balanced

Comment thread packages/core/DatadogSDKReactNative.podspec Outdated
Copilot AI balanced review requested due to automatic review settings October 26, 2026 14:26

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔵 Needs a closer look

Global build hooks, binary archive rewriting, and custom framework embedding require human validation across linkage modes and Release/archive builds.

4 open issues
1 previously missed issue

In code that hasn't changed since last review

Medium severity Prevent generic asset filenames from colliding in app resource bundles

packages/​react-native-session-replay/​DatadogSDKReactNativeSessionReplay.podspec:49

With default static linkage, s.resources copies these generically named files into the app's root resource bundle, where they collide with any app resources also named assets.json or assets.bin. This can cause duplicate-output build failures or overwrite an asset; the previous DDSessionReplay.bundle kept these names isolated. Preserve a namespaced container, or use Datadog-specific filenames and update the asset generators and Swift lookups together.

1 resolved since last review

Review effort: Balanced

This branch has not been deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants