Releases: sbokatuk/DatadogNet.Android
Release list
3.12.1.4
What's changed
Binding-only release. The native SDK is unchanged — still
dd-sdk-android 3.12.1 — and so
are the package ids, namespaces and API. The fourth component advances for the changes below:
what 3.12.1.3 started for two packages, this release finishes for all thirteen.
Complete R8 keep-rules, in every package
3.12.1.3 shipped consumer keep-rules for WebView and Ndk. That covered two of the thirteen
JNI-only entry surfaces — and none of upstream's own rules, because .NET for Android never feeds
an .aar's embedded proguard.txt to R8 the way Gradle would. Every package now ships a
generated buildTransitive/<PackageId>.pro with both halves:
- upstream's consumer rules, recovered verbatim from the
.aar— the
-keepattributes SourceFile,LineNumberTablethat Error Tracking needs, the Session Replay
recorder's-keepnames, and the rest that was silently dropped before; - curated keeps for the JNI-only entry surface:
Datadog,Rum/GlobalRumMonitorand the
RumMonitorinterface,LogsandLogger,Trace/DatadogTracing/GlobalDatadogTracer
and the tracer/span/scope/propagation interfaces,SessionReplay, every*Configurationand
itsBuilder, the enums whose constants C# reads, the OkHttp interceptors, and each module's
equivalents. All of it is reached from C# through JNI alone, which a Java shrinker cannot see.
If you enable Java shrinking (AndroidLinkTool=r8) you no longer need hand-written -keep
rules for Datadog classes, and workarounds can be deleted. The rules are generated by
build/generate-r8-rules.sh from the pinned .aars, CI fails on drift, and one emulator leg
now runs the smoke suite against a genuinely shrunk build — so a keep-rule regression fails CI
functionally instead of surfacing as a ClassNotFoundException in your Release build.
IntelliSense from upstream's KDoc
Every binding project now feeds upstream's -sources.jar to the binding generator
(@(JavaSourceJar)), which imports API documentation into the generated XML docs — on all three
target frameworks, downloaded and pinned like every other artifact. Expectations calibrated:
the importer parses Java sources and dd-sdk-android is Kotlin, so coverage is thin rather than
complete — but what it can extract now reaches your editor, and the hand-written convenience
layer remains fully documented.
The supply chain is PGP-verified
The SHA-256 pin list (now 30 pins, sources jars included) anchored what Maven Central served
on the day of pinning. It now also anchors that Datadog signed it:
build/UpdateMavenChecksums.sh downloads each Datadog artifact's detached .asc and verifies
it against Datadog's release signing key, pinned by full fingerprint
(CAF18D4EC00CA4450C6725A59333D4EF32A49F0A). A bad signature is a hard failure; a machine
without gpg skips loudly. The build itself gained a completeness guard — a declared artifact
whose pin is missing fails the build by name instead of slipping past unverified — and CI
regenerates both the pins and the keep-rules on every run and fails on any diff.
Smaller improvements
- New Troubleshooting entry for the
NU1107onXamarin.AndroidX.SavedStatethat every
net8 consumer hits: the direct1.4.0reference that settles it, and why it must not be
applied to net9/net10. - The unbound-artifact roster is complete and watched:
build/packages.tsvnow accounts
for all 41dd-sdk-android*artifacts on Maven Central with a reason per exclusion —
-flags,-flags-openfeatureand-profilingare recorded as binding candidates — and a
weeklyupstream-watchworkflow opens an issue when upstream releases a newer line or
publishes an artifact the roster has never met. - Releases cannot lie about their native version: the release workflow refuses a tag whose
native prefix disagrees withDirectory.Build.props(a documented override exists for the
deliberate case). build/BumpNativeVersion.shscripts the mechanical half of a native upgrade: props,
checksum pins, keep-rules, dependency verification, README versions and a release-notes
scaffold, in one command.
net8 sunset
Unchanged policy: the net8.0-android34.0 head is dropped, and the held-back dependency
versions unpinned, in the first release after .NET 8 leaves support on 10 November 2026.
Upgrading from 3.12.1.3
Nothing to change. A Release build with R8 enabled may keep more classes than before — that is
the point — and binaries are byte-for-byte the same native SDK.
Full changelog: v3.12.1.3...v3.12.1.4
Packages
Bound against dd-sdk-android 3.12.1, targeting net8.0-android34.0, net9.0-android35.0 and net10.0-android36.0.
The first three components of
3.12.1.4are the dd-sdk-android 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.Internal.Android |
dd-sdk-android-internal |
3.12.1.4 |
DatadogNet.Core.Android |
dd-sdk-android-core |
3.12.1.4 |
DatadogNet.Logs.Android |
dd-sdk-android-logs |
3.12.1.4 |
DatadogNet.TraceApi.Android |
dd-sdk-android-trace-api |
3.12.1.4 |
DatadogNet.TraceInternal.Android |
dd-sdk-android-trace-internal |
3.12.1.4 |
DatadogNet.Trace.Android |
dd-sdk-android-trace |
3.12.1.4 |
DatadogNet.RUM.Android |
dd-sdk-android-rum |
3.12.1.4 |
DatadogNet.SessionReplay.Android |
dd-sdk-android-session-replay |
3.12.1.4 |
DatadogNet.SessionReplayMaterial.Android |
dd-sdk-android-session-replay-material |
3.12.1.4 |
DatadogNet.SessionReplayCompose.Android |
dd-sdk-android-session-replay-compose |
3.12.1.4 |
DatadogNet.Ndk.Android |
dd-sdk-android-ndk |
3.12.1.4 |
DatadogNet.WebView.Android |
dd-sdk-android-webview |
3.12.1.4 |
DatadogNet.OkHttp.Android |
dd-sdk-android-okhttp |
3.12.1.4 |
dotnet add package DatadogNet.RUM.Android --version 3.12.1.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.12.1.3
What's changed
Binding-only release. The native SDK is unchanged — still
dd-sdk-android 3.12.1 — 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.
Release builds stop losing Datadog classes to R8
DatadogNet.WebView.Android and DatadogNet.Ndk.Android now ship consumer R8/ProGuard
keep-rules under buildTransitive/, imported into the consuming app automatically. Their entry
points — WebViewTracking, NdkCrashReports — are reached from .NET through JNI alone, which a
Java shrinker cannot see, so a shrunk Release build removed them and Enable threw
ClassNotFoundException at runtime from a package that was correctly installed. If you carried a
manual -keep for either, or disabled shrinking to work around this, you can remove the
workaround. New package-layout tests assert the rules stay in the packages.
Supply-chain pins for every Maven artifact
Java dependency verification always checked completeness — that every linked Java type is
provided by some referenced package. It said nothing about authenticity. Now every artifact
this repository resolves has a SHA-256 pinned in build/maven-checksums.txt (18 pins: the
thirteen dd-sdk modules plus Kronos, JCTools, RE2/J and androidx.metrics), and the
VerifyDatadogMavenArtifactHashes target checks the bytes actually resolved — on both the
@(AndroidMavenLibrary) path and the direct-download fallback — on every build. A hash that
changes for an unchanged version fails the build instead of shipping.
build/UpdateMavenChecksums.sh regenerates the pins on upgrade.
The upgrade ritual's sharpest steps are now a script
build/verify-transitive-deps.py re-derives every module's real runtime dependencies from its
Gradle .module metadata — the .pom is polluted by the flattened test-fixtures variant — and
checks them against what the projects declare, and checks the @(AndroidIgnoredJavaDependency)
list against the .pom pollution it neutralises. CI runs it before packing, so a dependency
upstream adds is a named failing coordinate rather than a NoClassDefFoundError in somebody's
app, and an ignore entry upstream retires is a warning rather than a place a real missing
dependency can hide.
Smaller improvements
- nuget.org now shows these notes:
docs/release-notes/<version>.mdis packed into
PackageReleaseNotes, with the releases page as fallback. - README versions can no longer go stale silently — the install snippets sat at
3.12.1.1
while3.12.1.2shipped;build/CheckReadmeVersions.shnow fails CI on drift. - The jctools/re2j versions, previously hand-synchronised across three projects, live once in
Directory.Build.props. - The README states plainly why the generated tier has no IntelliSense (upstream's sources jars
are Kotlin-only, and the binding toolchain's Javadoc import parses Java sources) and where the
documentation therefore lives.
net8 sunset
Stated policy, so the trade-off does not persist by inertia: the net8.0-android34.0 head —
past its platform support window since MAUI 8 left support on 14 May 2025, and the reason the
whole AndroidX/Kotlin dependency set is held below current — is dropped, and the held-back
versions unpinned, in the first release after .NET 8 itself leaves support on
10 November 2026.
Upgrading from 3.12.1.2
Nothing to change. A Release build with R8 enabled may now keep classes that previously
vanished — which is the fix, not a regression.
Full changelog: v3.12.1.2...v3.12.1.3
Packages
Bound against dd-sdk-android 3.12.1, targeting net8.0-android34.0, net9.0-android35.0 and net10.0-android36.0.
The first three components of
3.12.1.3are the dd-sdk-android 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.Internal.Android |
dd-sdk-android-internal |
3.12.1.3 |
DatadogNet.Core.Android |
dd-sdk-android-core |
3.12.1.3 |
DatadogNet.Logs.Android |
dd-sdk-android-logs |
3.12.1.3 |
DatadogNet.TraceApi.Android |
dd-sdk-android-trace-api |
3.12.1.3 |
DatadogNet.TraceInternal.Android |
dd-sdk-android-trace-internal |
3.12.1.3 |
DatadogNet.Trace.Android |
dd-sdk-android-trace |
3.12.1.3 |
DatadogNet.RUM.Android |
dd-sdk-android-rum |
3.12.1.3 |
DatadogNet.SessionReplay.Android |
dd-sdk-android-session-replay |
3.12.1.3 |
DatadogNet.SessionReplayMaterial.Android |
dd-sdk-android-session-replay-material |
3.12.1.3 |
DatadogNet.SessionReplayCompose.Android |
dd-sdk-android-session-replay-compose |
3.12.1.3 |
DatadogNet.Ndk.Android |
dd-sdk-android-ndk |
3.12.1.3 |
DatadogNet.WebView.Android |
dd-sdk-android-webview |
3.12.1.3 |
DatadogNet.OkHttp.Android |
dd-sdk-android-okhttp |
3.12.1.3 |
dotnet add package DatadogNet.RUM.Android --version 3.12.1.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.12.1.2
What's changed
Binding-only release. The native SDK is unchanged — still
dd-sdk-android 3.12.1 — and so are
the package IDs, namespaces and every existing signature. Upgrading is a version bump.
Everything here is an addition to the convenience layer, and every one exists because the
generated binding leaves a member technically reachable but effectively unusable from C#.
The two that matter most are blocked by Kotlin function types, which bind as interfaces rather
than delegates: you cannot pass a lambda, a method group, or an Action<>, so calling them means
declaring a Java.Lang.Object subclass and returning null for Kotlin's Unit. That is a lot of
ceremony for a header setter and a session id.
Package versions are
<dd-sdk-android version>.<binding revision>.3.12.1.2is
dd-sdk-android3.12.1, binding revision2. The fourth component belongs to this repository and
advances when the bindings or packaging change while the native artifacts stay put.
Added
Trace header injection — DatadogPropagation.Inject
The one that matters most. Distributed tracing is the reason most apps enable Trace at all, and this
was the wall in front of it:
fun <C> inject(context: DatadogSpanContext, carrier: C, setter: (C, String, String) -> Unit)That trailing lambda binds as Kotlin.Jvm.Functions.IFunction3. Getting it wrong does not fail
loudly — the request simply goes out with no trace headers, and the trace stops at the app.
var span = GlobalDatadogTracer.Get ().BuildSpan ("http.request").Start ();
foreach (var header in GlobalDatadogTracer.Get ().Propagate ().Inject (span.Context ()))
request.Headers.TryAddWithoutValidation (header.Key, header.Value);Three forms: one returning a new dictionary, one writing into a dictionary you own, and one taking
an Action<string, string> for carriers that are not dictionaries — an HttpRequestMessage, gRPC
metadata, a message envelope.
extract is deliberately not wrapped. Its signature nests a second Kotlin lambda — the SDK
hands you a visitor you call per header, whose Boolean return governs whether iteration continues
— and that contract is not documented anywhere the binding can see. Guessing it would produce
something that silently reads one header and stops. Extraction is also the rare direction for a
mobile app, which receives responses rather than serving requests.
Span outcome and identity — DatadogSpanExtensions
span.SetError (exception); // or SetError (kind, message, stack)
var traceId = span.GetTraceId (); // 32 lowercase hex
var spanId = span.GetSpanId (); // decimalSetError exists because addThrowable takes a java.lang.Throwable, which a .NET exception is
not — so the managed type, message and stack have to be set as separate fields for any of them to
reach Datadog. setError additionally takes a java.lang.Boolean, so even the flag needs boxing.
GetTraceId and GetSpanId render the ids the way dd-sdk-android's own DatadogInterceptor
does when it links a RUM resource to its APM trace: DatadogTraceId.toHexString() and
String.valueOf(long). The asymmetry — hex for one, decimal for the other — is Datadog's wire
format rather than a choice, and matching it exactly is what makes the correlation work.
toHexString() is toHexStringPadded(…, 32) on both DD128bTraceId and DD64bTraceId, so the
result is always 32 characters; a 64-bit id is the low half behind sixteen zeros, never a
16-character string.
Session id — RumMonitorExtensions.GetCurrentSessionIdAsync
var sessionId = await GlobalRumMonitor.Get ().GetCurrentSessionIdAsync ();getCurrentSessionId takes a kotlin.jvm.functions.Function1, so reading a value most apps want in
order to put it on a support ticket previously required an IFunction1 implementation returning
null for Kotlin's Unit.
Single-value attributes
DatadogAttributes.ToJava (value, key) is now public. RumMonitor.addAttribute,
addFeatureFlagEvaluation and Logger.addAttribute all take a bare java.lang.Object while
DatadogAttributes only exposed the map form, so a caller either hand-wrapped the value — which is
exactly what DatadogAttributes exists to avoid — or round-tripped a one-element dictionary.
monitor.AddAttribute ("cart.id", cartId);
monitor.AddFeatureFlagEvaluation ("new-checkout", true);
logger.AddAttribute ("tenant", tenantId);Resource overloads
StartResource, StopResource and two StopResourceWithError forms on RumMonitorExtensions,
taking int?/long? instead of Java.Lang.Integer/Java.Lang.Long, and an Exception overload.
The exception form also guards a trap the C# signature does not show: stackTrace is String in
Kotlin, not String?, so passing null reaches Java's own null check and throws — unlike
errorType beside it, and unlike addErrorWithStacktrace, both of which are genuinely nullable.
One thing deliberately not added
An earlier draft added a BuildSpan(string) overload, on the grounds that 3.x DatadogTracer
declares buildSpan(CharSequence) and callers were writing
BuildSpan(new Java.Lang.String(name)). That was wrong: the generator already emits
IDatadogTracerExtensions.BuildSpan(IDatadogTracer, string) in the same namespace, and a second one
made the call ambiguous. If you have been wrapping the operation name, you only need the using:
using Com.Datadog.Android.Trace.Api.Tracer;Documentation
build/packages.tsv now records what is not bound, and why — all fourteen dd-sdk-android*
artifacts Datadog publishes that this repository does not wrap, each with a reason. Datadog ships
27; thirteen are bound. The rest fall into four groups: Kotlin-ecosystem integrations whose idioms
have no C# meaning (-ktx, -rx, the two coroutine modules), instrumentation for Java libraries a
.NET app does not use (-glide, -coil, -fresco, -timber, -sqldelight), things that are not
libraries (-gradle-plugin, the BOM), and three worth revisiting — -compose, -tv and the two
OpenTelemetry modules.
The file already listed what is bound; the point of the addition is that "is X missing on purpose?"
now has an answer in the repository rather than in someone's memory.
Tests
94 package-layout tests pass, and the on-emulator suite grows from 13 checks to 17, all
running against the packed packages.
Until now this suite enabled Trace and stopped there — EnablesTrace registered a tracer and never
started a span — so the tracing path was configured and never driven. That 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. - Headers are injected 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. The
delegate form is driven too, and must write the same number of headers as the dictionary form. - The single-value attribute overloads are driven on RUM, feature flags and a logger, with
ToJavaasserted directly. - The session id is read through
GetCurrentSessionIdAsyncand asserted non-null; a null means
the Kotlin callback never fired, which is the failure theTaskwrapper exists to surface.
The harness gained async support to do the last of those.
Sample
samples/DatadogNet.Android.Example was still largely the MAUI project template — a hovercraft, a
click counter, and two Datadog calls. It is now the same shape as the iOS sample: sections for RUM,
Trace and Logs, and an on-screen activity log so it is useful without a Datadog account to send to.
The new Trace section traces an outgoing HttpRequestMessage end to end and records a failed
span.
It also had a real bug worth not shipping in a sample: OnDisappearing disposed the view scope and
then immediately started a new view, leaving one open for the rest of the session — collecting
every action and error that followed. Fixed.
Upgrading from 3.12.1.1
-<PackageReference Include="DatadogNet.RUM.Android" Version="3.12.1.1" />
+<PackageReference Include="DatadogNet.RUM.Android" Version="3.12.1.2" />Nothing is removed or renamed, and the native .aar files are byte-for-byte the same. All thirteen
packages move together, as they depend on each other at an exact version.
Full changelog: v3.12.1.1...v3.12.1.2
Packages
Bound against dd-sdk-android 3.12.1, targeting net8.0-android34.0, net9.0-android35.0 and net10.0-android36.0.
The first three components of
3.12.1.2are the dd-sdk-android 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.Internal.Android |
dd-sdk-android-internal |
3.12.1.2 |
DatadogNet.Core.Android |
dd-sdk-android-core |
3.12.1.2 |
DatadogNet.Logs.Android |
dd-sdk-android-logs |
3.12.1.2 |
DatadogNet.TraceApi.Android |
dd-sdk-android-trace-api |
3.12.1.2 |
DatadogNet.TraceInternal.Android |
dd-sdk-android-trace-internal |
[3.12.1.2](htt... |
2.26.3.2
What's changed
Same native SDK — dd-sdk-android 2.26.3
— with a documentation correction that changes which apps can use this line at all, and a set of
convenience overloads for the members that only look awkward from C#.
Package versions are
<dd-sdk-android version>.<binding revision>.2.26.3.2is
dd-sdk-android2.26.3, binding revision2. Nothing about the native artifacts changed.
Every one of these came out of building
DatadogNet, a cross-platform façade over these packages
and the iOS ones. Calling both SDKs through the same shape is what surfaced them.
⚠️ The minimum API level is 23, not 21
This corrects the 2.26.3.1 release notes and the README, and it removes one of the two reasons
those gave for choosing the 2.x line over 3.x.
The .aar manifests do declare minSdkVersion 21, and that is where the figure came from. It is
not reachable. Those .aars depend on an AndroidX generation in which androidx.savedstate 1.4.0
declares minSdkVersion 23, and the Android manifest merger takes the maximum across the whole
dependency graph rather than trusting the direct dependency. An app declaring 21 does not merely
misbehave on Android 5 — it fails to build:
uses-sdk:minSdkVersion 21 cannot be smaller than version 23 declared in library
… androidx.savedstate.savedstate-android.aar
Suggestion: use a compatible library with a minSdk of at most 21,
or increase this project's minSdk version to at least 23,
or use tools:overrideLibrary="androidx.savedstate" to force usage
(may lead to runtime failures)
So an app that still supports Android 5 or 5.1 cannot use these packages, and switching to the
3.x line costs it nothing on that count.
The tools:overrideLibrary escape is not recommended. It forces the library in and, as the error
itself says, may fail at runtime instead — a worse trade for the two API levels it buys.
The other reason to prefer 2.x is unaffected: tracing is still OpenTracing-based, and 3.0
removed it. That remains the deciding difference between the lines.
Nothing in the packages changed for this. It is a documentation fix, and it is here rather than in a
quiet README edit because an app on minSdk 21 will have discovered it as a build failure.
Added
DatadogAttributes.ToJava is public
The per-value converter behind DatadogAttributes.From. Several members take a bare value rather
than a map — RumMonitor.addAttribute, addFeatureFlagEvaluation, Logs.addAttribute,
Logger.addAttribute — and until now reaching them meant either hand-wrapping the value, which is
what DatadogAttributes exists to avoid, or round-tripping a one-element dictionary through
From to get at the result.
monitor.AddAttribute("build.channel", DatadogAttributes.ToJava("beta", "build.channel"));Or, better, through the new overloads below, which do it for you.
RUM convenience overloads
monitor.AddAttribute("build.channel", "beta");
monitor.AddFeatureFlagEvaluation("new-checkout", true);
monitor.StartResource("checkout", RumResourceMethod.Post, "https://api.example.com/orders");
monitor.StopResource("checkout", statusCode: 200, size: 1024, RumResourceKind.Native);
monitor.StopResourceWithError("checkout", exception);
var sessionId = await monitor.GetCurrentSessionIdAsync();StopResource takes int? and long? rather than Java.Lang.Integer and Java.Lang.Long. The
generated overload uses the Java boxes because both are nullable in Kotlin, so a C# caller has to
box through ValueOf and remember that null means "not known" rather than zero. Nullable value
types say the same thing in the language you are already writing.
GetCurrentSessionIdAsync is the one worth having. The generated GetCurrentSessionId takes a
kotlin.jvm.functions.Function1, which C# cannot express as a lambda at all — it binds as an
interface, so calling it means declaring a Java.Lang.Object subclass that implements IFunction1
and returns null for Kotlin's Unit. That is a lot of ceremony for a value most apps want in
order to paste it into a support ticket.
StopResourceWithError guards a non-null Kotlin parameter
RumMonitor.stopResourceWithError declares stackTrace: String — not String? — while
errorType beside it is nullable and addErrorWithStacktrace takes a nullable stack. The generated
C# signature shows all three as plain string, so nothing distinguishes them, and passing null for
the wrong one throws at runtime:
NullPointerException: Parameter specified as non-null is null: method
DatadogRumMonitor.stopResourceWithError, parameter stackTrace
The new overload takes string? and substitutes empty, so the C# signature says what Kotlin meant.
This is not a binding defect — the projection is faithful — but being faithful to Kotlin loses
information a C# caller needs, and the convenience layer is the right place to put it back.
Tracing convenience overloads
New in DatadogNet.Trace.Android, as Com.Datadog.Android.Trace.TracingExtensions:
using Com.Datadog.Android.Trace;
span.SetError(exception);
span.SetError("CheckoutError", "declined", stack);
span.Log(new Dictionary<string, object?> { ["event"] = "checkout.started" });
var headers = GlobalTracer.Get().InjectHeaders(span);SetError has no counterpart in io.opentracing.Span — dd-sdk-ios's OTSpan has one, this
does not. The Datadog convention on the Java side is an error tag plus four specific log fields,
which dd-trace turns into the span's error facets, and getting the field names wrong produces a span
that looks fine and is never counted as an error.
InjectHeaders exists because the obvious way silently produces nothing.
new TextMapInjectAdapter(myDictionary) compiles, runs, and gives you an empty dictionary: the
adapter's constructor takes an IDictionary<string, string>, which the binding marshals by
copying into a fresh java.util.HashMap. The SDK writes the headers into the copy, the managed
dictionary never sees them, and the request goes out untraced with no error anywhere.
InjectHeaders implements ITextMapInject instead, so the SDK calls back into managed code.
Log(IReadOnlyDictionary<string, object?>) is here because io.opentracing.Span.log takes
Map<String, ?>, which the binding projects as IDictionary<string, object> — a different
dictionary type from the IDictionary<string, Java.Lang.Object> every Datadog member takes, so
DatadogAttributes.From's output cannot be passed to it directly.
Logger.AddAttribute taking a plain value
logger.AddAttribute("session.kind", "e2e");Compatibility
No breaking changes. Every generated member is still there and every existing call still
compiles; the additions sit alongside them. Upgrading from 2.26.3.1 is a version bump.
Verified
All twelve packages pack across net8.0-android34.0, net9.0-android35.0 and
net10.0-android36.0 — except DatadogNet.SessionReplayCompose.Android, which is net9/net10 only.
The package-layout tests and the on-emulator smoke checks pass against the packed packages.
The new members are additionally exercised on an emulator by
DatadogNet's device checks, which drive them through a
cross-platform façade alongside the iOS equivalents.
Full changelog: v2.26.3.1...v2.26.3.2
Packages
Bound against dd-sdk-android 2.26.3, targeting net8.0-android34.0, net9.0-android35.0 and net10.0-android36.0.
The first three components of
2.26.3.2are the dd-sdk-android 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.Internal.Android |
dd-sdk-android-internal |
2.26.3.2 |
DatadogNet.Core.Android |
dd-sdk-android-core |
2.26.3.2 |
DatadogNet.Logs.Android |
dd-sdk-android-logs |
2.26.3.2 |
DatadogNet.OpenTracing.Android |
opentracing-api |
2.26.3.2 |
DatadogNet.Trace.Android |
dd-sdk-android-trace |
2.26.3.2 |
DatadogNet.RUM.Android |
dd-sdk-android-rum |
2.26.3.2 |
DatadogNet.SessionReplay.Android |
dd-sdk-android-session-replay |
2.26.3.2 |
DatadogNet.SessionReplayMaterial.Android |
dd-sdk-android-session-replay-material |
2.26.3.2 |
DatadogNet.SessionReplayCompose.Android |
dd-sdk-android-session-replay-compose |
2.26.3.2 |
DatadogNet.Ndk.Android |
dd-sdk-android-ndk |
2.26.3.2 |
DatadogNet.WebView.Android |
dd-sdk-android-webview |
2.26.3.2 |
DatadogNet.OkHttp.Android |
dd-sdk-android-okhttp |
2.26.3.2 |
dotnet add package DatadogNet.RUM.Android --version 2.26.3.2
Licensing
The binding code is MIT; the bundled native binaries are Apache-2.0, as built and
publishe...
2.26.3.1
What's changed
The 2.x line. Twelve packages binding dd-sdk-android 2.26.3
for .NET for Android and .NET MAUI.
dotnet add package DatadogNet.RUM.Android
Why a 2.x line exists
It is not simply an older 3.x. Two differences decide which line you want:
Android 5 support. 2.x has minSdk 21; dd-sdk-android 3.0 raised it to 23. An app that still
supports Android 5 or 5.1 can bind 2.x and cannot bind 3.x.
OpenTracing. 2.x tracing is OpenTracing-based — AndroidTracer implements
io.opentracing.Tracer, and you register it with GlobalTracer. 3.0 removed OpenTracing and
AndroidTracer outright. Tracing code does not port between the lines unchanged.
How the package set differs from 3.x
| 2.x (this line) | 3.x | |
|---|---|---|
| Packages | 12 | 13 |
| Trace modules | one: DatadogNet.Trace.Android |
three: Trace, TraceApi, TraceInternal |
| OpenTracing | DatadogNet.OpenTracing.Android |
none |
| Tracer entry point | AndroidTracer + GlobalTracer |
DatadogTracing + GlobalDatadogTracer |
| Minimum API | 21 | 23 |
DatadogNet.OpenTracing.Android is new and has no 3.x counterpart. It binds
io.opentracing:opentracing-api, -noop and -util 0.32.0, because no .NET binding for the Java
OpenTracing API exists on nuget.org — the OpenTracing package there is a native .NET
implementation of the same specification, sharing the name but none of the Java types.
Getting started with tracing
using Com.Datadog.Android.Trace;
using IO.Opentracing.Util;
using DdTrace = Com.Datadog.Android.Trace.Trace; // collides with Android.OS.Trace
DdTrace.Enable(new TraceConfiguration.Builder().Build());
var tracer = new AndroidTracer.Builder().SetService("my-app").Build();
GlobalTracer.RegisterIfAbsent(tracer);
var span = tracer.BuildSpan("checkout").Start();
span.SetTag("cart.items", new Java.Lang.Integer(3));
using (tracer.ActivateSpan(span)) { /* work */ }
span.Finish();The numeric SetTag overload is setTag(String, java.lang.Number), so pass a Java box rather than
a bare int — a C# int binds to the generic setTag(Tag<T>, T) overload and will not compile.
Everything else carries over from the 3.x line
RUM, Logs, Session Replay with the Material and Compose extensions, NDK crash reporting, WebView
tracking and the OkHttp integration behave the same, as does the convenience layer: IDisposable
view scopes, Dictionary<string, object?> attributes, and Exception overloads.
The same gotchas apply — TrackUserInteractions() not TrackInteractions(), Configuration.Builder
needing all four arguments, SessionReplay.Enable static while StartRecording is not, and MAUI
reporting one RUM view for the whole app unless you report views yourself.
What is not bound
The Session Replay wireframe mappers, the vendored dd-trace-java engine, and a handful of internal
types. All still ship in the .aar and still run. AndroidTracer and the whole
com.datadog.android.trace package bind without a single metadata rule.
Verified
All twelve packages pack across net8.0-android34.0, net9.0-android35.0 and
net10.0-android36.0 — except DatadogNet.SessionReplayCompose.Android, which is net9/net10 only.
87 package-layout tests pass, and 13 on-device smoke checks pass on an emulator against the packed
packages, including an OpenTracing span round-trip through AndroidTracer.
Full changelog: v3.12.1.1...v2.26.3.1
Packages
Bound against dd-sdk-android 2.26.3, targeting net8.0-android34.0, net9.0-android35.0 and net10.0-android36.0.
The first three components of
2.26.3.1are the dd-sdk-android 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.Internal.Android |
dd-sdk-android-internal |
2.26.3.1 |
DatadogNet.Core.Android |
dd-sdk-android-core |
2.26.3.1 |
DatadogNet.Logs.Android |
dd-sdk-android-logs |
2.26.3.1 |
DatadogNet.OpenTracing.Android |
opentracing-api |
2.26.3.1 |
DatadogNet.Trace.Android |
dd-sdk-android-trace |
2.26.3.1 |
DatadogNet.RUM.Android |
dd-sdk-android-rum |
2.26.3.1 |
DatadogNet.SessionReplay.Android |
dd-sdk-android-session-replay |
2.26.3.1 |
DatadogNet.SessionReplayMaterial.Android |
dd-sdk-android-session-replay-material |
2.26.3.1 |
DatadogNet.SessionReplayCompose.Android |
dd-sdk-android-session-replay-compose |
2.26.3.1 |
DatadogNet.Ndk.Android |
dd-sdk-android-ndk |
2.26.3.1 |
DatadogNet.WebView.Android |
dd-sdk-android-webview |
2.26.3.1 |
DatadogNet.OkHttp.Android |
dd-sdk-android-okhttp |
2.26.3.1 |
dotnet add package DatadogNet.RUM.Android --version 2.26.3.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/.
3.12.1.1
What's changed
First release. Thirteen packages binding dd-sdk-android 3.12.1
for .NET for Android and .NET MAUI.
What you get
RUM, Logs, Trace, Session Replay (with the Material and Compose extensions), NDK crash reporting,
WebView tracking and the OkHttp integration — every documented Datadog Android feature, reachable
from C#.
dotnet add package DatadogNet.RUM.Android
Start with DatadogNet.RUM.Android; it pulls in Core and Internal. Add the features you actually
enable. There is no façade package, because dd-sdk-android has no DatadogObjc equivalent and
inventing one would make every app pay for Session Replay and NDK crash reporting to use RUM.
Version numbering
3.12.1.1 is dd-sdk-android 3.12.1, binding revision 1. The fourth component belongs to
this repository and advances when the bindings or packaging change while the native artifacts stay
put.
Things worth knowing before you start
AndroidTracer no longer exists. dd-sdk-android 3.0 removed it together with the OpenTracing
dependency. Use DatadogTracing.NewTracerBuilder(Datadog.Instance).Build() and register it with
GlobalDatadogTracer.RegisterIfAbsent.
TrackUserInteractions(), not TrackInteractions(). Datadog's own documentation still shows
the latter for Android; it is not in the 3.x binary API.
Trace collides with Android.OS.Trace. Alias it:
using DdTrace = Com.Datadog.Android.Trace.Trace;.
Kotlin's default parameter values do not survive into C#. Where upstream marked a member
@JvmOverloads you get the arity ladder; where it did not, pass every argument.
Configuration.Builder is the one you will notice — pass variant and service explicitly.
Some object members are static and some are not. SessionReplay.Enable is static but
StartRecording/StopRecording are SessionReplay.Instance.StartRecording(...); the same applies
to GlobalDatadogTracer.Clear. That asymmetry is upstream's.
MAUI reports one RUM view for the whole app unless you report views yourself, because every
page renders into a single Activity. GlobalRumMonitor.Get().StartView("key", "Name") returns a
scope you can wrap in a using.
Convenience API
Each package adds a small hand-written layer over the generated binding: IDisposable view scopes,
Dictionary<string, object?> attributes instead of hand-wrapped Java.Lang.Objects, and Exception
overloads that fold the managed type, message and stack into error.kind, error.message and
error.stack. Nothing is hidden or renamed — the generated members are all still there.
What is not bound
The Session Replay wireframe mappers, dd-sdk-android-trace-internal's whole surface, and a
handful of internal types. All of them still ship in the .aar and still run; what you lose is
authoring a custom wireframe mapper in C#. Every omission is explained next to the rule that makes
it, in the relevant Transforms/Metadata.xml.
Target frameworks
All thirteen packages target net8.0-android34.0, net9.0-android35.0 and net10.0-android36.0,
except DatadogNet.SessionReplayCompose.Android, which is net9/net10 only — Compose's last net8
build pins an AndroidX SavedState old enough to collide with what a MAUI app resolves.
Build your app with MAUI 10. MAUI 9 cannot build against the AndroidX generation these packages
depend on: a plain MAUI 9 app with nothing but Xamarin.AndroidX.AppCompat 1.7.1.1 added fails
generating Java callable wrappers with a NullReferenceException inside the .NET Android SDK, with no
Datadog package present. That is an SDK defect, and MAUI 10 is unaffected.
Packages
Bound against dd-sdk-android 3.12.1, targeting net8.0-android34.0, net9.0-android35.0 and net10.0-android36.0.
The first three components of
3.12.1.1are the dd-sdk-android 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.Internal.Android |
dd-sdk-android-internal |
3.12.1.1 |
DatadogNet.Core.Android |
dd-sdk-android-core |
3.12.1.1 |
DatadogNet.Logs.Android |
dd-sdk-android-logs |
3.12.1.1 |
DatadogNet.TraceApi.Android |
dd-sdk-android-trace-api |
3.12.1.1 |
DatadogNet.TraceInternal.Android |
dd-sdk-android-trace-internal |
3.12.1.1 |
DatadogNet.Trace.Android |
dd-sdk-android-trace |
3.12.1.1 |
DatadogNet.RUM.Android |
dd-sdk-android-rum |
3.12.1.1 |
DatadogNet.SessionReplay.Android |
dd-sdk-android-session-replay |
3.12.1.1 |
DatadogNet.SessionReplayMaterial.Android |
dd-sdk-android-session-replay-material |
3.12.1.1 |
DatadogNet.SessionReplayCompose.Android |
dd-sdk-android-session-replay-compose |
3.12.1.1 |
DatadogNet.Ndk.Android |
dd-sdk-android-ndk |
3.12.1.1 |
DatadogNet.WebView.Android |
dd-sdk-android-webview |
3.12.1.1 |
DatadogNet.OkHttp.Android |
dd-sdk-android-okhttp |
3.12.1.1 |
dotnet add package DatadogNet.RUM.Android --version 3.12.1.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/.