SFMCSDK.Net.Android
3.1.1.1
dotnet add package SFMCSDK.Net.Android --version 3.1.1.1
NuGet\Install-Package SFMCSDK.Net.Android -Version 3.1.1.1
<PackageReference Include="SFMCSDK.Net.Android" Version="3.1.1.1" />
<PackageVersion Include="SFMCSDK.Net.Android" Version="3.1.1.1" />
<PackageReference Include="SFMCSDK.Net.Android" />
paket add SFMCSDK.Net.Android --version 3.1.1.1
#r "nuget: SFMCSDK.Net.Android, 3.1.1.1"
#:package SFMCSDK.Net.Android@3.1.1.1
#addin nuget:?package=SFMCSDK.Net.Android&version=3.1.1.1
#tool nuget:?package=SFMCSDK.Net.Android&version=3.1.1.1
SFMCSDK.Net.Android
.NET for Android bindings for the Salesforce Marketing Cloud SFMC SDK core module (com.salesforce.marketingcloud:sfmcsdk) — identity, event tracking, logging, and the module plumbing the MobilePush module plugs into.
dotnet add package SFMCSDK.Net.Android
using Com.Salesforce.Marketingcloud.Sfmcsdk;
var config = new SFMCSdkModuleConfig.Builder().Build();
// The Action overload is this package's addition - natively this takes a Kotlin Function1.
SFMCSdk.Configure(Android.App.Application.Context, config, status =>
Console.WriteLine($"SFMC SDK initialization: {status}"));
SFMCSdk.RequestSdk(sdk =>
sdk.Identity = sdk.Identity.NewBuilder().SetProfileId("contact-key").Build());
Push notifications live in the sibling MarketingCloudSDK.Net.Android, which depends on this package the same way the native MobilePush module depends on sfmcsdk. A cross-platform ergonomic layer lives in SFMCSDK.Net.
Contents
- Packages
- What is bound
- Installing
- Usage
- How this repository works
- Building locally
- Tests
- Upgrading the SFMC SDK
- Releasing
- Troubleshooting
- Licence
Packages
| Package | Wraps | Depends on | What it is for |
|---|---|---|---|
SFMCSDK.Net.Android |
sfmcsdk 3.1.1 (+ common-internal 1.0.0, unbound) |
Xamarin.Kotlin.StdLib, AndroidX, Play services basement |
The SFMC SDK core: SFMCSdk.Configure, identity, custom events, logging |
Versions are <sfmcsdk version>.<binding revision> — 3.1.1.1 is sfmcsdk 3.1.1, binding revision 1. The fourth component belongs to this repository and moves when the binding or packaging changes over an unchanged native SDK.
What is bound
The whole public surface of sfmcsdk, generated by class-parse with Java-package-derived namespaces (com.salesforce.marketingcloud.sfmcsdk → Com.Salesforce.Marketingcloud.Sfmcsdk), so a type's C# name can always be derived from its Kotlin one. On top of the generated tier, Additions/ supplies the pieces raw JNI makes painful:
| Instead of | Write |
|---|---|
a Java.Lang.Object, IFunction1 subclass per callback |
SFMCSdk.Configure(context, config, status => …) |
a Java.Lang.Object, ISFMCSdkReadyListener subclass |
SFMCSdk.RequestSdk(sdk => …) |
common-internal ships inside this package as an unbound .aar — it is Salesforce-internal plumbing the SDK needs on the classpath, with no public API worth a projection. The deliberately-unbound roster, with reasons, lives in build/packages.tsv.
Installing
<PackageReference Include="SFMCSDK.Net.Android" Version="3.1.1.1" />
Target frameworks: net8.0-android34.0, net9.0-android35.0, net10.0-android36.0. The SFMC SDK's own floor is Android 8.0 (API 26).
net8 note. The AndroidX generation sfmcsdk 3.x depends on has partially dropped net8 assets; the net8 head pins
Xamarin.AndroidX.Lifecycle.Processone minor below the.pom(2.9.4 vs 2.10.0), which is API-stable for what the SDK reaches. The net9/net10 heads carry the.pom-exact versions and are the ones Java dependency verification runs on.
Usage
Everything is the raw binding, in the same shapes Salesforce's Kotlin documentation uses. Initialize once, early — Application.OnCreate in a plain app, MauiProgram in MAUI:
SFMCSdk.SetLogging(LogLevel.Debug!, myListener); // optional, before Configure
SFMCSdk.Configure(context, new SFMCSdkModuleConfig.Builder().Build(), status => { });
Identity (v3 is an immutable record — rebuild and assign):
SFMCSdk.RequestSdk(sdk =>
sdk.Identity = sdk.Identity.NewBuilder()
.SetProfileId("contact-key")
.PutAttribute("tier", "gold")
.Build());
Custom events:
var checkout = EventManager.CustomEvent(
"checkout_completed",
new Dictionary<string, Java.Lang.Object> { ["total"] = 42.50 });
SFMCSdk.Track(checkout);
Reach for the generated namespaces directly when you need something these snippets do not show — nothing is hidden.
How this repository works
Nothing native is committed. @(AndroidMavenLibrary) resolves sfmcsdk and common-internal straight from Salesforce's own Maven repository (salesforce-marketingcloud.github.io — the group is not on Maven Central), feeds the SDK's Java dependency verification, and every resolved byte is checked against the SHA-256 pins in build/maven-checksums.txt. The net8 head predates @(AndroidMavenLibrary) and takes a DownloadFile fallback with the same pins.
Each .NET SDK's Android workload builds two target frameworks, so build/BuildNugets.sh packs twice (net9 band, then net10 from a scratch global.json) and build/merge-packages.py grafts the net10 assets into one package.
Layout
| Path | What |
|---|---|
src/Sfmc.Binding.props |
Everything the binding project(s) share: TFM bands, Maven resolution, checksum verification, packaging |
src/SFMCSDK.Net.Android/ |
The binding: Transforms/, Additions/, consumer R8 rules under buildTransitive/ |
build/ |
Pack, checksum, R8-rule and upgrade scripts; packages.tsv is the package roster |
tests/ |
PackageTests (nupkg shape, no workloads needed) and DeviceTests (a bare Activity driving the real SDK on an emulator) |
samples/ |
A MAUI app driving initialization, identity and events |
.github/workflows/ |
pr (beta to nuget.org), release (tag → nuget.org + GitHub release), auto-release (merged release note → tag), upstream-drift/upstream-watch |
Building locally
./build/BuildNugets.sh # packs 3.1.1.1 into ./artifacts
dotnet test tests/SFMCSDK.Net.Android.PackageTests
The sample needs the .NET 10 SDK (MAUI 9 cannot build against this AndroidX generation):
cd "$(mktemp -d)" && dotnet new globaljson --sdk-version 10.0.100 --roll-forward latestFeature
dotnet build <repo>/samples/SFMCSDK.Net.Android.Example -c Debug
Tests
dotnet test tests/SFMCSDK.Net.Android.PackageTests # nupkg layout, deps, checks the merge
./.github/scripts/run-emulator-tests.sh 3.1.1.1 net9.0-android35.0 # needs a running emulator
./.github/scripts/run-emulator-tests.sh 3.1.1.1 net9.0-android35.0 r8 # the shrunk leg
The device tests run without credentials on purpose: they prove the native classes are present, the JNI surface works and the Kotlin callback bridges fire — not that a tenant accepts the traffic.
Upgrading the SFMC SDK
./build/BumpNativeVersion.sh 3.2.0
which pins, re-checksums, regenerates R8 rules, packs and tests — then review what it prints that it does not automate (checksum diff review, Transforms re-validation, README pins, release notes). The upstream-watch workflow files an issue when Salesforce ships a version this repository does not bind.
Releasing
Merging a file named docs/release-notes/<four-part-version>.md to main is the release: auto-release tags it, release packs with verification off (the PR that merged it already verified), pushes to nuget.org via trusted publishing (OIDC — no stored API key) and creates the GitHub release with those notes. Every PR also publishes a -beta.<pr>.<run> prerelease of the full set.
Troubleshooting
ClassNotFoundException in Release builds only. Your app shrinks with R8 and something stripped the SDK. The package ships consumer keep-rules under buildTransitive/ that attach automatically; if you maintain your own -keep configuration make sure it does not override them.
XA4241: Java dependency ... is not satisfied. A .pom dependency has no NuGet binding in your app's graph. The package declares everything sfmcsdk 3.1.1 needs; if you see this after adding other Android bindings, your graph resolved an AndroidX version below the .pom's floor.
Restore fails with NU1301 about a missing artifacts source. The repository's NuGet.config declares ./artifacts as a local feed for samples and device tests. Run ./build/BuildNugets.sh once, or build your own project outside this repository.
Licence
The binding code in this repository is MIT. The native SFMC SDK artifacts inside the package are © Salesforce, BSD-3-Clause. The package licence expression is MIT AND BSD-3-Clause and both texts ship in every package 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
- Xamarin.AndroidX.Annotation (>= 1.9.1.5)
- Xamarin.AndroidX.Concurrent.Futures (>= 1.3.0.1)
- Xamarin.AndroidX.Core.Core.Ktx (>= 1.17.0)
- Xamarin.AndroidX.Lifecycle.Process (>= 2.10.0)
- Xamarin.AndroidX.Work.Runtime (>= 2.11.0)
- Xamarin.GooglePlayServices.Basement (>= 118.9.0)
- Xamarin.Kotlin.StdLib (>= 2.2.21)
-
net8.0-android34.0
- Xamarin.AndroidX.Annotation (>= 1.9.1.5)
- Xamarin.AndroidX.Concurrent.Futures (>= 1.3.0.1)
- Xamarin.AndroidX.Core.Core.Ktx (>= 1.17.0)
- Xamarin.AndroidX.Lifecycle.Common (>= 2.9.4)
- Xamarin.AndroidX.Lifecycle.Process (>= 2.9.4)
- Xamarin.AndroidX.Work.Runtime (>= 2.11.0)
- Xamarin.GooglePlayServices.Basement (>= 118.9.0)
- Xamarin.Kotlin.StdLib (>= 2.2.21)
-
net9.0-android35.0
- Xamarin.AndroidX.Annotation (>= 1.9.1.5)
- Xamarin.AndroidX.Concurrent.Futures (>= 1.3.0.1)
- Xamarin.AndroidX.Core.Core.Ktx (>= 1.17.0)
- Xamarin.AndroidX.Lifecycle.Process (>= 2.10.0)
- Xamarin.AndroidX.Work.Runtime (>= 2.11.0)
- Xamarin.GooglePlayServices.Basement (>= 118.9.0)
- Xamarin.Kotlin.StdLib (>= 2.2.21)
NuGet packages (2)
Showing the top 2 NuGet packages that depend on SFMCSDK.Net.Android:
| Package | Downloads |
|---|---|
|
MarketingCloudSDK.Net.Android
.NET for Android bindings for the Salesforce Marketing Cloud MobilePush module (com.salesforce.marketingcloud:marketingcloudsdk) - push registration, inbox, in-app messages, geofence and beacon messaging - plus the modular feature .aars of the Unified SDK architecture. Successor to the sfmc-net-bindings-mobile packages, at the v11 generation. |
|
|
SFMCSDK.Net
One cross-platform API for the Salesforce Marketing Cloud SFMC SDK core: awaitable initialization, identity (contact key and attributes) and custom event tracking on Android and iOS from shared code, over the SFMCSDK.Net.Android and SFMCSDK.Net.iOS bindings. Restores on plain target frameworks too, so shared class libraries and unit tests need no platform conditionals. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 3.1.1.1 | 0 | 7/30/2026 |
| 3.1.1.1-beta.5.7 | 0 | 7/30/2026 |
| 3.1.1.1-beta.5.6 | 0 | 7/30/2026 |
| 3.1.1.1-beta.4.8 | 0 | 7/30/2026 |
| 3.1.1.1-beta.4.5 | 0 | 7/30/2026 |
| 3.1.1.1-beta.2.4 | 0 | 7/30/2026 |
| 3.1.1.1-beta.1.3 | 0 | 7/30/2026 |
| 1.0.5.8 | 8,319 | 10/30/2024 |
| 1.0.5.6 | 219 | 10/7/2024 |
| 1.0.3.10 | 716 | 7/12/2024 |
| 1.0.3.4 | 177 | 7/12/2024 |
| 1.0.3.3 | 293 | 5/20/2024 |
| 1.0.3.2 | 199 | 5/17/2024 |
## What's changed
First release of the rebuilt binding, at the Unified SDK generation.
- Binds **sfmcsdk 3.1.1** (was 1.x in the retired `sfmc-net-bindings-mobile` packages), ships
`common-internal` 1.0.0 alongside it, resolved from Salesforce's own Maven repository and
SHA-256-pinned on every build.
- Target frameworks `net8.0-android34.0`, `net9.0-android35.0`, `net10.0-android36.0` — real
multi-targeting; the old net7-era `sed`-the-TFM packaging is gone, as is the `.targets` hack
that copied natives inside the restored package folder.
- New `Additions/`: `SFMCSdk.Configure(..., Action<IInitializationStatus>)` and
`SFMCSdk.RequestSdk(Action<SFMCSdk>)`, replacing the hand-rolled Kotlin `Function1`
boilerplate every consumer previously carried.
- Consumer R8 keep-rules ship under `buildTransitive/` — Release builds that shrink no longer
lose the SDK's JNI-only entry points.
- Migrating from `1.x`: the identity API is now an immutable record
(`sdk.Identity = sdk.Identity.NewBuilder()...Build()`), logging takes an `ILogListener`, and
the SDK's floor is Android 8.0 (API 26). Kotlin-derived namespaces are unchanged.