A Capacitor plugin for reading and writing NFC tags on iOS and Android devices. This plugin allows you to:
- Read NDEF messages from NFC tags.
- Write NDEF messages to NFC tags.
Note: NFC functionality is only available on compatible iOS devices running iOS 13.0 or later, and Android devices with NFC hardware.
Install the plugin using npm:
npm install @aacassandra/capacitor-nfc
npx cap sync| Feature | Android | iOS | Web (Chrome/Edge Android) |
|---|---|---|---|
| Read NDEF tag | âś… | âś… | âś… |
| Write NDEF tag | âś… | âś… | âś… |
| Listen for tag event | âś… | âś… | âś… |
| Listen for write event | âś… | âś… | âś… |
| Error handling | âś… | âś… | âś… |
| Check NFC support | âś… | âś… | âś… |
| Low-level/tag raw | ❌ | ❌ | ❌ |
| Background scan | ❌ | ❌ |
- âś… = Supported
- ❌ = Not supported
⚠️ * = Android can scan in background if app is in foreground service, but plugin only supports foreground scan by default.- Web NFC only works on Android (Chrome/Edge), not on iOS/Safari or desktop browsers.
To use NFC functionality on iOS, you need to perform some additional setup steps.
In Xcode:
- Open your project (
.xcworkspacefile) in Xcode. - Select your project in the Project Navigator.
- Select your app target.
- Go to the Signing & Capabilities tab.
- Click the
+ Capabilitybutton. - Add Near Field Communication Tag Reading.
Add the NFCReaderUsageDescription key to your Info.plist file to explain why your app needs access to NFC.
In your Info.plist file (usually located at ios/App/App/Info.plist), add:
<key>NFCReaderUsageDescription</key>
<string>This app requires access to NFC to read and write NFC tags.</string>Replace the description with a message that explains why your app needs NFC access.
To use NFC functionality on Android, follow these steps:
The plugin automatically adds the required NFC permissions to your AndroidManifest.xml:
<uses-permission android:name="android.permission.NFC" />
<uses-feature android:name="android.hardware.nfc" android:required="true" />If you want to make NFC optional for your app, change android:required="true" to android:required="false" in your app's main AndroidManifest.xml.
In your app, you should check if NFC is available and enabled before using NFC functionality:
import { NFC } from '@aacassandra/capacitor-nfc';
// Start scanning only if NFC is available
NFC.startScan()
.then(() => {
console.log('NFC scanning started');
})
.catch((error) => {
console.error('NFC error:', error);
// This will be triggered if NFC is not available or not enabled
});The plugin automatically handles foreground NFC detection. Make sure your activity handles the NFC intent.
This plugin provides consistent NFC functionality across both iOS and Android, but there are some platform-specific behaviors to be aware of:
- iOS: Uses the
CoreNFCframework and requires user interaction to initiate scanning. The NFC scanning session will show a system dialog. - Android: Can detect NFC tags automatically when they come in range, even if the app is in the background (if configured).
The plugin normalizes the data format between iOS and Android to provide a consistent developer experience:
- TEXT Records: On both platforms, the language code prefix is removed so you only get the actual text content.
- URI Records: The URI identifier code is handled appropriately on both platforms.
- Payload Format: All payloads are returned as strings to maintain consistency between platforms.
- iOS: Apple's CoreNFC API will detect if multiple tags are present and prompt the user to isolate a single tag.
- Android: Android typically handles one tag at a time, but the plugin adds extra verification for consistency.
- iOS: The plugin checks if the device has NFC hardware capability.
- Android: The plugin verifies both hardware availability and if NFC is enabled in device settings.
-
NFC Not Detected on Android
- Ensure NFC is enabled in the device settings
- Check if the device has NFC hardware support
- Verify the tag is compatible with your device
-
iOS NFC Dialog Not Showing
- Make sure you've added the required NFC capability and usage description
- Verify your app is built for iOS 13.0 or later
- Ensure you're testing on a physical device (NFC won't work in simulators)
Import the plugin into your code:
import { NFC } from '@aacassandra/capacitor-nfc';To read NFC tags, you need to start a scanning session and listen for nfcTag events.
import { NFC, NDEFMessages, NFCError } from '@aacassandra/capacitor-nfc';
// Start NFC scanning
NFC.startScan().catch((error) => {
console.error('Error starting NFC scan:', error);
});
// Listen for NFC tag detection
const nfcTagListener = NFC.addListener('nfcTag', (data: NDEFMessages) => {
console.log('Received NFC tag:', data);
});
// Handle NFC errors
const nfcErrorListener = NFC.addListener('nfcError', (error: NFCError) => {
console.error('NFC Error:', error);
});To write to NFC tags, you use the writeNDEF method and provide an array of NDEF records.
import { NFC, NFCError } from '@aacassandra/capacitor-nfc';
// Start NFC writing mode
const recordsToWrite = {
records: [
{
type: 'T', // TEXT record
payload: 'Hello, NFC!'
},
{
type: 'U', // URI record
payload: 'https://example.com'
}
]
};
NFC.writeNDEF(recordsToWrite).catch((error) => {
console.error('Error starting NFC write:', error);
});
// Listen for successful write
const writeSuccessListener = NFC.addListener('nfcWriteSuccess', () => {
console.log('Successfully wrote to NFC tag');
});
// Handle NFC write errors
const writeErrorListener = NFC.addListener('nfcError', (error: NFCError) => {
console.error('NFC Write Error:', error);
});The plugin supports different types of NDEF records. Here are examples for common record types:
// Reading a TEXT record
NFC.addListener('nfcTag', (data) => {
data.messages.forEach(message => {
message.records.forEach(record => {
if (record.type === 'T') {
console.log('Text content:', record.payload);
}
});
});
});
// Writing a TEXT record
NFC.writeNDEF({
records: [
{
type: 'T',
payload: 'This is a text record'
}
]
});// Reading a URI record
NFC.addListener('nfcTag', (data) => {
data.messages.forEach(message => {
message.records.forEach(record => {
if (record.type === 'U') {
console.log('URI content:', record.payload);
// Could be "https://example.com"
}
});
});
});
// Writing a URI record
NFC.writeNDEF({
records: [
{
type: 'U',
payload: 'https://example.com'
}
]
});// Reading a custom MIME type record
NFC.addListener('nfcTag', (data) => {
data.messages.forEach(message => {
message.records.forEach(record => {
if (record.type === 'application/json') {
console.log('JSON data:', record.payload);
// Could be a JSON string that you need to parse
try {
const jsonData = JSON.parse(record.payload);
console.log('Parsed JSON:', jsonData);
} catch (e) {
console.error('Failed to parse JSON data');
}
}
});
});
});
// Writing a custom MIME type record
NFC.writeNDEF({
records: [
{
type: 'application/json',
payload: JSON.stringify({ id: 1, name: 'Product Name' })
}
]
});To write NDEF messages to NFC tags, use the writeNDEF method and listen for nfcWriteSuccess events.
import { NFC, NDEFWriteOptions, NFCError } from '@aacassandra/capacitor-nfc';
const message: NDEFWriteOptions = {
records: [
{
type: 'T', // Text record type
payload: 'Hello, NFC!',
},
],
};
// Write NDEF message to NFC tag
NFC.writeNDEF(message)
.then(() => {
console.log('Write initiated');
})
.catch((error) => {
console.error('Error writing to NFC tag:', error);
});
// Listen for write success
const nfcWriteSuccessListener = NFC.addListener('nfcWriteSuccess', () => {
console.log('NDEF message written successfully.');
});
// Handle NFC errors
const nfcErrorListener = NFC.addListener('nfcError', (error: NFCError) => {
console.error('NFC Error:', error);
});Starts the NFC scanning session.
Returns: Promise<void>
NFC.startScan()
.then(() => {
// Scanning started
})
.catch((error) => {
console.error('Error starting NFC scan:', error);
});Writes an NDEF message to an NFC tag.
Parameters:
options: NDEFWriteOptions- The NDEF message to write.
Returns: Promise<void>
NFC.writeNDEF(options)
.then(() => {
// Write initiated
})
.catch((error) => {
console.error('Error writing NDEF message:', error);
});Adds a listener for NFC tag detection events.
Parameters:
eventName: 'nfcTag'listener: (data: NDEFMessages) => void- The function to call when an NFC tag is detected.
Returns: PluginListenerHandle
const nfcTagListener = NFC.addListener('nfcTag', (data: NDEFMessages) => {
console.log('Received NFC tag:', data);
});Adds a listener for NFC error events.
Parameters:
eventName: 'nfcError'listener: (error: NFCError) => void- The function to call when an NFC error occurs.
Returns: PluginListenerHandle
const nfcErrorListener = NFC.addListener('nfcError', (error: NFCError) => {
console.error('NFC Error:', error);
});Adds a listener for NFC write success events.
Parameters:
eventName: 'nfcWriteSuccess'listener: () => void- The function to call when an NDEF message has been written successfully.
Returns: PluginListenerHandle
const nfcWriteSuccessListener = NFC.addListener('nfcWriteSuccess', () => {
console.log('NDEF message written successfully.');
});Options for writing an NDEF message.
interface NDEFWriteOptions {
records: NDEFRecord[];
}Data received from an NFC tag.
interface NDEFMessages {
messages: NDEFMessage[];
}An NDEF message consisting of one or more records.
interface NDEFMessage {
records: NDEFRecord[];
}An NDEF record.
interface NDEFRecord {
/**
* The type of the record.
*/
type: string;
/**
* The payload of the record.
*/
payload: string;
}An NFC error.
interface NFCError {
/**
* The error message.
*/
error: string;
}To integrate this plugin into your Capacitor app:
-
Install the plugin:
npm install @aacassandra/capacitor-nfc npx cap sync
-
Import the plugin in your code:
import { NFC } from '@aacassandra/capacitor-nfc';
-
Use the plugin methods as described in the Usage section.
Here's a complete example of how to read and write NFC tags in your app:
import { NFC, NDEFMessages, NDEFWriteOptions, NFCError } from '@aacassandra/capacitor-nfc';
// Start NFC scanning
NFC.startScan().catch((error) => {
console.error('Error starting NFC scan:', error);
});
// Listen for NFC tag detection
const nfcTagListener = NFC.addListener('nfcTag', (data: NDEFMessages) => {
console.log('Received NFC tag:', data);
});
// Handle NFC errors
const nfcErrorListener = NFC.addListener('nfcError', (error: NFCError) => {
console.error('NFC Error:', error);
});
// Prepare an NDEF message to write
const message: NDEFWriteOptions = {
records: [
{
type: 'T', // Text record type
payload: 'Hello, NFC!',
},
],
};
// Write NDEF message to NFC tag
NFC.writeNDEF(message)
.then(() => {
console.log('Write initiated');
})
.catch((error) => {
console.error('Error writing to NFC tag:', error);
});
// Listen for write success
const nfcWriteSuccessListener = NFC.addListener('nfcWriteSuccess', () => {
console.log('NDEF message written successfully.');
});
// Don't forget to remove listeners when they're no longer needed
// For example, in a Vue or React component's onDestroy/componentWillUnmount:
// nfcTagListener.remove();
// nfcErrorListener.remove();
// nfcWriteSuccessListener.remove();For Android, you might want to add a button to check NFC status and prompt users to enable NFC if it's disabled:
import { NFC } from '@aacassandra/capacitor-nfc';
function checkNfcStatus() {
NFC.startScan()
.then(() => {
// NFC is available and enabled
console.log('NFC is ready to use');
})
.catch((error) => {
// NFC might be unavailable or disabled
console.error('NFC Error:', error);
// You could show a dialog to prompt the user to enable NFC
if (error.includes('not enabled')) {
// Direct user to NFC settings
// On Android, you could use App.openUrl to send the user to NFC settings
// or show an instruction to enable NFC from the notification shade
}
});
}This plugin now supports Web NFC on browsers that implement the Web NFC API, such as Chrome and Edge on Android. On unsupported browsers (including all iOS browsers), NFC features will throw an error or be unavailable.
- On web, the plugin uses the browser's native Web NFC API (
NDEFReader) if available. - If the browser does not support Web NFC, all NFC methods will throw an error indicating NFC is not supported.
- The API and event listeners are the same as on native platforms, so your code can be cross-platform.
You can check if the current browser supports Web NFC:
import { NFC } from '@aacassandra/capacitor-nfc';
NFC.isNFCSupported().then((isSupported) => {
if (!isSupported) {
alert('Web NFC is not supported in this browser.');
}
});import { NFC } from '@aacassandra/capacitor-nfc';
// Start scanning (will throw if not supported)
NFC.startScan()
.then(() => console.log('Web NFC scan started'))
.catch(err => alert('NFC not supported: ' + err.error));
// Listen for NFC tag
NFC.addListener('nfcTag', (data) => {
console.log('Web NFC tag:', data);
});- Web NFC is only available on Android (Chrome/Edge) and not on iOS/Safari or desktop browsers.
- Web NFC API is still experimental and may change in the future.
- Only NDEF tags are supported (no low-level tag access).
Support: If you encounter any issues or have questions, feel free to open an issue.