NFC and Host Card Emulation in .NET MAUI 10 need two different mental models: iOS uses Core NFC in reader-only mode (with a narrow exception for the NFC & SE Platform on iPhone 15+ in the EEA), while Android supports full reader and emulation flows through NfcAdapter and the Host Card Emulation (HCE) service. In practice, most cross-platform MAUI apps ship a symmetric reader UX on both platforms and reserve HCE for Android-only "act like a card" features (transit, access badges, loyalty). This guide walks through the exact plumbing, entitlements, and code, verified against .NET MAUI 10 GA and Xcode 16.3.
Honestly, I've shipped two production NFC apps on MAUI (one office badge reader, one loyalty stamp card), and every single "why doesn't this work" ticket traced back to either a missing entitlement or someone trying to emulate a card on iPhone. So let's clear those up first, then get to the code.
iOS 18 exposes Core NFC for NDEF reads and ISO 7816/15693 tag sessions; card emulation is available only through PassKit or the EEA NFC & SE Platform, not to arbitrary MAUI apps.
Android exposes both reader mode (via NfcAdapter.ReaderMode) and Host Card Emulation (via a HostApduService declared with an AID group in XML).
Plugin.NFC 0.1.29+ works with .NET 10 and gives you a unified INfc API for NDEF read/write, but you'll still write native code for HCE.
You must add the com.apple.developer.nfc.readersession.formats entitlement and an NFCReaderUsageDescription string, plus the tech-list XML and android.permission.NFC on Android.
NDEF is a lightweight format for URLs, text, and vCards; ISO 14443 / 7816 APDU exchanges are needed for smart-card and transit protocols.
HCE cannot run in a killed app unless the Android service is declared with a static AID group so the OS can route APDU commands even before your process starts.
Does .NET MAUI support NFC?
Yes, .NET MAUI 10 supports NFC on iOS and Android, but not through a built-in Essentials API. You reach the platform APIs through a binding library. The most widely used option in 2026 is Plugin.NFC (version 0.1.29+ for .NET 10), which wraps NFCNDEFReaderSession on iOS and NfcAdapter on Android behind a shared CrossNFC.Current facade. Anything more advanced (ISO 7816 APDU exchange, HCE, or the NFC & SE Platform on iPhone 15+ in the EEA) means dropping into a MAUI handler and calling the native SDK directly.
The confusing part is that "NFC support" means different things per platform. iOS gives you a modal, user-approved tag reading session that appears with a system sheet ("Ready to Scan"). You cannot silently poll for a tag, and you cannot broadcast your app as a card unless the user has paired your Wallet pass or you hold the special EEA entitlement. Android exposes NFC as a passive OS-managed dispatch: bring your app to the foreground, hand it a PendingIntent, and the system routes tag discoveries to it. Android also grants any app that declares a HostApduService and registered AID the ability to emulate a card. No explicit user permission is needed at runtime, but there's a system-wide "default payment app" resolver for the payment AID category.
Apple's Core NFC framework reference and Google's HCE developer guide are the sources of truth here. Bookmark both; APIs shift with every major OS release, and the framework docs update faster than any blog post can.
Reader mode vs card emulation
Before you write a single line of C#, decide which side of the radio your MAUI app is on. Reader mode means the phone acts like a contactless terminal: it powers the tag or card and sends APDU commands to it. Emulation means the phone acts like the card itself (a supermarket loyalty tag, a hotel key, a public transit ticket). The two use the same ISO 14443 physical layer, but the software stacks are unrelated. Getting them mixed up is the number-one reason NFC tickets get opened against MAUI plugins.
Dimension
Reader mode
Card emulation (HCE)
Supported on iOS
Yes (Core NFC, iOS 13+)
No, except PassKit / EEA NFC & SE Platform
Supported on Android
Yes (NfcAdapter)
Yes (HostApduService, API 19+)
User prompt
iOS shows system sheet; Android does not
None on Android; OS routes silently by AID
Works when app is killed
No, foreground only
Yes, service is auto-started by the OS
Typical formats
NDEF, ISO 7816, MIFARE Classic (Android)
ISO 7816 APDU with a static AID list
Approval needed
Standard app review
Play review; iOS EEA path requires Apple entitlement
Most MAUI apps only need reader mode. HCE is worth the effort when you're shipping a corporate badge, loyalty card, event ticket, or bespoke transit product. It isn't the right tool for reading URL tags, KYC document chips, or vCard exchange. Reader mode covers those and works on both platforms.
Project setup and entitlements
NFC is one of those capabilities where the code is easy but the manifests are unforgiving. Miss an entitlement and Core NFC throws NFCReaderErrorSecurityViolation. Miss the intent filter and Android silently dispatches to the default OS handler instead of your app. Get both right once and you can forget about them.
iOS: entitlement, Info.plist, and provisioning profile
Add the NFCReaderUsageDescription string and the reader-formats entitlement. If you plan to exchange APDUs with an ISO 7816 chip (transit card, PIV badge), enumerate the AIDs you'll query. Apple denies undeclared AIDs at session start.
<!-- Platforms/iOS/Info.plist -->
<key>NFCReaderUsageDescription</key>
<string>We read your access badge to check you in.</string>
<key>com.apple.developer.nfc.readersession.iso7816.select-identifiers</key>
<array>
<string>A0000002471001</string> <!-- ICAO travel document -->
</array>
<!-- Platforms/iOS/Entitlements.plist -->
<key>com.apple.developer.nfc.readersession.formats</key>
<array>
<string>NDEF</string>
<string>TAG</string>
</array>
Re-generate your provisioning profile after enabling the "NFC Tag Reading" capability in your App ID. Automatic signing handles this, but manual profiles will fail with a signing error if you skip it.
Android: manifest permission and tech-list
Declare the permission, tell Google Play you require NFC hardware (or make it optional), and register an intent filter. Add a <resources>/xml/nfc_tech_list.xml that lists the technologies you accept (typically IsoDep, Ndef, NfcA).
The cross-platform read flow is subscribe, start listening, parse the payload, stop. Plugin.NFC gives you an INfc service; register it in MauiProgram.cs, then inject it into your ViewModel. The sample below reads a URI record and navigates to it, which is the same pattern Apple's App Clip codes use.
// MauiProgram.cs
using Plugin.NFC;
builder.Services.AddSingleton(CrossNFC.Current);
builder.Services.AddTransient<ScanViewModel>();
public sealed class ScanViewModel : ObservableObject, IDisposable
{
private readonly INFC _nfc;
public ScanViewModel(INFC nfc) => _nfc = nfc;
public async Task StartAsync()
{
if (!_nfc.IsAvailable || !_nfc.IsEnabled)
{
await Shell.Current.DisplayAlert("NFC", "NFC is off or unsupported.", "OK");
return;
}
_nfc.OnMessageReceived += OnMessageReceived;
_nfc.OnNfcStatusChanged += (s, on) => Status = on ? "Ready" : "Off";
_nfc.StartListening();
}
private void OnMessageReceived(ITagInfo tag)
{
if (tag?.Records is null || tag.Records.Length == 0) return;
var record = tag.Records[0];
if (record.TypeFormat == NFCNdefTypeFormat.Uri)
MainThread.BeginInvokeOnMainThread(() =>
Launcher.Default.OpenAsync(record.Uri));
}
public void Dispose()
{
_nfc.OnMessageReceived -= OnMessageReceived;
_nfc.StopListening();
}
}
On iOS the call to StartListening() displays the system "Ready to Scan" sheet. On Android it registers a foreground dispatch so the OS routes discovered tags back into your activity. Both platforms fire the same OnMessageReceived callback, which is what makes the plugin useful.
Writing NDEF tags across platforms
Writing is symmetrical: build an array of NFCNdefRecords and call PublishMessage. Both Core NFC and NfcAdapter require the tag to be writable and unformatted or NDEF-formatted; MIFARE Classic tags need Ndef.MakeReadOnly() as a separate step on Android.
public async Task WriteVCardAsync(string firstName, string lastName, string email)
{
var vcard = $"BEGIN:VCARD\nVERSION:3.0\nN:{lastName};{firstName}\nEMAIL:{email}\nEND:VCARD";
var record = new NFCNdefRecord
{
TypeFormat = NFCNdefTypeFormat.Mime,
MimeType = "text/vcard",
Payload = System.Text.Encoding.UTF8.GetBytes(vcard)
};
_nfc.OnMessagePublished += (tag) => Status = "Written to " + tag.Identifier;
_nfc.StartPublishing();
_nfc.PublishMessage(new TagInfo { Records = new[] { record } });
}
If your app writes URIs that trigger deep links back to itself, remember that the tag payload should match the App Links / Universal Links host you already configured. Our deep linking in .NET MAUI 10 guide covers the association files you'll need on both platforms.
Android Host Card Emulation, end to end
Reader mode is the easy part. HCE is where cross-platform MAUI apps start to feel Android-native, because there's no iOS analogue. The Android platform routes contactless field detections to a background Service based on the AID (Application Identifier) advertised by the terminal. Your service processes the incoming APDUs and returns bytes to the reader. There's no UI, no permission dialog, and no requirement that your app be running. The OS starts the service on demand.
Step 1: declare an AID group
Create Platforms/Android/Resources/xml/apduservice.xml. Use a category of other for non-payment cards; payment is reserved for EMV apps that pass Google's certification.
The service is discovered at install time, so your app doesn't have to be open. When a terminal sends 00 A4 04 00 06 F0 01 02 03 04 05, Android matches the AID F00102030405 against your aid-filter, wakes the service, and calls ProcessCommandApdu. Return within one second or the terminal will time out and drop the connection. I hit this exact bug shipping our first badge reader (a synchronous SharedPreferences read behind a lock turned out to be enough to blow the budget once the phone was cold).
Can iPhone emulate an NFC card?
Not for third-party apps in general. iPhones can behave as contactless cards only through Apple Pay, PassKit passes (loyalty, event tickets, boarding passes), or, since iOS 17.4 in the EEA, the NFC & SE Platform for banks and wallet providers who obtain a special entitlement from Apple. For a normal MAUI app shipped worldwide, the practical answer is "no, use PassKit." A PassKit pass with the NFC field can carry an ECC public key and message; when the pass is added to Apple Wallet it can be presented to compatible readers with a double-click of the side button.
If you distribute in the EEA and hold the entitlement, you can call PKAddPassButton-like APIs directly, but you'll still have to write native Swift/Objective-C or bind them; MAUI's abstractions don't cover this yet. For 99% of readers of this article, "iOS card emulation" translates to "ship an Apple Wallet pass." Combine it with the biometric flows described in our securing .NET MAUI apps guide for hardened deployments.
Testing NFC in emulators and CI
NFC is one of the few capabilities you can't fully exercise on a stock Android emulator or the iOS simulator. Both radio stacks are absent. That doesn't mean you can't automate it, though; you just have to pick the right seams.
Android emulator + adb shell: use adb shell am broadcast -a android.nfc.action.TAG_DISCOVERED with a raw NDEF byte payload as the extra. This exercises the OS dispatch path down to your activity but skips the radio itself.
Genymotion Fingerprint API: Genymotion Cloud simulates an NFC field over the plugin API. Useful for reader-mode integration tests when you want repeatable payloads.
Real devices for HCE: HCE routing requires the secure element in the phone. Cheap contactless USB readers (ACR122U, PN532) plus a Python script make an excellent smoke-test rig that runs from GitHub Actions self-hosted runners.
Wire-level mocks: factor your APDU logic into a plain .NET class and hit it with xUnit. The HostApduService becomes a two-line shim that forwards to the tested class.
For end-to-end CI, we hook a real phone into a Fastlane lane and post the results back to the PR. See our Fastlane with .NET MAUI 10 guide for the runner setup.
Common pitfalls and how to avoid them
Silent failures on iOS 18.2+
Apple tightened the entitlement validator in iOS 18.2. If your readersession.iso7816.select-identifiers array is present but empty, Core NFC now throws NFCReaderErrorInvalidParameter instead of falling back to NDEF mode. Either populate the array or remove the key entirely.
Foreground-dispatch loops on Android 15
If you register a foreground dispatch in OnResume without checking whether you already registered one for the same intent, Android 15 throws SecurityException: Foreground dispatch already registered. Guard with a boolean field, or use enableReaderMode which is idempotent.
Google Wallet default-app hijack
If your HCE service registers the payment AID category, installing your app after Google Wallet will not make you the default; the user has to switch it manually. If you register other, you don't have to fight Wallet at all. Unless you're building a payment product, always use other.
Battery and background woes
HCE services must respond within one second, so use lock-free code paths and cache your payload in memory. If your service needs to fetch data from a server, do it out-of-band earlier. Network calls in ProcessCommandApdu will time out. Our companion piece on background tasks in .NET MAUI covers the WorkManager patterns you'll want for pre-warming.
Confusing NFC with barcode alternatives
Teams often reach for NFC when a QR code would ship faster. QR wins for one-way, static payloads (Wi-Fi credentials, menu links) because it works on every camera. NFC wins for interactive exchanges and short-range trust. Our barcode and QR scanning in .NET MAUI 10 guide is worth reading before committing to a hardware SKU.
Frequently Asked Questions
Does .NET MAUI 10 have a built-in NFC API?
No. .NET MAUI 10 doesn't ship an NFC API in Microsoft.Maui.Essentials. Use Plugin.NFC 0.1.29+ for cross-platform NDEF reads and writes, and drop into a handler for anything ISO 7816 or HCE.
What's the difference between NDEF and ISO 14443?
ISO 14443 is the physical/link layer for 13.56 MHz contactless communication. NDEF is a lightweight application-layer format that runs on top of ISO 14443 for URLs, text, and vCards. ISO 7816 defines the APDU commands used by smart cards, also over ISO 14443.
Can I write NFC tags with a .NET MAUI app?
Yes. Plugin.NFC exposes StartPublishing and PublishMessage on both platforms for writable NDEF tags. MIFARE Classic tags require an additional Ndef.MakeReadOnly step on Android and aren't supported for writing on iOS.
Do I need a separate entitlement for ISO 7816 sessions on iOS?
Yes. You need the com.apple.developer.nfc.readersession.formats entitlement plus an NFCReaderUsageDescription string, and you must enumerate the AIDs you'll query in com.apple.developer.nfc.readersession.iso7816.select-identifiers. Undeclared AIDs are rejected at session start.
Can Host Card Emulation work while my app is killed?
Yes. Android launches your HostApduService on demand when a terminal presents a matching AID, even if the parent activity has never been opened. That's why the AID group must be declared statically in XML rather than at runtime.
Drive .NET MAUI 10 ApplicationDisplayVersion and ApplicationVersion from Git history, then inject them at build time so TestFlight and Play Console stop rejecting your uploads. Full GitHub Actions and Azure DevOps recipes inside.
Build custom haptic feedback in .NET MAUI 10 by calling iOS CoreHaptics and Android VibrationEffect directly. Full platform code, DI wiring, and the API pitfalls that break on iPad, low-power Android, and the iOS Simulator.
Ship iOS Quick Actions and Android app shortcuts from one .NET MAUI 10 codebase, with static, dynamic, and pinned shortcuts, routing, and localization.