Releases: sbokatuk/DatadogNet.iOS
Release list
3.14.0.5
What's changed
Binding-only release. The native SDK is unchanged — still
dd-sdk-ios 3.14.0 — and so are the
package ids, namespaces and API. The fourth component advances for one reason: apps using these
packages can now build for a real iPhone. Every earlier release fails its device link.
Real-device builds no longer fail to link
Building any consuming app for ios-arm64 — a physical device, any target framework — failed at
the native link with a wall of:
error : Undefined symbols for architecture arm64:
"_OBJC_CLASS_$_DDConfiguration", referenced from: in registrar.o
"_OBJC_CLASS_$_DDRUMConfiguration", referenced from: in registrar.o
...
while the identical build for the simulator linked and ran fine.
The defect is upstream, in the prebuilt archives this repository binds. dd-sdk-ios builds its
device slices with a 12.0 deployment target and its simulator slices with 14.0 (the
arm64-simulator floor) — and below iOS 13, the Swift compiler withholds static Objective-C
registration for @objc classes whose metadata needs runtime fix-ups: no _OBJC_CLASS_$_<Name>
symbol, no __objc_classlist entry. 41 classes that every simulator slice exports are simply
not there to link against in the device slices: DDConfiguration, DDSite, DDTrackingConsent
and the URLSession instrumentation types in Core; DDLogEvent; DDRUMConfiguration and all the
RUM event-model classes; DDTraceConfiguration; DDSessionReplayConfiguration. The .NET static
registrar references bound classes by exactly those names, so any app that reaches one — and
DDConfiguration is the front door — cannot link.
Every prebuilt upstream archive checked has the same asymmetry (2.30.2, 3.13.0, 3.14.0, and the
arm64e twin zips), so this is not a 3.14.0 regression and no earlier package release escapes it:
the 2.x line and 3.14.0.1–3.14.0.4 all fail device links. It went unnoticed because nothing
on either side ever linked a device build: this repository's CI was simulator-only (no longer —
see below), and upstream's consumers overwhelmingly build from source via SwiftPM/CocoaPods with
their app's own, higher deployment target. The defect is reported upstream with the full
evidence; a corrected upstream build makes this entire mechanism disappear.
The fix: generated linker aliases, plus up-front realization
The missing classes are not gone from the device binaries. Each class object is present and
exported under its Swift metadata symbol (_$s…CN) — the simulator slice exports the very same
object under both that name and the Objective-C one, at the same address. So, per affected class,
the packages now carry one linker flag:
-Wl,-alias,_$s11DatadogCore18objc_ConfigurationCN,_OBJC_CLASS_$_DDConfiguration
build/GenerateDeviceClassAliases.sh derives the table mechanically from the binaries (join the
two names on their shared address in the simulator slice; require the Swift symbol to be exported
by the device slice) and writes one committed file per framework under
build/device-class-aliases/. Datadog.Binding.props folds each file into the framework's
NativeReference as LinkerFlags, which travel inside the binding assembly — consuming apps get
the repair automatically, with no project changes.
Linking is half the story. On device those class objects start out unrealized, and messaging
unrealized Swift class metadata is not a slow path but a segfault — measured on hardware: a cold
[DDConfiguration class] crashes, while the same address realized through the class's Swift
metadata accessor (_$s…CMa) becomes a fully working, name-resolvable class. And the first such
message does not wait for app code: the static registrar's xamarin_create_classes, called from
main() before a single line of managed code, does [DDConfiguration class] for every mapped
bound class — so no managed hook (a module initializer included; tried, crashed identically) can
run early enough. The realization therefore ships as native code: each affected framework gets a
generated <Framework>Realize.xcframework, a static library whose one dyld initializer calls
the metadata accessor of every aliased class. dyld runs it after the Datadog dylibs load and
before main — exactly the window. On the simulator, where the classes are statically
registered anyway, the accessors return immediately — the path is identical on both targets and
exercised by the simulator test suites. Verified end-to-end on a physical iPhone 15 Pro Max:
install, launch, SDK initialization, and runtime name-resolution of the previously missing
classes.
Guard rails, so this cannot ship broken again
- A Mach-O symbol audit joins the package tests (
SymbolAuditTests): every class the binding
assemblies register must resolve for a device link exactly as it does for a simulator link —
exported by the device slice or covered by a shipped alias; every shipped alias must point at a
symbol the device slice actually exports and must not shadow a class the device slice has
learned to export itself; and a package that ships aliases must ship the realization library
calling exactly those classes' metadata accessors. Symbol-level checking of the native payload
existed nowhere before; the audit is what would have caught this defect at pack time. - CI now links for a real device on both bands. The release link check became a matrix —
net9.0-ios18.0andnet10.0-ios26.0— and the example app gained a net10 band
(-p:DatadogSdkBand=net10) so the newest target framework is the one exercised most. build/BumpNativeVersion.sh's checklist regenerates the aliases right after fetching new
frameworks: the Swift mangled names change with every native release, and the audit fails on
stale ones.
Upgrading from 3.14.0.4
-<PackageReference Include="DatadogNet.RUM.iOS" Version="3.14.0.4" />
+<PackageReference Include="DatadogNet.RUM.iOS" Version="3.14.0.5" />Nothing to change beyond the version: same native SDK, same API, same package set, and all
packages move together as they depend on each other at an exact version. If your app only ever
ran on the simulator, nothing visible changes; if you have been unable to build for a device,
this release is the fix.
Full changelog: v3.14.0.4...v3.14.0.5
Packages
Bound against dd-sdk-ios 3.14.0, targeting net8.0-ios18.0, net9.0-ios18.0 and net10.0-ios26.0.
The first three components of
3.14.0.5are the dd-sdk-ios version; the fourth is this
repository's binding revision, which advances when the bindings or packaging change while
the native binaries stay put.
| Package | Wraps | NuGet |
|---|---|---|
DatadogNet.Core.iOS |
DatadogCore |
3.14.0.5 |
DatadogNet.RUM.iOS |
DatadogRUM |
3.14.0.5 |
DatadogNet.Logs.iOS |
DatadogLogs |
3.14.0.5 |
DatadogNet.Trace.iOS |
DatadogTrace |
3.14.0.5 |
DatadogNet.SessionReplay.iOS |
DatadogSessionReplay |
3.14.0.5 |
DatadogNet.WebViewTracking.iOS |
DatadogWebViewTracking |
3.14.0.5 |
DatadogNet.CrashReporting.iOS |
DatadogCrashReporting |
3.14.0.5 |
DatadogNet.Flags.iOS |
DatadogFlags |
3.14.0.5 |
DatadogNet.Profiling.iOS |
DatadogProfiling |
3.14.0.5 |
DatadogNet.Internal.iOS |
DatadogInternal |
3.14.0.5 |
DatadogNet.OpenTelemetryApi.iOS |
OpenTelemetryApi |
3.14.0.5 |
DatadogNet.Objc.iOS |
(compatibility meta-package) |
3.14.0.5 |
dotnet add package DatadogNet.Core.iOS --version 3.14.0.5
dotnet add package DatadogNet.RUM.iOS --version 3.14.0.5
Licensing
The binding code is MIT; the bundled native binaries are Apache-2.0, as built and
published by Datadog. Each package ships both texts under licenses/.
3.14.0.4
What's changed
Binding-only release. The native SDK is unchanged — still
dd-sdk-ios 3.14.0 — and so are the
package ids, namespaces and API. The fourth component advances for the changes below: round two of
the ergonomics review, aimed this time at the packaging metadata, the supply chain around the
native archive, and the release machinery.
Descriptions no longer point at an empty package
Since 3.14.0.1 the RUM, Logs and Trace descriptions ended "The managed DD* API lives in
DatadogNet.Objc.iOS; this package ships the native feature" — carried over from 2.x, where the
DatadogObjc framework really did hold every DD* type, and wrong ever since 3.0 deleted it: each
package binds its own surface (RUM's ApiDefinitions.cs alone is 7,400 lines), and
DatadogNet.Objc.iOS is a dependency-only meta-package with no assembly at all. A reader on
nuget.org following that sentence installed an empty package. The descriptions now say where the
API actually is, the stale rationale comment in src/Datadog.Binding.props is rewritten to match
reality, and the package tests reject any description that makes the old claim again.
The packed README's links now work on nuget.org
The same README.md ships in every package and is rendered on each package's nuget.org page — where
its eleven repo-relative links (the sample, build/checksums.txt, the regeneration guide, the
Flags shim, the licence and friends) resolved against nuget.org and rendered as dead text. Every
repository link is absolute now; in-page anchors stay as they are, since those work everywhere the
file renders.
Checksums: trust-on-first-use replaced by GitHub's own digests
build/checksums.txt is the trust anchor for the ~200 MB native archive, but its pins were
recorded by downloading the archive and writing down whatever hash arrived — so a tampered first
download would have minted the poisoned hash as the truth. The new build/UpdateChecksums.sh
records the digest the GitHub releases API reports for the asset, computed by GitHub at upload
time, and requires a fresh download to hash to the same value before anything is written.
FetchXcFrameworks.sh additionally cross-checks the pin against the live digest before
downloading and hard-fails on a disagreement; when the API is unreachable — offline,
rate-limited — the pinned hash still guards the download, so no build grows a network dependency
it did not have. Run against 3.14.0, the published digest equals the pin recorded under the old
flow: a retroactive check the old flow could not offer.
Package validation against the published baseline
CI now holds every packed package's API to the last published release — this one's baseline is
3.14.0.3 — so an accidental API break, most plausibly a regenerated binding quietly dropping a
member, fails in CI instead of surfacing in a consumer's compiler. It runs as
build/ValidatePackageApi.sh on the merged artifacts rather than at pack time: each band's pack
pass produces an intermediate that legitimately lacks the other band's frameworks, and only the
finished package carries the framework set the baseline has. The baseline downloads from
nuget.org, so the check is CI's and an explicit local invocation's, never part of an offline
pack.
Release machinery
- A release tag must agree with
Directory.Build.props. The tag alone drives which native
line is bound, so a mistyped tag would have published packages whose version does not describe
their contents. The workflow now fails before building when the tag's native prefix or binding
revision disagrees with the props; releasing a different line on purpose remains possible
through a documented repository variable. - Upstream releases are watched. A weekly workflow compares
DatadogNativeVersionagainst
the latest dd-sdk-ios release and opens one issue — idempotently — when upstream is ahead,
linking the release and the upgrade ritual. build/BumpNativeVersion.shstarts a native upgrade in one command: props, digest-anchored
checksum pin, README badge/prose/snippets, the validation baseline, and a scaffolded
release-notes file, finishing with a self-check. The README's upgrade guide now leads with it —
and putsDiffSwiftHeaders.shbeforeFetchXcFrameworks.sh, since the previous step order
would have diffed the new release against itself.build/CheckReadmeVersions.shnow also verifies the dd-sdk-ios badge and the "Built
against" prose — the two hardcoded spots the upgrade guide used to shrug about ("nothing
else will notice when it goes stale"). Something notices.GenerateBindings.sh's usage example no longer names DatadogObjc, a framework deleted
upstream in 3.0.
Upgrading from 3.14.0.3
-<PackageReference Include="DatadogNet.RUM.iOS" Version="3.14.0.3" />
+<PackageReference Include="DatadogNet.RUM.iOS" Version="3.14.0.4" />Nothing to change beyond the version: same native SDK, same API, same package set, and the native
xcframeworks are byte-for-byte the same build. All packages move together, as they depend on each
other at an exact version. The corrected descriptions and working README links appear on
nuget.org with this version.
Full changelog: v3.14.0.3...v3.14.0.4
Packages
Bound against dd-sdk-ios 3.14.0, targeting net8.0-ios18.0, net9.0-ios18.0 and net10.0-ios26.0.
The first three components of
3.14.0.4are the dd-sdk-ios version; the fourth is this
repository's binding revision, which advances when the bindings or packaging change while
the native binaries stay put.
| Package | Wraps | NuGet |
|---|---|---|
DatadogNet.Core.iOS |
DatadogCore |
3.14.0.4 |
DatadogNet.RUM.iOS |
DatadogRUM |
3.14.0.4 |
DatadogNet.Logs.iOS |
DatadogLogs |
3.14.0.4 |
DatadogNet.Trace.iOS |
DatadogTrace |
3.14.0.4 |
DatadogNet.SessionReplay.iOS |
DatadogSessionReplay |
3.14.0.4 |
DatadogNet.WebViewTracking.iOS |
DatadogWebViewTracking |
3.14.0.4 |
DatadogNet.CrashReporting.iOS |
DatadogCrashReporting |
3.14.0.4 |
DatadogNet.Flags.iOS |
DatadogFlags |
3.14.0.4 |
DatadogNet.Profiling.iOS |
DatadogProfiling |
3.14.0.4 |
DatadogNet.Internal.iOS |
DatadogInternal |
3.14.0.4 |
DatadogNet.OpenTelemetryApi.iOS |
OpenTelemetryApi |
3.14.0.4 |
DatadogNet.Objc.iOS |
(compatibility meta-package) |
3.14.0.4 |
dotnet add package DatadogNet.Core.iOS --version 3.14.0.4
dotnet add package DatadogNet.RUM.iOS --version 3.14.0.4
Licensing
The binding code is MIT; the bundled native binaries are Apache-2.0, as built and
published by Datadog. Each package ships both texts under licenses/.
3.14.0.3
What's changed
Binding-only release. The native SDK is unchanged — still
dd-sdk-ios 3.14.0 — and so are the
package ids, namespaces and API. The fourth component advances for the changes below, which came
out of a full ergonomics review of the four DatadogNet repositories.
IntelliSense on the generated tier
The main entry types now carry doc summaries — 26 of them, written in the ApiDefinitions.cs
files and carried by the binding generator into the packages' XML docs (measured before relying
on it, not assumed): DDDatadog, DDConfiguration, DDSite, DDTrackingConsent,
DDURLSessionInstrumentation, every module's Enable/configuration types, DDRUMMonitor, the
UIKit tracking predicates, DDLogger, DDLogs, DDLogEvent, DDTracer, the three header
writers, DDSessionReplay and its privacy overrides, DDWebViewTracking and DDCrashReporter.
The long tail of generated members — the 377 RUM model types, mostly — stays bare; the C# names
map 1:1 onto the Objective-C ones, so upstream's reference covers them.
The DDLogger null-attributes papercut: resolved by documentation, deliberately
3.14.0.2's notes flagged that Info(message, attributes) throws on a null dictionary, and
suggested a missing [NullAllowed]. Investigated properly: upstream declares those parameters
_Nonnull, and the Swift implementation takes a non-optional [String: Any] — so a
[NullAllowed] "fix" would have traded today's managed ArgumentNullException for a native
crash in the bridging thunk. The binding stays faithful. The rationale now lives as a comment on
the interface in ApiDefinitions.cs (so a future regeneration does not "fix" it wrongly) and in
the README's troubleshooting section; the Additions layer's
Log(level, message, exception?, attributes?) remains the null-tolerant path.
Trim and AOT analyzers, permanently on
The whole surface — generated tier and Additions — analyses clean, so an unsafe reflection
pattern introduced later surfaces at build time. IsTrimmable is deliberately not set: it
would opt the assemblies into consumer-side trimming the device tests do not exercise;
src/Datadog.Binding.props records the reasoning.
Release pipeline
- nuget.org now shows these notes.
docs/release-notes/<version>.mdis packed into
PackageReleaseNotes, with the GitHub releases page as fallback for versions without a
curated file. - README versions can no longer go stale silently — the install snippets sat at
3.14.0.1
while3.14.0.2shipped.build/CheckReadmeVersions.shruns in CI and fails when the README's
pins disagree withDirectory.Build.props. - The upgrade path while Objective Sharpie is broken is now a tool, not archaeology.
./build/DiffSwiftHeaders.sh <version>writes one diff per framework whose generated
-Swift.hchanged — the porting work list — and prints the archive's SHA-256 for
build/checksums.txtfrom the same bytes.docs/regenerating-bindings.mdexplains how to
read a diff, including why a_Nonnullin the header must not become[NullAllowed].
Sample
The sample now exercises the whole usable surface: DatadogNet.WebViewTracking.iOS joins its
references with a tracked WKWebView page, a button makes an instrumented NSUrlSession request
through the generic Enable<TDelegate>() — the one automatic-instrumentation path nothing
demonstrated — and a per-view Session Replay privacy override shows the granular control the
global levels cannot give.
net8 sunset
Stated policy, so the trade-off does not persist by inertia: the net8.0-ios18.0 head — past
its platform support window since MAUI 8 left support on 14 May 2025, though still verified by
the simulator checks — is dropped in the first release after .NET 8 itself leaves support on
10 November 2026.
Upgrading from 3.14.0.2
Nothing to change: same native SDK, same API. The new doc summaries appear on restore.
Full changelog: v3.14.0.2...v3.14.0.3
Packages
Bound against dd-sdk-ios 3.14.0, targeting net8.0-ios18.0, net9.0-ios18.0 and net10.0-ios26.0.
The first three components of
3.14.0.3are the dd-sdk-ios version; the fourth is this
repository's binding revision, which advances when the bindings or packaging change while
the native binaries stay put.
| Package | Wraps | NuGet |
|---|---|---|
DatadogNet.Core.iOS |
DatadogCore |
3.14.0.3 |
DatadogNet.RUM.iOS |
DatadogRUM |
3.14.0.3 |
DatadogNet.Logs.iOS |
DatadogLogs |
3.14.0.3 |
DatadogNet.Trace.iOS |
DatadogTrace |
3.14.0.3 |
DatadogNet.SessionReplay.iOS |
DatadogSessionReplay |
3.14.0.3 |
DatadogNet.WebViewTracking.iOS |
DatadogWebViewTracking |
3.14.0.3 |
DatadogNet.CrashReporting.iOS |
DatadogCrashReporting |
3.14.0.3 |
DatadogNet.Flags.iOS |
DatadogFlags |
3.14.0.3 |
DatadogNet.Profiling.iOS |
DatadogProfiling |
3.14.0.3 |
DatadogNet.Internal.iOS |
DatadogInternal |
3.14.0.3 |
DatadogNet.OpenTelemetryApi.iOS |
OpenTelemetryApi |
3.14.0.3 |
DatadogNet.Objc.iOS |
(compatibility meta-package) |
3.14.0.3 |
dotnet add package DatadogNet.Core.iOS --version 3.14.0.3
dotnet add package DatadogNet.RUM.iOS --version 3.14.0.3
Licensing
The binding code is MIT; the bundled native binaries are Apache-2.0, as built and
published by Datadog. Each package ships both texts under licenses/.
3.14.0.2
What's changed
Binding-only release. The native SDK is unchanged — still
dd-sdk-ios 3.14.0 — and so are the
package IDs, namespaces and every existing signature. Upgrading is a version bump.
The headline is OTSpan.GetTraceId, and it is worth stating why a getter warrants one: reading a
span's trace id from C# was not merely inconvenient, it was a trap that a consumer of these packages
fell into and shipped. Details below.
Package versions are
<dd-sdk-ios version>.<binding revision>.3.14.0.2is dd-sdk-ios
3.14.0, binding revision2. The fourth component belongs to this repository and advances when
the bindings or packaging change while the native binaries stay put.
Added
Span identity — OTSpan.GetTraceId / GetSpanId
OTSpanContext declares nothing but forEachBaggageItem. There is no traceID or spanID on the
protocol or on any bound type, and 3.x did not change that — so the ids can only be recovered by
injecting into a Datadog-format headers writer and reading what comes back.
That much is merely awkward. The trap is what you find when you look:
x-datadog-trace-id: 6096355397431041644 ← decimal, and only the LOW 64 bits
x-datadog-tags: _dd.p.tid=6a61e4ff00000000 ← the HIGH 64, somewhere else entirely
A caller who reads the obvious header gets a decimal string naming half of an id that, rendered the
way Datadog renders it, looks nothing like it. DatadogNet 3.14.0.1 did exactly that and shipped
with iOS reporting 6096355397431041644 where Android reported
6a61e4ff000000002e430f579ece9a6c for the same span — which quietly broke RUM-resource-to-APM-trace
correlation on iOS, because _dd.trace_id is the only thing that links them.
var traceId = span.GetTraceId (DDTracer.Shared ()); // 32 lowercase hex, always
var spanId = span.GetSpanId (DDTracer.Shared ()); // decimalThe rendering matches dd-sdk-android's own DatadogInterceptor, which is the reference
implementation of this correlation: DatadogTraceId.toHexString() for the trace id and
String.valueOf(long) for the span id. The asymmetry is Datadog's wire format rather than a choice.
toHexString() is toHexStringPadded(…, 32) on both the 128-bit and 64-bit implementations, so the
result is always 32 characters — with _dd.p.tid absent, the high half is genuinely zero and is
padded, not omitted.
Header injection — OTSpan.InjectHeaders
foreach (var header in span.InjectHeaders (DDTracer.Shared ()))
request.Headers.TryAddWithoutValidation (header.Key, header.Value);The bound API needs a dance that is not visible in the signatures: construct a writer, hand it to
Inject as though it were the carrier, then read the headers back off the writer. There is also
one writer type per format — unlike Android, where the formats are a property of the tracer and one
call writes all of them — so several formats means several round trips.
The format selector is a new OTHeaderFormats flags enum belonging to this repository, because the
bound DDTracingHeaderType is an Objective-C class of static singletons rather than an enum (Swift's
enum did not survive the projection) and so cannot be combined or compared. Defaults to Datadog plus
W3C trace context.
Span outcome — OTSpan.SetError / Log
span.SetError (exception);
span.Log (new Dictionary<string, object?> { ["event"] = "retry", ["attempt"] = 2 });SetErrorWithKind takes kind, message and stack separately, and a caller who passes only the message
gets a span marked as an error with nothing in the APM error panel to act on.
RUM — single-value attributes and the session id
monitor.AddAttribute ("cart.id", cartId);
monitor.AddViewAttribute ("cart.items", 3);
monitor.AddFeatureFlagEvaluation ("new-checkout", true);
var sessionId = await monitor.GetCurrentSessionIdAsync ();DatadogAttributes.ToNSObject (value, key) is now public, which is what these are built on.
AddAttributeForKey, AddViewAttributeForKey, AddFeatureFlagEvaluationWithName and
DDLogger.AddAttributeForKey all take a bare NSObject while DatadogAttributes only exposed the
dictionary form — so a caller either hand-wrapped the value, which is exactly what
DatadogAttributes exists to avoid, or round-tripped a one-element dictionary.
GetCurrentSessionIdAsync wraps CurrentSessionIDWithCompletion, which answers through a block on
the SDK's own queue.
Logs
DDLogger.AddAttribute (key, value), taking a plain value rather than an NSObject.
Documentation
The README gains an API coverage section, measured by diffing each framework's generated
-Swift.h against ApiDefinitions.cs rather than asserted:
| Framework | ObjC types | Bound |
|---|---|---|
DatadogRUM |
377 | 377 |
DatadogLogs |
16 | 16 |
DatadogCore |
12 | 12 |
DatadogTrace |
12 | 12 |
DatadogSessionReplay |
4 | 4 |
DatadogInternal |
2 | 2 |
DatadogCrashReporting |
1 | 1 |
DatadogWebViewTracking |
1 | 1 |
Member coverage is the same story — of 61 selectors and properties on DatadogCore, 59 are exported,
and the two that are not are init and new, removed on purpose by [DisableDefaultCtor].
What is missing is missing upstream, and the section now says so precisely rather than vaguely:
| Swift types | ObjC types | |
|---|---|---|
DatadogFlags |
15 | 0 |
DatadogProfiling |
2 | 0 |
OpenTelemetryApi |
— | no -Swift.h at all |
Feature Flags leans on generics (FlagDetails<T>) and enums with associated values (AnyValue),
neither of which Swift projects into Objective-C. DatadogTrace is additionally 24 public Swift
types projected down to 12, and the casualty is OTelTracerProvider — so OpenTelemetry tracing is
unreachable even though OpenTracing is not.
That is also why DatadogNet.Flags.iOS and DatadogNet.Profiling.iOS ship frameworks with no
callable API.
New: a prototype for reaching the Swift-only frameworks
shims/DatadogFlagsObjc/ is a hand-written Swift @objc wrapper
around DatadogFlags. It compiles against the real 3.14.0 framework with zero warnings and emits
exactly the header Objective Sharpie consumes, so the rest of the path to a NuGet is the ordinary one
this repository already runs.
Two things make Flags tractable: Datadog already flattened the generics at the convenience layer
(getBooleanValue, getStringValue, getIntegerValue, getDoubleValue, getObjectValue and the
matching …Details), and FlagsClient.shared(named:in:) returns a real object to wrap.
AnyValue maps onto the Foundation object graph, which is what a C# caller wants anyway.
Nothing ships. It is not built, packaged, bound or referenced — see its README for what remains.
The standing cost is worth naming: the wrapper is ours, so when Datadog changes
FlagsClientProtocol it stops compiling, at build time rather than someone's runtime.
Tests
127 package-layout tests pass, and the on-simulator suite grows from 17 checks to 21, all
running against the packed packages.
Until now this suite enabled Trace and stopped there — EnablesTrace constructed the three header
writers and never started a span — so the tracing path was configured and never driven. That is the
gap the trace-id defect slipped through, and it is now closed:
- A span is started, tagged, errored, logged and finished. Its ids are asserted by shape
rather than for non-emptiness: 32 lowercase hex characters and not all zeros for the trace, decimal
for the span. "Not empty" is what a caller checked before, and it is why the wrong rendering
shipped. - Headers are injected in all three formats and cross-checked two ways: the id must equal the
traceparentW3C value across all 128 bits — derived independently ofGetTraceId, so a second
opinion rather than a restatement — and must end with the low 64 bits the Datadog header carries in
decimal. Selecting no formats must produce nothing rather than throwing. - The single-value attribute overloads are driven on RUM, view attributes, feature flags and a
logger, andToNSObjectis asserted to mapnulltoNSNull— because an explicitly empty
attribute and an unset one are different things in a RUM event. - The session id is read through
GetCurrentSessionIdAsyncand asserted non-null; a null means
the completion block never fired, which is the failure theTaskwrapper exists to surface.
The harness gained async support to do the last of those, matching the shape the runner already
had on the façade side.
One thing the new checks turned up: Info(message, attributes) is generated without [NullAllowed]
on the dictionary, so passing null throws rather than reaching the SDK. Objective-C accepts nil
there. The single-argument overload and the ergonomic Log both handle it, so this is a papercut
rather than a gap — but it is real, and worth knowing before you hit it.
Sample
samples/DatadogNet.iOS.Example gains a Trace section, because it enabled Trace and never
demonstrated it. Two buttons: one traces an outgoing HttpRequestMessage end to end — start a span,
inject the headers a receiving service continues the trace from, report the status, finish — and one
records a failed span with SetError and Log. RUM gains a button showing the current session id.
Upgrading from 3.14.0.1
-<PackageReference Include="DatadogNet.RUM.iOS" Version="3.14.0.1" />
+<PackageReference Include="DatadogNet.RUM.iOS" Version="3.14.0.2" />Nothing is removed or renamed, and the native xcframeworks are byte-for-byte the same build. All
packages move together, as they depend on each other at an exact version.
If you read span ids yourself, replace whatever you were doing with GetTraceId/GetSpanId and
check what ...
3.14.0.1
What's changed
Moves to dd-sdk-ios 3.14.0, the current release, from 2.30.2. This is the 2.x → 3.x major
upgrade, and it restructures the package set: DatadogObjc and CrashReporter are gone upstream,
DatadogFlags and DatadogProfiling are new, and the DD* types that all lived in one namespace
now live in the module each belongs to.
Every app has to change code, not just a version number. The migration table below covers it.
Package versions are
<dd-sdk-ios version>.<binding revision>.3.14.0.1is dd-sdk-ios
3.14.0, binding revision1.
⚠️ Breaking changes
The DatadogObjc namespace is gone. Upstream deleted the framework and moved its types into
the product modules, so a single using DatadogObjc; becomes one import per feature:
-using DatadogObjc;
+using DatadogCore; // DDDatadog, DDConfiguration, DDSite, DDTrackingConsent
+using DatadogRUM; // DDRUM, DDRUMMonitor, DDRUMConfiguration, the RUM event models
+using DatadogLogs; // DDLogs, DDLogger, DDLoggerConfiguration, DDLogEvent
+using DatadogTrace; // DDTrace, DDTracer, the header writersDDCoreLoggerLevel and DDTracingHeaderType live in DatadogInternal, which every module already
depends on — add using DatadogInternal; if you touch either.
| Type | 2.30.2 namespace | 3.14.0 namespace |
|---|---|---|
DDDatadog, DDConfiguration, DDSite, DDTrackingConsent, DDURLSessionInstrumentation |
DatadogObjc |
DatadogCore |
DDRUM, DDRUMMonitor, DDRUMConfiguration, DDRUMView, all RUM event models |
DatadogObjc |
DatadogRUM |
DDLogs, DDLogger, DDLoggerConfiguration, DDLogEvent |
DatadogObjc |
DatadogLogs |
DDTrace, DDTracer, DDHTTPHeadersWriter, DDB3HTTPHeadersWriter |
DatadogObjc |
DatadogTrace |
DDCoreLoggerLevel, DDTracingHeaderType |
DatadogObjc |
DatadogInternal |
DDSessionReplay and friends |
DatadogSessionReplay |
unchanged |
DatadogNet.CrashReporter.iOS is retired. dd-sdk-ios 3.0 replaced PLCrashReporter with
KSCrash, which is linked into DatadogCrashReporting rather than shipped separately — the binary
defines 912 KSCrash symbols and no PLCrash ones. Drop the reference; DatadogNet.CrashReporting.iOS
is self-contained now. Every PLCrashReporter* type is gone with it.
Crash reports are now delivered through RUM error tracking only. The Logs product no longer
reports fatal errors, so RUM and Crash Reporting must both be enabled to see crashes.
DatadogNet.Objc.iOS is now a compatibility meta-package. It ships no assembly — just
dependencies on Core, RUM, Logs, Trace and SessionReplay — so an existing PackageReference still
restores a working set after a version bump. It does not spare you the namespace changes above.
New apps should reference the product modules directly and ignore it.
Tracing header writers changed. DDOTelHTTPHeadersWriter is replaced by
DDW3CHTTPHeadersWriter, and all of them lost their sampling argument — trace sampling is now
derived from the RUM session.id so a trace and its session agree.
-var writer = new DDHTTPHeadersWriter(DDTraceSamplingStrategy.CustomWithSampleRate(100), DDTraceContextInjection.All);
+var writer = new DDHTTPHeadersWriter(DDTraceContextInjection.All);URLSession instrumentation is unified. DatadogURLSessionDelegate, DDURLSessionDelegate and
DDNSURLSessionDelegate are all gone, replaced by DDURLSessionInstrumentation. This binding's
convenience overloads carry over unchanged:
DDURLSessionInstrumentation.Enable<MySessionDelegate>();RUMView(path:) became RUMView(name:). The DDRUMView initializer now takes a name and an
optional isUntrackedModal flag.
Session Replay's defaultPrivacyLevel is gone for good. It was deprecated in 2.19.0 and
removed in 3.0; the three fine-grained levels are required initializer arguments. If you are coming
straight from 2.17.0, see the 2.30.2.1 notes for that change.
Added
DatadogNet.Flags.iOS and DatadogNet.Profiling.iOS, for the two new SDK modules. Both ship
the native framework but expose no Objective-C API at all — upstream has not projected them
into Objective-C yet, so there is nothing callable from C#. They are published so the package set
mirrors the SDK and so adding the API later is a version bump rather than a new package id.
View-level RUM attributes (the headline 3.0 RUM change) — attributes set on a view now
propagate to the resources, actions, errors and long tasks recorded while it is active, instead of
having to be repeated on every call:
using (Datadog.Rum.StartView("checkout"))
{
Datadog.Rum.AddViewAttributes(new Dictionary<string, object?> { ["cart.size"] = 3 });
Datadog.Rum.AddAction(DDRUMActionType.Tap, "pay"); // inherits cart.size
Datadog.Rum.RemoveViewAttributes("cart.size");
}AddViewAttributeForKey, AddViewAttributes, RemoveViewAttributeForKey and
RemoveViewAttributesForKeys are all bound, with C#-dictionary and params overloads.
DDRUMConfiguration.TrackMemoryWarnings, reporting memory warnings as RUM errors.
Multi-instance overloads throughout. Nearly every entry point gained an instanceName:
variant, so a host app and an embedded SDK can run separate Datadog instances.
DDW3CHTTPHeadersWriter for W3C tracecontext propagation.
Fixed
The generator that produces these bindings was rewritten for the 3.x layout, and several classes of
defect were found and fixed along the way. Each would have compiled cleanly and failed at runtime or
corrupted a call:
extraInfowas bound as anoutparameter. The pointer-to-pointer heuristic counted the*
insideNSDictionary<NSString *, id> *, sosetUserInfo,addUserExtraInfoand several others
tookoutdictionaries that callers could never populate.[NullAllowed]was missing everywhere. Nullability is expressed in the Objective-C type,
not the property attribute list, so every nullable property was bound as non-null.@protocol DDFoo;forward declarations swallowed the next interface.DDDataEncryptionwas
bound withDDConfiguration's entire member list.+ initializeWithConfiguration:trackingConsent:was bound as a constructor because its
selector starts with "init"; it is a static void method. Constructors are now identified by
returninginstancetypeon an instance method.- Swift class properties were bound twice — once as the property and once as its
+getter —
producing duplicate C# members. - Block parameters were mangled. A naive paren match read
(void (^)(NSTimeInterval))as the
typevoid (^; all ten block-taking methods, including every event mapper, are nowAction<>/
Func<>.
The meta-package would have shipped without net10 dependencies. merge-packages.py decided what
to merge from lib/ folders, and a dependency-only package has none — so DatadogNet.Objc.iOS
advertised net8 and net9 only, and a net10 consumer would have restored it and got nothing at all.
Dependency groups are now merged independently of lib assets.
Tests
The on-simulator suite is 17 checks, run against the packed packages on both net9.0-ios18.0
and net10.0-ios26.0. It covers the new surface: view-attribute propagation, the unified URLSession
instrumentation by type, KSCrash-backed crash reporting, fine-grained Session Replay privacy with
per-view overrides, and both the RUM and Logs event mappers actually firing.
The framework-loaded check now expects eleven dynamic frameworks and asserts KSCrash resolves as
a class — 3.x removes the one static-archive special case the 2.x bindings had to carry.
Package layout tests are 127 checks, including a new one asserting the meta-package ships
dependencies for every target framework and no assembly or payload.
Notes
Packages total about 67 MB, up from 50 MB on 2.30.2 — the frameworks themselves grew. The
largest is DatadogNet.Internal.iOS at 20.7 MB, comfortably under the 250 MB nuget.org limit.
Objective Sharpie still cannot be used. Version 3.5.116 bundles a clang that fails on recent
iOS SDK module maps. The bindings were generated by parsing the shipped -Swift.h headers directly;
build/GenerateBindings.sh documents the problem and honours a SHARPIE override for when it is
fixed.
The 2.x line ends at 2.30.2.1. It remains on nuget.org and is unaffected by this release. If you
cannot take the namespace changes yet, stay there — but note that 2.x receives no further upstream
fixes.
Full changelog: v2.30.2.1...v3.14.0.1
Packages
Bound against dd-sdk-ios 3.14.0, targeting net8.0-ios18.0, net9.0-ios18.0 and net10.0-ios26.0.
The first three components of
3.14.0.1are the dd-sdk-ios version; the fourth is this
repository's binding revision, which advances when the bindings or packaging change while
the native binaries stay put.
| Package | Wraps | NuGet |
|---|---|---|
DatadogNet.Core.iOS |
DatadogCore |
3.14.0.1 |
DatadogNet.RUM.iOS |
DatadogRUM |
3.14.0.1 |
DatadogNet.Logs.iOS |
DatadogLogs |
3.14.0.1 |
DatadogNet.Trace.iOS |
DatadogTrace |
3.14.0.1 |
DatadogNet.SessionReplay.iOS |
DatadogSessionReplay |
3.14.0.1 |
DatadogNet.WebViewTracking.iOS |
DatadogWebViewTracking |
3.14.0.1 |
DatadogNet.CrashReporting.iOS |
DatadogCrashReporting |
[3.14.0.1](h... |
2.30.2.2
What's changed
- add maui ergnomics (09d05bd)
Full changelog: v2.30.2.1...v2.30.2.2
Packages
Bound against dd-sdk-ios 2.30.2, targeting net8.0-ios18.0, net9.0-ios18.0 and net10.0-ios26.0.
The first three components of
2.30.2.2are the dd-sdk-ios version; the fourth is this
repository's binding revision, which advances when the bindings or packaging change while
the native binaries stay put.
| Package | Wraps | NuGet |
|---|---|---|
DatadogNet.Objc.iOS |
DatadogObjc |
2.30.2.2 |
DatadogNet.Core.iOS |
DatadogCore |
2.30.2.2 |
DatadogNet.Internal.iOS |
DatadogInternal |
2.30.2.2 |
DatadogNet.Logs.iOS |
DatadogLogs |
2.30.2.2 |
DatadogNet.RUM.iOS |
DatadogRUM |
2.30.2.2 |
DatadogNet.SessionReplay.iOS |
DatadogSessionReplay |
2.30.2.2 |
DatadogNet.Trace.iOS |
DatadogTrace |
2.30.2.2 |
DatadogNet.WebViewTracking.iOS |
DatadogWebViewTracking |
2.30.2.2 |
DatadogNet.CrashReporting.iOS |
DatadogCrashReporting |
2.30.2.2 |
DatadogNet.CrashReporter.iOS |
CrashReporter |
2.30.2.2 |
DatadogNet.OpenTelemetryApi.iOS |
OpenTelemetryApi |
2.30.2.2 |
dotnet add package DatadogNet.Objc.iOS --version 2.30.2.2
Licensing
The binding code is MIT; the bundled native binaries are Apache-2.0, as built and
published by Datadog. Each package ships both texts under licenses/.
2.30.2.1
What's changed
Updates the native SDK from dd-sdk-ios 2.17.0 to 2.30.2, the last release of the 2.x line —
thirteen minor versions, published between September 2024 and October 2025. The 2.x line continued
to receive fixes after 3.0.0 shipped, so 2.30.2 is genuinely the end of the line rather than the
last release before the split.
Everything upstream added is bound: 29 new types, 17 new enums and 133 new members across the
eleven packages — 27 types and 120 members in DatadogObjc alone. Measured by parsing the
-Swift.h header each xcframework ships and diffing it against 2.17.0's, not by reading the
documentation.
Package versions are
<dd-sdk-ios version>.<binding revision>.2.30.2.1is dd-sdk-ios
2.30.2, binding revision1. The revision restarts at 1 for each new native version.
⚠️ Breaking changes
DDSessionReplay and DDSessionReplayConfiguration no longer exist in the DatadogObjc
namespace. Upstream removed the parallel copies it used to declare there; Session Replay now
lives only in DatadogSessionReplay. If you wrote using DatadogObjc; and referred to
DDSessionReplay, add the other namespace:
using DatadogObjc;
+using DatadogSessionReplay;The upside: the two identically named types that previously made DDSessionReplay ambiguous when
both namespaces were imported are gone, so no alias is needed any more.
Session Replay privacy is now three settings, not one. defaultPrivacyLevel is deprecated
upstream in favour of independent text/input, image and touch levels, and the new initializer
requires all three — the choice can no longer be left implicit.
-DDSessionReplay.EnableWith(new DDSessionReplayConfiguration(replaySampleRate: 100)
-{
- DefaultPrivacyLevel = DDSessionReplayConfigurationPrivacyLevel.Mask,
-});
+DDSessionReplay.EnableWith(new DDSessionReplayConfiguration(
+ replaySampleRate: 100,
+ textAndInputPrivacyLevel: DDTextAndInputPrivacyLevel.MaskAll,
+ imagePrivacyLevel: DDImagePrivacyLevel.MaskAll,
+ touchPrivacyLevel: DDTouchPrivacyLevel.Hide));The old single-argument initializer and DefaultPrivacyLevel are still bound, so existing code
keeps compiling — but they are deprecated upstream and will be removed. Allow, Mask and
MaskUserInput map onto the new levels as Datadog documents.
DDRUMVitalEventVital.details is gone, replaced by failureReason, parentId, stepType and
vitalDescription. It is only reachable from inside a RUM event mapper, so most apps will not
notice.
Fixed
Session Replay would have failed at runtime had the binding been carried over unchanged.
Through 2.17.0 these classes were declared SWIFT_CLASS("_TtC20DatadogSessionReplay..."), which
sets the Objective-C runtime name to the mangled Swift symbol — so the binding spelled that mangled
name out in [BaseType (Name = ...)]. From 2.19.0 they are declared SWIFT_CLASS_NAMED, which
expands to swift_name(...) only and leaves the runtime name as the plain @interface name. The
binary confirms it: it exports _OBJC_CLASS_$_DDSessionReplay, not the mangled symbol. The Name=
attributes are therefore removed. Keeping them would have compiled cleanly and then failed with
"the native class hasn't been loaded" the first time a replay type was touched.
Added
Fine-grained Session Replay masking (2.18.0) — DDTextAndInputPrivacyLevel,
DDImagePrivacyLevel and DDTouchPrivacyLevel.
Per-view privacy overrides (2.19.0) — DDSessionReplayPrivacyOverrides, reached through a
category on UIView, so a single view can be masked or hidden regardless of the session-wide
level:
var overrides = myView.GetDdSessionReplayPrivacyOverrides();
overrides.TextAndInputPrivacy = DDTextAndInputPrivacyLevelOverride.MaskAll;
overrides.Hide = new NSNumber(true);Deferred replay recording (2.21.0) — StartRecordingImmediately on the configuration, plus
DDSessionReplay.StartRecording() and StopRecording(), for apps that start recording only after
consent or on a particular screen.
Account information (2.29.0) — DDDatadog.SetAccountInfoWithAccountId, AddAccountExtraInfo
and ClearAccountInfo. Account details propagate to Logs, RUM, Traces and error reporting.
DDLogEvent gains a matching AccountInfo, and every RUM event model gains Account.
DDDatadog.ClearUserInfo (2.30.0), and SetUserInfoWithUserId, which requires an id where the
old overload did not (2.24.0).
SwiftUI auto-tracking (2.29.0) — DDSwiftUIRUMViewsPredicate and
DDSwiftUIRUMActionsPredicate, their DDDefault* implementations, and the
SwiftUIViewsPredicate / SwiftUIActionsPredicate properties on DDRUMConfiguration. Bound with
the same [Model, Protocol] shape as the UIKit predicates, so an app can subclass the generated
class instead of implementing the interface.
The AP2 datacenter (2.29.0) — DDSite.Ap2.
RUM attribute APIs (2.23.0) — DDRUMMonitor.AddAttributes and RemoveAttributesForKeys, for
setting attributes on the monitor rather than per event.
DDConfiguration.BackgroundTasksEnabled (2.22.0), and DDRUMConfiguration.TrackAnonymousUser
(2.24.0) with the matching AnonymousId on RUM user models.
New RUM view metrics reachable through the event mappers: Time To Network Settled and
Interaction To Next View (2.23.0), hang and hitch rates (2.25.0), and the view performance models
(CLS, FCP, FID, INP, LCP, FBC) and slow-frame detail. Device models gain battery level, brightness,
locale, power-saving mode and time zone (2.30.0), and every event gains Ddtags (2.30.1).
DDInternalLogger (2.19.0) — the Objective-C entry point to the SDK's internal telemetry.
PLCrashReporterConfig.MaxReportBytes and the initializer that sets it, from the PLCrashReporter
update in 2.25.0.
Tests
The on-simulator suite grows to 20 checks, running against the packed packages on both
net9.0-ios18.0 and net10.0-ios26.0. New coverage: fine-grained Session Replay privacy with
deferred recording start/stop, per-view privacy overrides set and read back through a fresh
accessor, account info set/extend/clear alongside user-info clearing, and the new RUM attribute
APIs and AP2 site.
run-simulator-tests.sh now deletes the device app's obj/ and bin/ before building. Clearing
the NuGet cache is not enough: the native payload is extracted into obj/ and copied into the
.app, and neither step re-runs when the package version string is unchanged — so re-packing the
same version left the previous build's xcframeworks embedded in the app. That produced a
genuinely misleading failure during this upgrade, in which the frameworks were present and loaded
but every Objective-C class lookup missed, because the app was running 2.17.0 binaries against a
2.30.2 binding.
Notes
Package size dropped from about 80 MB to about 50 MB across the eleven packages. The frameworks
themselves are smaller in 2.30.2; nothing changed in how they are stripped or packed.
Objective Sharpie could not be used for this upgrade. Version 3.5.116, the current release,
bundles a clang that cannot parse the module maps in recent iOS SDKs — it fails with
module '_stddef' requires feature 'found_incompatible_headers__check_search_paths' against both
the 18.5 and 26.5 SDKs, before emitting anything. It also refuses to bind a framework whose
recorded DTSDKName is not installed, which is normal for a downloaded binary. The delta was
therefore derived by parsing the shipped headers and diffing them against the previous version's.
build/GenerateBindings.sh documents both problems and now honours a SHARPIE environment
variable, so the package can be expanded and run in place without administrator rights once it
works again.
No new packages. dd-sdk-ios 2.30.2 ships the same eleven frameworks as 2.17.0.
DatadogFlags and DatadogProfiling are 3.x-only, as is the removal of DatadogObjc and the move
from PLCrashReporter to KSCrash.
Full changelog: v2.17.0.1...v2.30.2.1
Packages
Bound against dd-sdk-ios 2.30.2, targeting net8.0-ios18.0, net9.0-ios18.0 and net10.0-ios26.0.
The first three components of
2.30.2.1are the dd-sdk-ios version; the fourth is this
repository's binding revision, which advances when the bindings or packaging change while
the native binaries stay put.
| Package | Wraps | NuGet |
|---|---|---|
DatadogNet.Objc.iOS |
DatadogObjc |
2.30.2.1 |
DatadogNet.Core.iOS |
DatadogCore |
2.30.2.1 |
DatadogNet.Internal.iOS |
DatadogInternal |
2.30.2.1 |
DatadogNet.Logs.iOS |
DatadogLogs |
2.30.2.1 |
DatadogNet.RUM.iOS |
DatadogRUM |
2.30.2.1 |
DatadogNet.SessionReplay.iOS |
DatadogSessionReplay |
2.30.2.1 |
DatadogNet.Trace.iOS |
DatadogTrace |
2.30.2.1 |
DatadogNet.WebViewTracking.iOS |
DatadogWebViewTracking |
2.30.2.1 |
DatadogNet.CrashReporting.iOS |
DatadogCrashReporting |
2.30.2.1 |
DatadogNet.CrashReporter.iOS |
CrashReporter |
2.30.2.1 |
DatadogNet.OpenTelemetryApi.iOS |
OpenTelemetryApi |
2.30.2.1 |
dotnet ad...
2.17.0.1
What's changed
First release of the DatadogNet.*.iOS packages, replacing the DatadogObjc.iOS /
DatadogCore.iOS set published from the old DataDog-SDK-iOS-net repository. Same eleven
packages, same native SDK (dd-sdk-ios 2.17.0), same namespaces and same API — rebuilt on a
packaging pipeline that is tested.
Package versions are
<dd-sdk-ios version>.<binding revision>.2.17.0.1is dd-sdk-ios
2.17.0, binding revision1. The fourth component belongs to this repository and advances when
the bindings or packaging change while the native binaries stay put.
⚠️ Breaking changes
Package IDs have changed. <Framework>.iOS is replaced by DatadogNet.<Name>.iOS.
-<PackageReference Include="DatadogObjc.iOS" Version="2.17.0.1" />
+<PackageReference Include="DatadogNet.Objc.iOS" Version="2.17.0.1" />The namespaces are unchanged — DatadogObjc, DatadogCore, DatadogSessionReplay and the
rest — so no using directive and no call site changes. See the README's
migration table for all eleven.
net7.0-ios is dropped. The packages now target net8.0-ios18.0, net9.0-ios18.0 and
net10.0-ios26.0; the old ones targeted net7.0-ios16.1 and net8.0-ios17.2.
Minimum deployment target is iOS 12.2, up from 12.0. The Datadog frameworks are Swift and rely
on the OS-provided Swift runtime, which is only ABI-stable from 12.2 — the packages previously
claimed support for two OS versions on which their own dependency does not exist.
CrashReporter.iOS was versioned 1.11.2.x; DatadogNet.CrashReporter.iOS is 2.17.0.1. It
ships inside the same Datadog release as everything else, and the PLCrashReporter-derived numbering
made it impossible to tell which Datadog build a given package belonged to.
Fixed
A startup crash in DatadogInternal.iOS. The binding declared three URLSession overloads
that INSUrlSessionDataDelegate already declares, so each selector was registered twice. This was
not a compile error — it killed the app during assembly registration, before a line of its own code
ran:
Could not register the selector 'URLSession:task:didFinishCollectingMetrics:' of the member
'DatadogInternal.DatadogURLSessionDelegate.URLSession' because the selector is already registered
on the member 'DidFinishCollectingMetrics'.
The duplicates are gone. The methods are still callable under their inherited names.
The inter-package dependency graph was inverted. DatadogInternal.iOS declared dependencies on
DatadogCore.iOS and DatadogTrace.iOS; the frameworks' actual load commands say both of those
depend on DatadogInternal. The graph is now derived from the binaries.
DatadogTrace.iOS did not declare OpenTelemetryApi.iOS. DatadogTrace is the only framework
that links OpenTelemetry, but the dependency was declared on DatadogObjc.iOS instead — so
referencing Trace on its own did not link. DatadogNet.Trace.iOS declares it directly.
Added
net9.0-ios and net10.0-ios.
A convenience API over the generated binding, in DatadogNet.Objc.iOS. Nothing is hidden or
renamed; the generated members are all still there.
using (monitor.StartView("checkout"))— a disposable scope, instead of a
StartViewWithKey/StopViewWithKeypair matched by string key that leaks the view on an early
return or an exception.- Plain C# dictionaries where the raw API takes
NSDictionary<NSString, NSObject>, on every RUM and
Logs overload. Values may be strings, numbers,bool,DateTime,Guid, enums, arrays and
nested dictionaries; anything unconvertible throws rather than being silently dropped. monitor.AddError(exception)andlogger.Log(level, message, exception, attributes), which take
a managedExceptionwhere the binding takes anNSError— the latter settingerror.kind,
error.messageanderror.stackso it renders as an error in the Logs UI.DDLogger.Create(name: "app")andDDLogs.Enable(), instead of an eight-argument designated
initializer with no defaults.DDDatadog.SetUserInfo(id)with optional name, email and attributes.TrackingConsentas a real C# enum, mirroringDDTrackingConsent, which is a class of static
instances.
Tests. 123 package-layout checks over the packed .nupkgs — target frameworks, native payload,
slices, xcframework manifests, dependency groups, licences, symbols — and a 14-check on-simulator
suite that installs the packed packages into a real iOS app and drives the SDK: initialization,
RUM views/actions/errors/resources, all six log levels, Trace with all three header writers, Session
Replay, crash reporting, both URLSession delegates, and the convenience layer. It also asserts that
all eleven native frameworks are actually loaded into the process, which is what would catch a
package whose payload was empty or mis-stripped.
CI. Pull requests build, test and publish a -beta.<pr>.<run> prerelease; tagging v2.17.0.1
publishes the set and creates a GitHub release. Publishing uses nuget.org trusted publishing, so
there is no long-lived API key.
Changed
Packages are about 74 MB in total, down from what shipping every slice would cost. The upstream
archive carries tvOS slices for every framework, macCatalyst/macOS/watchOS/visionOS for two of them,
and a full set of dSYMs — none of it reachable from a net*-ios binding, and all of it embedded
once per target framework. FetchXcFrameworks.sh strips to the two iOS slices and rewrites each
Info.plist to match.
The native payload ships as a single compressed file rather than a directory of loose framework
files, which is what previously risked NU5123 and path-length restore failures on Windows.
No Carthage, and nothing is built from source. Datadog publishes the built xcframeworks as a
release asset, so the build downloads one archive and verifies it against a SHA-256 pinned in
build/checksums.txt. gen.sh, fixgen.sh, changever.sh, pack.sh, unpack.sh and
publish.sh are all gone; regeneration is build/GenerateBindings.sh, which writes to a scratch
directory for diffing rather than overwriting the committed sources — which is how the
duplicate-selector crash above survived for so long.
Licence metadata is accurate. The packages declared MIT, which described the binding code but
not the native binaries they ship. They now declare MIT AND Apache-2.0 and carry both texts under
licenses/. Your obligations have not changed; the metadata was simply incomplete.
Notes
DatadogNet.CrashReporting.iOS and DatadogNet.WebViewTracking.iOS are deliberately not pulled
in by DatadogNet.Objc.iOS. Neither is referenced by DatadogObjc's binary, and crash reporting
installs a signal handler — not something an app that only wanted RUM should get by default.
Reference them explicitly.
DDSessionReplay exists in both the DatadogObjc and DatadogSessionReplay namespaces, wrapping
two different native classes that do the same thing. Prefer the DatadogObjc one; importing both
namespaces unqualified makes the name ambiguous.
dd-sdk-ios 3.x is a larger move than a version bump: it removes DatadogObjc entirely (the
DD* types moved into each feature module), replaces PLCrashReporter with KSCrash, and adds
DatadogFlags and DatadogProfiling. This release deliberately stays on the 2.x line.
Packages
Bound against dd-sdk-ios 2.17.0, targeting net8.0-ios18.0, net9.0-ios18.0 and net10.0-ios26.0.
The first three components of
2.17.0.1are the dd-sdk-ios version; the fourth is this
repository's binding revision, which advances when the bindings or packaging change while
the native binaries stay put.
| Package | Wraps | NuGet |
|---|---|---|
DatadogNet.Objc.iOS |
DatadogObjc |
2.17.0.1 |
DatadogNet.Core.iOS |
DatadogCore |
2.17.0.1 |
DatadogNet.Internal.iOS |
DatadogInternal |
2.17.0.1 |
DatadogNet.Logs.iOS |
DatadogLogs |
2.17.0.1 |
DatadogNet.RUM.iOS |
DatadogRUM |
2.17.0.1 |
DatadogNet.SessionReplay.iOS |
DatadogSessionReplay |
2.17.0.1 |
DatadogNet.Trace.iOS |
DatadogTrace |
2.17.0.1 |
DatadogNet.WebViewTracking.iOS |
DatadogWebViewTracking |
2.17.0.1 |
DatadogNet.CrashReporting.iOS |
DatadogCrashReporting |
2.17.0.1 |
DatadogNet.CrashReporter.iOS |
CrashReporter |
2.17.0.1 |
DatadogNet.OpenTelemetryApi.iOS |
OpenTelemetryApi |
2.17.0.1 |
dotnet add package DatadogNet.Objc.iOS --version 2.17.0.1
Licensing
The binding code is MIT; the bundled native binaries are Apache-2.0, as built and
published by Datadog. Each package ships both texts under licenses/.