DatadogNet.Core.Android
3.12.1.4
dotnet add package DatadogNet.Core.Android --version 3.12.1.4
NuGet\Install-Package DatadogNet.Core.Android -Version 3.12.1.4
<PackageReference Include="DatadogNet.Core.Android" Version="3.12.1.4" />
<PackageVersion Include="DatadogNet.Core.Android" Version="3.12.1.4" />
<PackageReference Include="DatadogNet.Core.Android" />
paket add DatadogNet.Core.Android --version 3.12.1.4
#r "nuget: DatadogNet.Core.Android, 3.12.1.4"
#:package DatadogNet.Core.Android@3.12.1.4
#addin nuget:?package=DatadogNet.Core.Android&version=3.12.1.4
#tool nuget:?package=DatadogNet.Core.Android&version=3.12.1.4
DatadogNet.Android
.NET for Android and .NET MAUI bindings for the native
Datadog Android SDK (dd-sdk-android).
Enable Datadog Real User Monitoring, Logs, Trace, Session Replay, WebView tracking and native crash
reporting from C#, in a net8.0-android, net9.0-android or net10.0-android app.
dotnet add package DatadogNet.RUM.Android
using Com.Datadog.Android;
using Com.Datadog.Android.Core.Configuration;
using Com.Datadog.Android.Privacy;
using Com.Datadog.Android.Rum;
var configuration = new Configuration.Builder(
clientToken: "<CLIENT_TOKEN>", env: "production", variant: "", service: "my-app")
.UseSite(DatadogSite.Us1)
.Build();
Datadog.Initialize(context, configuration, TrackingConsent.Granted);
Rum.Enable(new RumConfiguration.Builder("<RUM_APPLICATION_ID>").Build());
Contents
- Packages
- Installing
- Usage
- Convenience API
- How this repository works
- Building locally
- Upgrading the Datadog SDK
- Releasing
- Troubleshooting
- Licence
Packages
Thirteen packages, one per dd-sdk-android module. Versions are
<dd-sdk-android version>.<binding revision> — 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.
| Package | Wraps | Depends on | What it is for |
|---|---|---|---|
DatadogNet.RUM.Android |
dd-sdk-android-rum |
Core, Internal | The usual starting point. Real User Monitoring — views, actions, resources, errors, long tasks and mobile vitals. |
DatadogNet.Core.Android |
dd-sdk-android-core |
Internal | SDK initialization, configuration, consent, user and account info. Every feature needs it. |
DatadogNet.Internal.Android |
dd-sdk-android-internal |
— | Shared foundation every other module is built on. |
DatadogNet.Logs.Android |
dd-sdk-android-logs |
Core, Internal | Log collection. |
DatadogNet.Trace.Android |
dd-sdk-android-trace |
Core, Internal, TraceApi, TraceInternal | Distributed tracing (APM). |
DatadogNet.TraceApi.Android |
dd-sdk-android-trace-api |
Core, Internal | The tracing contract — IDatadogTracer, IDatadogSpan, IDatadogScope. |
DatadogNet.TraceInternal.Android |
dd-sdk-android-trace-internal |
Core, Internal, TraceApi | The tracing engine. Ships the module; binds nothing. |
DatadogNet.SessionReplay.Android |
dd-sdk-android-session-replay |
Core, Internal | Session Replay. Requires RUM. |
DatadogNet.SessionReplayMaterial.Android |
dd-sdk-android-session-replay-material |
SessionReplay | Records Material Components faithfully. |
DatadogNet.SessionReplayCompose.Android |
dd-sdk-android-session-replay-compose |
SessionReplay, Internal | Records Jetpack Compose content. net9/net10 only. |
DatadogNet.Ndk.Android |
dd-sdk-android-ndk |
Core, Internal | Native (NDK) crash capture. Opt-in. |
DatadogNet.WebView.Android |
dd-sdk-android-webview |
Core, Internal | Bridges RUM/Logs out of a WebView. Opt-in. |
DatadogNet.OkHttp.Android |
dd-sdk-android-okhttp |
Internal, RUM, Trace | Reports outgoing HTTP calls as RUM resources and propagates tracing headers. |
Most apps need one or two lines:
<PackageReference Include="DatadogNet.RUM.Android" Version="3.12.1.4" />
<PackageReference Include="DatadogNet.Logs.Android" Version="3.12.1.4" />
DatadogNet.Core.Android arrives transitively — you rarely reference it directly, though you will
using Com.Datadog.Android; to reach Datadog.Initialize.
There is no façade package. The iOS bindings have
DatadogNet.Objc.iOS, which re-exports the whole SDK, becausedd-sdk-iosships aDatadogObjcframework that does exactly that.dd-sdk-androidhas no equivalent, and inventing one would mean every app paying for Session Replay and NDK crash reporting to use RUM. Reference the features you actually enable.
Target frameworks: net8.0-android34.0, net9.0-android35.0, 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, and holding the whole
repository back to match would have broken MAUI consumers of all thirteen packages to keep net8 for
the one that needs Compose.
Minimum API level: 23 (Android 6.0) — dd-sdk-android 3.x raised its own floor from 21.
net8 sunset. The net8 head is already past its platform support window — the net8 mobile workloads left support with MAUI 8 on 14 May 2025 — and ships for the apps that still target it, with the emulator checks run against it. It is also what holds the whole AndroidX/Kotlin dependency set below current (see
Directory.Build.props). So the trade-off does not persist by inertia: the net8 head is dropped, and the held-back versions unpinned, in the first release after .NET 8 itself leaves support on 10 November 2026.
MAUI version: build with MAUI 10. See Building locally.
Installing
<ItemGroup>
<PackageReference Include="DatadogNet.RUM.Android" Version="3.12.1.4" />
</ItemGroup>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">23</SupportedOSPlatformVersion>
The packages are Android-only. In a multi-targeted MAUI project, guard the reference so an iOS or Windows head does not try to restore them:
<ItemGroup Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">
<PackageReference Include="DatadogNet.RUM.Android" Version="3.12.1.4" />
</ItemGroup>
Usage
The C# names are the Kotlin/Java ones projected into C#, so com.datadog.android.rum.Rum becomes
Com.Datadog.Android.Rum.Rum and enable(...) becomes Enable(...).
samples/DatadogNet.Android.Example is a working MAUI app
that does all of the below; Datadog.cs is the
setup in one file.
Initialize
Once, as early as possible. In MAUI that means MauiProgram.CreateMauiApp, or better still your
Application subclass — crash reporting only covers what happens after it is enabled, and startup
crashes are the ones worth catching.
using Com.Datadog.Android;
using Com.Datadog.Android.Core.Configuration;
using Com.Datadog.Android.Privacy;
var configuration = new Configuration.Builder(
clientToken: "<CLIENT_TOKEN>", env: "production", variant: "", service: "my-app")
.UseSite(DatadogSite.Us1) // Us1, Us3, Us5, Eu1, Ap1, Ap2, Uk1, Us1Fed, Us2Fed
.SetBatchSize(BatchSize.Medium)
.SetUploadFrequency(UploadFrequency.Average)
.Build();
Datadog.Initialize(context, configuration, TrackingConsent.Granted);
Datadog.SetVerbosity((int)Android.Util.LogPriority.Warn); // SDK problems to logcat
Configuration.Builder takes all four arguments — Kotlin's defaults for variant and service
do not survive into C#, so pass "" and your service name explicitly.
RUM
using Com.Datadog.Android.Rum;
using Com.Datadog.Android.Rum.Tracking;
var rum = new RumConfiguration.Builder("<RUM_APPLICATION_ID>")
.SetSessionSampleRate(100f)
.TrackUserInteractions()
.UseViewTrackingStrategy(new ActivityViewTrackingStrategy(true))
.Build();
Rum.Enable(rum);
TrackUserInteractions(), notTrackInteractions(). Datadog's own documentation still shows the latter; it does not exist in 3.x.
MAUI renders every page into a single Activity, so ActivityViewTrackingStrategy reports one
view for the whole app. Report pages yourself instead:
var monitor = GlobalRumMonitor.Get();
using (monitor.StartView("checkout", "Checkout"))
{
monitor.AddAction(RumActionType.Tap, "pay", new Dictionary<string, object?>
{
["cart.total"] = 42.50m,
});
try { /* ... */ }
catch (Exception exception) { monitor.AddError(exception); }
}
StartView, AddAction and AddError above are from the convenience API.
Logs
using Com.Datadog.Android.Log;
Logs.Enable(new LogsConfiguration.Builder().Build());
var logger = new Logger.Builder()
.SetName("app")
.SetBundleWithRumEnabled(true)
.Build();
logger.Log(LogLevel.Info, "user signed in");
logger.Log(LogLevel.Error, "payment failed", exception, new Dictionary<string, object?>
{
["order.id"] = orderId,
});
Trace
using Com.Datadog.Android.Trace;
Trace.Enable(new TraceConfiguration.Builder().Build());
GlobalDatadogTracer.RegisterIfAbsent(DatadogTracing.NewTracerBuilder().Build());
AndroidTraceris gone. dd-sdk-android 3.0 removed it along with the OpenTracing dependency.DatadogTracing.NewTracerBuilder()is the replacement. Note also thatGlobalDatadogTracer.GetandRegisterIfAbsentare static whileClearandGetOrNullare not — the latter areGlobalDatadogTracer.Instance.Clear().
Session Replay
using Com.Datadog.Android.Sessionreplay;
SessionReplay.Enable(new SessionReplayConfiguration.Builder(100f)
.SetTextAndInputPrivacy(TextAndInputPrivacy.MaskAll)
.SetImagePrivacy(ImagePrivacy.MaskAll)
.SetTouchPrivacy(TouchPrivacy.Hide)
.Build());
Requires RUM. The three privacy levels decide what is redacted on the device, before anything is
uploaded. Loosen them deliberately. The older single SessionReplayPrivacy is deprecated upstream
and still bound, but prefer the three.
Enableis static;StartRecordingandStopRecordingare not — they areSessionReplay.Instance.StartRecording(sdkCore). That asymmetry is upstream's, not the binding's.
Add DatadogNet.SessionReplayMaterial.Android or DatadogNet.SessionReplayCompose.Android and
register the extension when your app draws Material or Compose content:
.AddExtensionSupport(new MaterialExtensionSupport())
Native crash reporting
Add DatadogNet.Ndk.Android, then enable it after initializing the SDK:
using Com.Datadog.Android.Ndk;
NdkCrashReports.Enable();
Crashes are reported on the next launch, as RUM errors and logs. Upload your native symbols to
Datadog for symbolication. Like DatadogNet.WebView.Android, the package ships consumer R8
keep-rules for its JNI-only entry point, so Release shrinking cannot strip NdkCrashReports.
Network instrumentation
Add DatadogNet.OkHttp.Android. This is what makes HTTP calls visible in RUM:
using Com.Datadog.Android.Okhttp;
var client = new OkHttpClient.Builder()
.AddInterceptor(new DatadogInterceptor.Builder(hosts).Build())
.EventListenerFactory(new DatadogEventListener.Factory())
.Build();
HttpClient in .NET does not route through OkHttp unless you configure
AndroidMessageHandler, so a MAUI app using HttpClient will not report resources automatically.
WebView tracking
using Com.Datadog.Android.Webview;
WebViewTracking.Enable(webView, new List<string> { "example.com" });
The package ships consumer R8/ProGuard keep-rules (under buildTransitive/), because
WebViewTracking is reached from .NET through JNI alone and a shrunk Release build would
otherwise remove it and throw ClassNotFoundException at runtime. Nothing to configure — NuGet
imports them into the consuming app automatically.
User info and consent
Datadog.SetUserInfo(userId: "user-123", name: "Ada Lovelace", email: "ada@example.com");
Datadog.SetTrackingConsent(TrackingConsent.Pending);
Pending collects events but holds them on the device until consent is granted or refused — which
is what a prompt-on-first-launch flow wants.
Convenience API
The generated binding is a faithful projection of Kotlin, which makes some things clumsy in C#. Each package adds a small hand-written layer over it. The generated members are all still there; nothing is hidden or renamed.
| Instead of | Write |
|---|---|
monitor.StartView("k", "Name", new Dictionary<string, Java.Lang.Object>()) … StopView |
using (monitor.StartView("k", "Name")) |
hand-wrapping every value in Java.Lang.Object |
new Dictionary<string, object?> { ["k"] = 42 } on any overload below |
monitor.AddAction(type, name, javaMap) |
monitor.AddAction(type, name, attributes?) |
monitor.AddError(message, source, throwable, javaMap) with a Throwable you do not have |
monitor.AddError(exception) |
logger.Log(priority, message, throwable, javaMap) |
logger.Log(level, message, exception?, attributes?) |
The view scope is the one worth adopting everywhere: the raw API is a StartView / StopView pair
matched by key, and a view left open by an early return or an exception captures every later action
and error in the session.
Attribute values may be strings, any numeric type, bool, DateTime, DateTimeOffset, Guid,
enums, Java.Lang.Objects, arrays and nested dictionaries. Anything else throws ArgumentException
rather than being silently dropped.
IntelliSense on the generated tier is thin — wired, but limited by Kotlin. Every binding project now feeds upstream's
-sources.jarto the binding generator (@(JavaSourceJar), downloaded and SHA-256-pinned like every other artifact), which imports API documentation into the generated XML docs. The importer parses Java sources, though, and dd-sdk-android's sources jars are almost entirely.kt— so it extracts what it can, and most of the raw surface stays bare. The convenience layer above is fully documented; for the raw surface the C# names map 1:1 onto the Kotlin ones, so upstream's own reference is the documentation.
What is not bound
Three groups of members are deliberately absent, each for a reason recorded next to the rule that
removes it in the relevant Transforms/Metadata.xml:
- Session Replay wireframe mappers (
...recorder.mapper, 28 types). The hierarchy is generic and its single member erases tomap(Object, …), which the generator cannot bind. The types still ship in the.aarand still run, so recording is unaffected — including through the Material and Compose extensions. What you cannot do is author a custom mapper in C#. dd-sdk-android-trace-internal's entire surface. It is the dd-trace-java engine vendored undercom.datadog.trace.**; the tracing API you call iscom.datadog.android.trace.*, inTraceandTraceApi. The package ships the module without binding it.- A handful of internal types —
EvictingQueue,SessionRebasedSampler,OkHttpRequestInfoBuilder— plus theExecutorServicemembers ofFlushableExecutorServiceand the abstractbuild()onTracingInterceptor.BaseBuilder. All are generator failures on erased generics or covariant returns, and none is reachable from a documented API.
Kotlin constructs that do not project into C# at all are a property of the language boundary,
not of these bindings: extension functions (Session Replay's View.setSessionReplayHidden, the RUM
resource helpers, everything in the coroutine and Rx integrations) land on synthetic …Kt classes,
and inline functions taking lambdas are not callable. Default parameter values do not exist in
C#; where upstream marked a member @JvmOverloads you get the arity ladder, and where it did not,
you must pass every argument.
How this repository works
Maven Central: com.datadoghq:dd-sdk-android-*:3.12.1
│ @(AndroidMavenLibrary) — resolves the .aar and its .pom, cached under
│ ~/.cache/dotnet-android/MavenCacheDirectory
▼
src/DatadogNet.<Package>.Android/ — binding project + committed Transforms/Metadata.xml
│ build/BuildNugets.sh — pack twice (net9 band, net10 band), then merge
▼
artifacts/*.nupkg ──► nuget.org
Nothing is committed and nothing is compiled from source. There is no fetch script: the .NET
Android SDK resolves each module from Maven Central, and — because it reads the .pom too — fails
the build when an .aar links against Java types that no referenced package provides. That check
is why this repository has no libs/ directory and why a missing Java dependency is a build error
here rather than a NoClassDefFoundError in somebody's app.
That check is about completeness; authenticity is pinned separately. Every artifact this
repository resolves has a SHA-256 recorded in build/maven-checksums.txt,
and the VerifyDatadogMavenArtifactHashes target checks the bytes actually resolved — on both the
@(AndroidMavenLibrary) path and the direct-download fallback — against it on every build. A hash
that changes for an unchanged version fails the build instead of shipping;
build/UpdateMavenChecksums.sh regenerates the pins after a
version bump.
Why the two-pass build. Each .NET SDK's Android workload ships reference packs for the current
target framework and the previous one — the .NET 9 band builds net8 + net9, the .NET 10 band builds
net9 + net10. No single SDK builds all three, so BuildNugets.sh packs twice and
merge-packages.py grafts the net10 assets into the net9 packages,
carrying the dependency group across with them.
Four Java dependencies have no .NET binding and are embedded as plain Java rather than left to
fail at runtime: Kronos (Core), JCTools and RE2/J (TraceApi), and androidx.metrics
(RUM). Each is embedded in exactly one package — the same classes contributed twice would be
dexed twice and fail the consuming app's build.
Layout
| Path | What |
|---|---|
src/DatadogNet.*.Android/ |
One binding project per module. Transforms/Metadata.xml is committed and explains every rule. |
src/Datadog.Binding.props |
Everything the thirteen projects share, so each .csproj is its identity and its dependencies. |
src/DatadogNet.*/Additions/ |
The hand-written convenience API. |
build/packages.tsv |
The package set. The build script, both workflows and the tests all read it. |
build/ |
Pack and merge scripts. |
tests/DatadogNet.Android.PackageTests/ |
Asserts the shape of the packed .nupkgs. |
tests/DatadogNet.Android.DeviceTests/ |
An Android app that consumes the packed packages and drives the real SDK on an emulator. |
samples/DatadogNet.Android.Example/ |
A MAUI app doing the same, the way an app would. |
The tests consume the packed .nupkgs from artifacts/ rather than referencing the projects, so
they exercise what actually gets published — including the inter-package dependencies, which a
ProjectReference would bypass entirely.
DatadogNet.sln deliberately contains the binding projects and the tests but not the sample,
so dotnet build DatadogNet.sln does not require the MAUI workload.
Building locally
Requires the .NET 9 and .NET 10 SDKs with the android workload, a JDK, and the Android SDK with
platforms 34, 35 and 36.
./build/BuildNugets.sh # packs all thirteen into artifacts/
dotnet test tests/DatadogNet.Android.PackageTests
Run the on-emulator smoke tests against the packed packages, with an emulator already booted:
./.github/scripts/run-emulator-tests.sh 3.12.1.4 net9.0-android35.0
Build and run the sample:
cd /tmp && dotnet new globaljson --sdk-version 10.0.301 --force
dotnet build <repo>/samples/DatadogNet.Android.Example/DatadogNet.Android.Example.csproj -t:Run
The sample targets
net10.0-android36.0and needs the .NET 10 SDK, which this repository'sglobal.jsondoes not select — hence the scratch directory. That is a constraint on the MAUI version you build the sample with, not on what the packages support: MAUI 9 cannot build against the AndroidX generation these packages depend on, and it is an SDK defect rather than anything the bindings do. A plain MAUI 9 app with nothing butXamarin.AndroidX.AppCompat 1.7.1.1added fails the same way, with no Datadog package present.
Upgrading the Datadog SDK
One script runs every mechanical step, in order, stopping at the first failure:
./build/BumpNativeVersion.sh 3.13.0
It bumps DatadogNativeVersion and resets DatadogBindingRevision to 1 in
Directory.Build.props; re-pins every artifact's SHA-256
(UpdateMavenChecksums.sh, which PGP-verifies the Datadog
downloads when gpg is present); regenerates the consumer R8 keep-rules from the new .aars
(generate-r8-rules.sh); re-checks every module's declared
dependencies against its Gradle metadata
(verify-transitive-deps.py); rewrites this README's pinned
versions; and scaffolds docs/release-notes/<version>.md. What remains is judgement:
- Review the diffs. In
build/maven-checksums.txt, only artifacts whose version changed should have a changed hash — anything else is the event the pins exist to catch. - Re-check each
Transforms/Metadata.xml. A removal rule that no longer matches anything becomes aBG8A00warning rather than an error, so a rule that upstream has fixed will linger silently. Same for the@(AndroidIgnoredJavaDependency)block insrc/Datadog.Binding.props: verify-transitive-deps.py warns about entries no current.pommentions, because a stale ignore is where a real missing dependency can hide. - Review the regenerated
src/*/buildTransitive/*.profor upstream rule changes, and extend the curated keeps ingenerate-r8-rules.shif the new line added entry points. ./build/BuildNugets.sh— every module is resolved fresh from Maven Central and verified against the new pins — then both test suites.
To spelunk one module's dependencies by hand, read the Gradle module metadata, not the
.pom:
curl -s https://repo1.maven.org/maven2/com/datadoghq/dd-sdk-android-core/3.13.0/dd-sdk-android-core-3.13.0.module \
| python3 -c "import json,sys; [print(d['group']+':'+d['module'], d['version']['requires']) for v in json.load(sys.stdin)['variants'] if v['name']=='releaseVariantReleaseRuntimePublication' for d in v.get('dependencies',[])]"
The .pom is wrong: Gradle flattens the test-fixtures variant into it, so it lists JUnit,
Mockito, AssertJ, Elmyr, kotlin-reflect and a dd-sdk-android.tools:unit:unspecified that
resolves nowhere. Those are neutralised by the @(AndroidIgnoredJavaDependency) block, and
verify-transitive-deps.py keeps both directions honest on every CI run: a dependency upstream
adds is a named failing coordinate, an ignore entry upstream retires is a warning.
If Datadog adds or removes a module, add or remove a row in build/packages.tsv and the matching
project — the build script, the workflows and the package tests all follow from it.
Releasing
Tag it. v3.12.1.4 builds, tests, publishes all thirteen packages to nuget.org via trusted
publishing, and creates a GitHub release. The tag drives which native SDK is bound, so an older
line can be released by tagging it.
Pull requests publish a -beta.<pr>.<run> prerelease of the whole set.
Both run the same build.yml: pack, package tests, and the emulator
smoke tests. Pull requests additionally compile the MAUI sample against the packed packages;
releases do not, since the commit being tagged has already been through that check and it would
otherwise put a MAUI workload install between the packages being built and being published.
Curated notes in docs/release-notes/<version>.md replace the generated commit list when present.
Troubleshooting
Nothing appears in Datadog. Check UseSite matches your organisation's region — this is the
most common cause. Call Datadog.SetVerbosity((int)LogPriority.Verbose) to see the SDK's own
diagnostics in logcat.
NoClassDefFoundError at runtime. A Java dependency did not make it into the app. Usually a
partially restored package; clear the cached copies and restore again:
rm -rf ~/.nuget/packages/datadognet.*. If it happens only in a shrunk build (R8 on, i.e.
AndroidLinkTool=r8) and names a Datadog class, see the next entry.
R8 / Java shrinking. Every package ships consumer keep-rules under buildTransitive/ —
generated by build/generate-r8-rules.sh and applied to your app
automatically whenever R8 runs. Two sections each: upstream's own consumer rules, recovered from
the .aar because .NET for Android never feeds an embedded proguard.txt to R8, and curated
keeps for the entry surface C# reaches through JNI alone — reflection a Java shrinker cannot see,
which would otherwise remove Datadog, Rum, the configuration builders and every other entry
point from a shrunk build. CI runs one emulator leg with R8 on, so the rules are exercised
against a real shrink on every build. If a shrunk build still reports a Datadog class missing,
add a -keep for anything you reach only through your own reflection — and open an issue,
because a class reachable from the documented API belongs in the shipped rules.
Duplicate class when building the app. Two packages are contributing the same Java classes.
The four embedded third-party libraries are each owned by exactly one package for this reason — if
you added a PackageReference for one of them yourself, remove it.
NU1107 on Xamarin.AndroidX.SavedState in a net8 app. Two packages in the AndroidX graph
the bindings pull in disagree about SavedState: Navigation.Common 2.9.6 wants >= 1.4.0, while
SavedState.Ktx 1.3.2 — reached through Activity.Ktx — pins [1.3.2, 1.3.3). The .NET 9 and
.NET 10 SDKs resolve the higher version and emit NU1608; the .NET 8 SDK refuses outright:
error NU1107: Version conflict detected for Xamarin.AndroidX.SavedState. Install/reference
Xamarin.AndroidX.SavedState 1.4.0 directly to project ... to resolve this issue.
Do what the error says — this is a direct reference that exists only to settle the transitive conflict, and one every net8 consumer of these packages needs:
<PackageReference Include="Xamarin.AndroidX.SavedState" Version="1.4.0" />
Scope it to net8 in a multi-targeted project: net9 and net10 settle their own graphs higher, and
pinning 1.4.0 there is a downgrade that fails the other way round (NU1605).
XA4241/XA4242 when building this repository. Java dependency verification found an
unsatisfied dependency. Add the matching binding PackageReference to the project; the error names
the Microsoft-maintained package when one exists.
'Trace' is an ambiguous reference. Com.Datadog.Android.Trace.Trace collides with
Android.OS.Trace. Alias it: using DdTrace = Com.Datadog.Android.Trace.Trace;.
'Logs' does not exist in the namespace 'DatadogNet.Logs' — or the same for Trace or
SessionReplay. Your app's own namespace starts with DatadogNet., and C# resolves a bare name
outward through enclosing namespaces before looking at using directives. The bindings avoid
creating DatadogNet.<Feature> namespaces for exactly this reason, so if you see it, something in
your solution declares one. Rename it or fully qualify the call.
RUM records one view for the whole app. Expected in MAUI: every page renders into a single
Activity. Report views yourself with monitor.StartView(...).
HTTP calls do not appear as RUM resources. HttpClient does not route through OkHttp by
default. Use the OkHttp client directly, or configure AndroidMessageHandler.
Licence
The binding code in this repository is MIT. The native artifacts the packages ship are
built and published by Datadog and are Apache-2.0, as are Kronos, JCTools and androidx.metrics;
RE2/J is under the Go licence. Every package declares MIT AND Apache-2.0 and carries the MIT
text, the Apache-2.0 text and Datadog's NOTICE under licenses/.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0-android34.0 is compatible. net9.0-android was computed. net9.0-android35.0 is compatible. net10.0-android was computed. net10.0-android36.0 is compatible. |
-
net10.0-android36.0
- DatadogNet.Internal.Android (>= 3.12.1.4)
- GoogleGson (>= 2.13.2)
- Square.OkHttp3 (>= 4.12.0.10)
- Xamarin.AndroidX.Annotation (>= 1.9.1.5)
- Xamarin.AndroidX.Collection (>= 1.5.0.3)
- Xamarin.AndroidX.Work.Runtime (>= 2.11.0)
- Xamarin.Kotlin.StdLib (>= 2.2.21)
-
net8.0-android34.0
- DatadogNet.Internal.Android (>= 3.12.1.4)
- GoogleGson (>= 2.13.2)
- Square.OkHttp3 (>= 4.12.0.10)
- Xamarin.AndroidX.Annotation (>= 1.9.1.5)
- Xamarin.AndroidX.Collection (>= 1.5.0.3)
- Xamarin.AndroidX.Work.Runtime (>= 2.11.0)
- Xamarin.Kotlin.StdLib (>= 2.2.21)
-
net9.0-android35.0
- DatadogNet.Internal.Android (>= 3.12.1.4)
- GoogleGson (>= 2.13.2)
- Square.OkHttp3 (>= 4.12.0.10)
- Xamarin.AndroidX.Annotation (>= 1.9.1.5)
- Xamarin.AndroidX.Collection (>= 1.5.0.3)
- Xamarin.AndroidX.Work.Runtime (>= 2.11.0)
- Xamarin.Kotlin.StdLib (>= 2.2.21)
NuGet packages (9)
Showing the top 5 NuGet packages that depend on DatadogNet.Core.Android:
| Package | Downloads |
|---|---|
|
DatadogNet
One cross-platform Datadog API for .NET MAUI: RUM, Logs, Trace and Session Replay on Android, iOS and Mac Catalyst from shared code, over the native dd-sdk-android and dd-sdk-ios bindings. Restores and no-ops on Windows, so a multi-headed app needs no conditionals. |
|
|
DatadogNet.Trace.Android
.NET for Android / .NET MAUI bindings for the native Datadog Android SDK's dd-sdk-android-trace module: distributed tracing (APM) through Trace, TraceConfiguration, DatadogTracing and GlobalDatadogTracer. Built against dd-sdk-android 3.12.1. Note that dd-sdk-android 3.0 removed AndroidTracer and the OpenTracing dependency; DatadogTracing.NewTracerBuilder is the replacement. Add DatadogNet.OkHttp.Android to trace outgoing HTTP calls. |
|
|
DatadogNet.Logs.Android
.NET for Android / .NET MAUI bindings for the native Datadog Android SDK's dd-sdk-android-logs module: log collection through Logger, with attributes, tags and an event mapper for redacting entries on the device before upload. Built against dd-sdk-android 3.12.1. Requires DatadogNet.Core.Android, which it pulls in. |
|
|
DatadogNet.Ndk.Android
.NET for Android / .NET MAUI bindings for the native Datadog Android SDK's dd-sdk-android-ndk module: native crash reporting through NdkCrashReports.Enable, which installs a signal handler and reports the crash as a RUM error and log on the next launch. Built against dd-sdk-android 3.12.1. Ships prebuilt .so libraries for every ABI upstream publishes. Opt-in and separate on purpose: it installs a signal handler, which an app that only wanted RUM should not pay for. |
|
|
DatadogNet.RUM.Android
.NET for Android / .NET MAUI bindings for the native Datadog Android SDK's dd-sdk-android-rum module: Real User Monitoring - views, actions, resources, errors, long tasks and mobile vitals - through Rum, RumConfiguration and GlobalRumMonitor, with Activity, Fragment and Navigation view-tracking strategies. Built against dd-sdk-android 3.12.1. Requires DatadogNet.Core.Android, which it pulls in. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 3.12.1.4 | 105 | 7/26/2026 |
| 3.12.1.4-beta.11.19 | 28 | 7/30/2026 |
| 3.12.1.4-beta.10.17 | 27 | 7/30/2026 |
| 3.12.1.4-beta.9.16 | 34 | 7/29/2026 |
| 3.12.1.4-beta.8.15 | 29 | 7/28/2026 |
| 3.12.1.4-beta.7.14 | 53 | 7/26/2026 |
| 3.12.1.3 | 174 | 7/24/2026 |
| 3.12.1.3-beta.6.13 | 53 | 7/24/2026 |
| 3.12.1.3-beta.5.12 | 37 | 7/24/2026 |
| 3.12.1.2 | 107 | 7/23/2026 |
| 3.12.1.2-beta.4.10 | 38 | 7/23/2026 |
| 3.12.1.2-beta.4.9 | 42 | 7/23/2026 |
| 3.12.1.2-beta.4.8 | 45 | 7/23/2026 |
| 3.12.1.1 | 96 | 7/23/2026 |
| 3.12.1.1-beta.2.5 | 44 | 7/23/2026 |
| 2.26.3.2 | 82 | 7/23/2026 |
| 2.26.3.1 | 96 | 7/23/2026 |
| 2.26.3.1-beta.3.6 | 42 | 7/23/2026 |
## What's changed
Binding-only release. The native SDK is unchanged — still
[dd-sdk-android 3.12.1](https://github.com/DataDog/dd-sdk-android/releases/tag/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,LineNumberTable` that 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`/`GlobalRumMonitor` and the
`RumMonitor` interface, `Logs` and `Logger`, `Trace`/`DatadogTracing`/`GlobalDatadogTracer`
and the tracer/span/scope/propagation interfaces, `SessionReplay`, every `*Configuration` and
its `Builder`, 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 `.aar`s, 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 `NU1107` on `Xamarin.AndroidX.SavedState` that every
net8 consumer hits: the direct `1.4.0` reference that settles it, and why it must not be
applied to net9/net10.
- **The unbound-artifact roster is complete and watched**: `build/packages.tsv` now accounts
for all 41 `dd-sdk-android*` artifacts on Maven Central with a reason per exclusion —
`-flags`, `-flags-openfeature` and `-profiling` are recorded as binding candidates — and a
weekly `upstream-watch` workflow 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 with `Directory.Build.props` (a documented override exists for the
deliberate case).
- **`build/BumpNativeVersion.sh`** scripts 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.