Skip to content

@capawesome-team/capacitor-nfc

Capacitor plugin for reading and writing NFC tags.

Features

  • 🖥️ Cross-platform: Supports Android, iOS and Web.
  • 🔄 NDEF: Read and write NFC Data Exchange Format (NDEF) messages.
  • 📳 HCE: Emulate an NFC card that other devices can interact with.
  • Raw Commands: Send raw commands to an NFC tag and receive the response.
  • 🛠️ Utils: Utility functions to make your life easier.
  • ⚔️ Battle-Tested: Used in more than 100 projects.
  • 📚 Documentation: Comprehensive documentation to help you get started.
  • 🔁 Up-to-date: Always supports the latest Capacitor version.
  • ⭐️ Support: First-class support from the Capawesome Team.

Installation

This plugin is only available to Capawesome Insiders. First, make sure you have the Capawesome npm registry set up. You can do this by running the following commands:

npm config set @capawesome-team:registry https://npm.registry.capawesome.io
npm config set //npm.registry.capawesome.io/:_authToken <YOUR_LICENSE_KEY>

Attention: Replace <YOUR_LICENSE_KEY> with the license key you received from Polar. If you don't have a license key yet, you can get one by becoming a Capawesome Insider.

Next, install the package:

npm install @capawesome-team/capacitor-nfc
npx cap sync

Android

Permissions

This API requires the following permissions be added to your AndroidManifest.xml before the application tag:

<!-- To get access to the NFC hardware. -->
<uses-permission android:name="android.permission.NFC" />
<!-- The minimum SDK version that your application can support. -->
<uses-sdk android:minSdkVersion="10"/>
<!-- (Optional) This will ensure that your app appears in Google Play only for devices with NFC hardware. -->
<uses-feature android:name="android.hardware.nfc" android:required="true" />

Intent Filter

If you want to launch your app through an NFC tag, please take a look at the Android documentation. There you will find which changes you have to apply to your AndroidManifest.xml (example).

Services

To be able to use Host Card Emulation (HCE), you also need to add the following service inside the application tag in your AndroidManifest.xml (usually android/app/src/main/AndroidManifest.xml):

<service android:name=".MyHostApduService" android:exported="true"
         android:permission="android.permission.BIND_NFC_SERVICE">
    <intent-filter>
        <action android:name="android.nfc.cardemulation.action.HOST_APDU_SERVICE"/>
    </intent-filter>
    <meta-data android:name="android.nfc.cardemulation.host_apdu_service"
               android:resource="@xml/apduservice"/>
</service>

This meta-data tag points to an apduservice.xml file. The following is an example of such a file with a single AID group declaration containing two proprietary AIDs:

<host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android"
           android:description="@string/servicedesc"
           android:requireDeviceUnlock="false">
    <aid-group android:description="@string/aiddescription"
               android:category="other">
        <aid-filter android:name="F0010203040506"/>
        <aid-filter android:name="F0394148148100"/>
    </aid-group>
</host-apdu-service>

You can find more information about this in the Android documentation.

iOS

Ensure Near Field Communication Tag Reading capabilities have been enabled in your application in Xcode. See Add a capability to a target for more information.

Finally, add the NFCReaderUsageDescription key to the ios/App/App/Info.plist file, which tells the user why the app needs to use NFC:

+ <key>NFCReaderUsageDescription</key>
+ <string>The app enables the reading and writing of various NFC tags.</string>

If you want to launch your app through an NFC tag, please take a look at the Core NFC documentation. The NFC tag requires a URI record (see createNdefUriRecord(...)) that must contain either a universal link (see Deep Linking with Universal and App Links) or a supported URL scheme.

Configuration

No configuration required for this plugin.

Demo

A working example can be found here: capawesome-team/capacitor-nfc-demo

Android iOS

Guides

Usage

import { Nfc, NfcUtils, NfcTagTechType } from '@capawesome-team/capacitor-nfc';
import { Capacitor } from '@capacitor/core';

const createNdefTextRecord = () => {
  const utils = new NfcUtils();
  const { record } = utils.createNdefTextRecord({ text: 'Capacitor NFC Plugin' });
  return record;
};

const write = async () => {
  return new Promise((resolve) => {
    const record = createNdefTextRecord();

    Nfc.addListener('nfcTagScanned', async (event) => {
      await Nfc.write({ message: { records: [record] } });
      await Nfc.stopScanSession();
      resolve();
    });

    Nfc.startScanSession();
  });
};

const read = async () => {
  return new Promise((resolve) => {
    Nfc.addListener('nfcTagScanned', async (event) => {
      await Nfc.stopScanSession();
      resolve(event.nfcTag);
    });

    Nfc.startScanSession();
  });
};

const makeReadOnly = async () => {
  return new Promise((resolve) => {
    Nfc.addListener('nfcTagScanned', async (event) => {
      await Nfc.makeReadOnly();
      await Nfc.stopScanSession();
      resolve();
    });

    Nfc.startScanSession();
  });
};

const readSignature = async () => {
  return new Promise((resolve) => {
    Nfc.addListener('nfcTagScanned', async (event) => {
      if (Capacitor.getPlatform() === 'android') {
        // 1. Connect to the tag.
        await Nfc.connect({ techType: NfcTagTechType.NfcA }); 
        // 2. Send one or more commands to the tag and receive the response.
        const result = await Nfc.transceive({ data: [60, 0] });
        // 3. Close the connection to the tag.
        await Nfc.close();
        await Nfc.stopScanSession();
        resolve(response);
      } else {
        // 1. Send one or more commands to the tag and receive the response.
        const result = await Nfc.transceive({ techType: NfcTagTechType.NfcA, data: [60, 0] });
        await Nfc.stopScanSession();
        resolve(response);
      }
    });

    Nfc.startScanSession();
  });
};

const erase = async () => {
  return new Promise((resolve) => {
    Nfc.addListener('nfcTagScanned', async (event) => {
      await Nfc.erase();
      await Nfc.stopScanSession();
      resolve();
    });

    Nfc.startScanSession();
  });
};

const format = async () => {
  return new Promise((resolve) => {
    Nfc.addListener('nfcTagScanned', async (event) => {
      await Nfc.format();
      await Nfc.stopScanSession();
      resolve();
    });

    Nfc.startScanSession();
  });
};

const isSupported = async () => {
  const { isSupported } = await Nfc.isSupported();
  return isSupported;
};

const isEnabled = async () => {
  const { isEnabled } = await Nfc.isEnabled();
  return isEnabled;
};

const openSettings = async () => {
  await Nfc.openSettings();
};

const checkPermissions = async () => {
  const { nfc } = await Nfc.checkPermissions();
  return nfc;
};

const requestPermissions = async () => {
  const { nfc } = await Nfc.requestPermissions();
  return nfc;
};

const removeAllListeners = async () => {
  await Nfc.removeAllListeners();
};

API

startScanSession(...)

startScanSession(options?: StartScanSessionOptions | undefined) => Promise<void>

Start a scan session. Only one session can be active at a time.

Stop the session as soon as you are done using stopScanSession(...).

On iOS, this will trigger the NFC Reader Session alert.

Param Type
options StartScanSessionOptions

Since: 0.0.1


stopScanSession(...)

stopScanSession(options?: StopScanSessionOptions | undefined) => Promise<void>

Stop the active scan session.

Param Type
options StopScanSessionOptions

Since: 0.0.1


write(...)

write(options: WriteOptions) => Promise<void>

Write to a NFC tag.

This method must be called from within a nfcTagScanned handler.

Param Type
options WriteOptions

Since: 0.0.1


respond(...)

respond(options: RespondOptions) => Promise<void>

Send a response APDU back to the remote device.

Only available on Android.

Param Type
options RespondOptions

Since: 6.3.0


makeReadOnly()

makeReadOnly() => Promise<void>

Make a NFC tag readonly.

This method must be called from within a nfcTagScanned handler.

Attention: This is permanent and can not be undone.

Since: 0.0.1


erase()

erase() => Promise<void>

Erase the NFC tag by writing an empty NDEF message.

This method must be called from within a nfcTagScanned handler.

Since: 0.3.0


format()

format() => Promise<void>

Format the NFC tag as NDEF and write an empty NDEF message.

This method must be called from within a nfcTagScanned handler.

Only available on Android.

Since: 0.3.0


transceive(...)

transceive(options: TransceiveOptions) => Promise<TransceiveResult>

Send raw command to the tag and receive the response.

This method must be called from within a nfcTagScanned handler.

On Android, the tag must be connected with connect() first.

⚠️ Experimental: This method could not be tested extensively yet. Please let us know if you discover any issues!

⚠️ Attention: A bad command can damage the tag forever. Please read the Android and iOS documentation linked below first.

More information on how to use this method on Android: https://bit.ly/3ywSkvT

More information on how to use this method on iOS with... - ISO 15693-3: https://apple.co/3Lliaum - FeliCa: https://apple.co/3LpvRs6

Only available on Android and iOS.

Param Type
options TransceiveOptions

Returns: Promise<TransceiveResult>

Since: 0.3.0


connect(...)

connect(options: ConnectOptions) => Promise<void>

Connect to the tag and enable I/O operations.

This method must be called from within a nfcTagScanned handler.

Only available on Android.

Param Type
options ConnectOptions

Since: 6.0.0


close()

close() => Promise<void>

Close the connection to the tag.

This method must be called from within a nfcTagScanned handler.

Only available on Android.

Since: 6.0.0


isSupported()

isSupported() => Promise<IsSupportedResult>

Returns whether or not NFC is supported.

Returns: Promise<IsSupportedResult>

Since: 0.0.1


isEnabled()

isEnabled() => Promise<IsEnabledResult>

Returns whether or not NFC is enabled.

Only available on Android.

Returns: Promise<IsEnabledResult>

Since: 0.0.1


openSettings()

openSettings() => Promise<void>

Opens the NFC device settings so that the user can enable or disable NFC.

Only available on Android.

Since: 0.0.1


getAntennaInfo()

getAntennaInfo() => Promise<GetAntennaInfoResult>

Returns information regarding Nfc antennas on the device such as their relative positioning on the device.

Only available on Android.

Returns: Promise<GetAntennaInfoResult>

Since: 6.1.0


setAlertMessage(...)

setAlertMessage(options: SetAlertMessageOptions) => Promise<void>

Set a custom message, which is displayed in the NFC Reader Session alert.

Only available on iOS.

Param Type
options SetAlertMessageOptions

Since: 6.2.0


checkPermissions()

checkPermissions() => Promise<PermissionResult>

Check permission for reading and writing NFC tags.

This method is only needed on Web. On Android and iOS, granted is always returned.

Returns: Promise<PermissionResult>

Since: 0.0.1


requestPermissions()

requestPermissions() => Promise<PermissionResult>

Request permission for reading and writing NFC tags.

This method is only needed on Web. On Android and iOS, granted is always returned.

Returns: Promise<PermissionResult>

Since: 0.0.1


addListener('commandReceived', ...)

addListener(eventName: 'commandReceived', listenerFunc: (event: CommandReceivedEvent) => void) => Promise<PluginListenerHandle>

Called whenever a NFC reader sends an Application Protocol Data Unit (APDU).

Only available on Android.

Param Type
eventName 'commandReceived'
listenerFunc (event: CommandReceivedEvent) => void

Returns: Promise<PluginListenerHandle>

Since: 6.3.0


addListener('nfcLinkDeactivated', ...)

addListener(eventName: 'nfcLinkDeactivated', listenerFunc: (event: NfcLinkDeactivatedEvent) => void) => Promise<PluginListenerHandle>

Called when the NFC link has been deactivated or lost.

Only available on Android.

Param Type
eventName 'nfcLinkDeactivated'
listenerFunc (event: NfcLinkDeactivatedEvent) => void

Returns: Promise<PluginListenerHandle>

Since: 6.3.0


addListener('nfcTagScanned', ...)

addListener(eventName: 'nfcTagScanned', listenerFunc: (event: NfcTagScannedEvent) => void) => Promise<PluginListenerHandle>

Called when a new NFC tag is scanned.

Param Type
eventName 'nfcTagScanned'
listenerFunc (event: NfcTagScannedEvent) => void

Returns: Promise<PluginListenerHandle>

Since: 0.0.1


addListener('scanSessionCanceled', ...)

addListener(eventName: 'scanSessionCanceled', listenerFunc: () => void) => Promise<PluginListenerHandle>

Called when the scan session was canceled.

Only available on iOS.

Param Type
eventName 'scanSessionCanceled'
listenerFunc () => void

Returns: Promise<PluginListenerHandle>

Since: 0.0.1


addListener('scanSessionError', ...)

addListener(eventName: 'scanSessionError', listenerFunc: (event: ScanSessionErrorEvent) => void) => Promise<PluginListenerHandle>

Called when an error occurs during the scan session.

Param Type
eventName 'scanSessionError'
listenerFunc (event: ScanSessionErrorEvent) => void

Returns: Promise<PluginListenerHandle>

Since: 0.0.1


removeAllListeners()

removeAllListeners() => Promise<void>

Remove all listeners for this plugin.

Since: 0.0.1


Interfaces

StartScanSessionOptions

Prop Type Description Default Since
alertMessage string A custom message, which is displayed in the NFC Reader Session alert. Only available on iOS. 0.0.1
compatibilityMode boolean Whether or not to use the NFCNDEFReaderSession. Attention: This mode only supports reading NDEF tags. Only available on iOS. false 6.4.0
techTypes NfcTagTechType[] The NFC tag technologies to filter on in this session. Only available on Android. 0.0.1
mimeTypes string[] Mime types to filter on in this session. Only available on Android. 0.0.1
pollingOptions PollingOption[] Type of tags to detect during a polling sequence. Only available on iOS. [PollingOption.iso14443, PollingOption.iso15693] 0.2.0

StopScanSessionOptions

Prop Type Description Since
errorMessage string A custom error message, which is displayed in the NFC Reader Session alert. Only available on iOS. 0.0.1

WriteOptions

Prop Type Description Since
message NdefMessage The NDEF message to write. 0.0.1

NdefMessage

Prop Type Description Since
records NdefRecord[] The records of the NDEF message. 0.0.1

NdefRecord

Prop Type Description Since
id number[] The record identifier as byte array. 0.0.1
payload number[] The payload field data as byte array. 0.0.1
tnf TypeNameFormat The record type name format which indicates the structure of the value of the type field. 0.0.1
type number[] The type of the record payload. This should be used in conjunction with the tnf field to determine the payload format. 0.0.1

RespondOptions

Prop Type Description Since
data number[] Bytes to send. 6.3.0

TransceiveResult

Prop Type Description Since
response number[] Bytes received in response. 0.3.0

TransceiveOptions

Prop Type Description Since
techType NfcTagTechType The NFC tag technology to connect with. Only available on iOS. 0.3.0
data number[] Bytes to send. 0.3.0
iso15693RequestFlags Iso15693RequestFlag[] The request flags for the NFC tag technology type NfcV (ISO 15693-3). Only available on iOS 14+ 0.3.0
iso15693CommandCode number The custom command code defined by the IC manufacturer for the NFC tag technology type NfcV (ISO 15693-3). Valid range is 0xA0 to 0xDF inclusively, 0x23 and 0x24 are also supported. Only available on iOS 14+ 0.3.0

ConnectOptions

Prop Type Description Since
techType NfcTagTechType The NFC tag technology to connect with. Only available on Android. 6.0.0

IsSupportedResult

Prop Type Description Since
isSupported boolean 0.0.1
nfc boolean Whether or not NFC is supported on the device. 6.3.0
hce boolean Whether or not Host Card Emulation (HCE) is supported on the device. 6.3.0

IsEnabledResult

Prop Type Since
isEnabled boolean 0.0.1

GetAntennaInfoResult

Prop Type Description Since
availableAntennas Antenna[] The available NFC antennas on the device. 6.1.0
deviceHeight number The height of the device in millimeters. 6.1.0
deviceWidth number The width of the device in millimeters. 6.1.0
isDeviceFoldable boolean Whether or not the device is foldable. 6.1.0

Antenna

Prop Type Description Since
locationX number The location of the NFC antenna on the X axis in millimeters. 6.1.0
locationY number The location of the NFC antenna on the Y axis in millimeters. 6.1.0

SetAlertMessageOptions

Prop Type Description Since
message string The custom message, which is displayed in the NFC Reader Session alert. 6.2.0

PermissionResult

Prop Type Description Since
nfc PermissionState Permission state for reading and writing NFC tags. 0.0.1

PluginListenerHandle

Prop Type
remove () => Promise<void>

CommandReceivedEvent

Prop Type Description Since
data number[] The command received from the remote device. 6.3.0

NfcLinkDeactivatedEvent

Prop Type Description Since
reason DeactivationReason The reason why the deactivation occurred. 6.3.0

NfcTagScannedEvent

Prop Type Description Since
nfcTag NfcTag The scanned NFC tag. 0.0.1

NfcTag

Prop Type Description Since
atqa number[] The ATQA/SENS_RES bytes of an NFC A tag. Only available on Android. 0.0.1
applicationData number[] The Application Data bytes from ATQB/SENSB_RES of an NFC B tag. Only available on Android and iOS. 0.0.1
barcode number[] The barcode bytes of an NfcBarcode tag. Only available on Android. 0.0.1
canMakeReadOnly boolean Whether the NDEF tag can be made read-only or not. Only available on Android. 0.0.1
dsfId number[] The DSF ID bytes of an NFC V tag. Only available on Android. 0.0.1
hiLayerResponse number[] The higher layer response bytes of an ISO-DEP tag. Only available on Android. 0.0.1
historicalBytes number[] The historical bytes of an ISO-DEP tag. Only available on Android and iOS. 0.0.1
id number[] The tag identifier (low level serial number) which is used for anti-collision and identification. 0.0.1
isWritable boolean Whether the NDEF tag is writable or not. Only available on Android and iOS. 0.0.1
manufacturer number[] The manufacturer bytes of an NFC F tag. Only available on Android and iOS. 0.0.1
manufacturerCode number The Integrated Circuit (IC) manufacturer code of an NFC V tag. Only available on iOS. 6.3.0
maxSize number The maximum NDEF message size in bytes. Only available on Android and iOS. 0.0.1
message NdefMessage The NDEF-formatted message. 0.0.1
protocolInfo number[] The Protocol Info bytes from ATQB/SENSB_RES of an NFC B tag. Only available on Android. 0.0.1
responseFlags number[] The Response Flag bytes of an NFC V tag. Only available on Android. 0.0.1
sak number[] The SAK/SEL_RES bytes of an NFC A tag. Only available on Android. 0.0.1
systemCode number[] The System Code bytes of an NFC F tag. Only available on Android and iOS. 0.0.1
techTypes NfcTagTechType[] The technologies available in this tag. Only available on Android and iOS. 0.0.1
type NfcTagType The NDEF tag type. Only available on Android and iOS. 0.0.1

ScanSessionErrorEvent

Prop Type Description Since
message string The error message. 0.0.1

Type Aliases

PermissionState

"denied" | "granted" | "prompt"

Enums

NfcTagTechType

Members Value Description Since
NfcA 'NFC_A' The NFC-A (ISO 14443-3A) tag technology. Only available on Android. 0.0.1
NfcB 'NFC_B' The NFC-B (ISO 14443-3B) tag technology. Only available on Android. 0.0.1
NfcF 'NFC_F' The NFC-F (JIS 6319-4) tag technology. Only available on Android and iOS. 0.0.1
NfcV 'NFC_V' The NFC-V (ISO 15693) tag technology. Only available on Android and iOS. 0.0.1
IsoDep 'ISO_DEP' The ISO-DEP (ISO 14443-4) tag technology. Only available on Android. 0.0.1
Iso7816 'ISO_7816' The ISO 7816 tag technology. Only available on iOS. 5.1.0
Ndef 'NDEF' The NDEF tag technology. Only available on Android. 0.0.1
MifareClassic 'MIFARE_CLASSIC' The MIFARE Classic tag technology. Only available on Android. 0.0.1
MifareDesfire 'MIFARE_DESFIRE' The MIFARE Desfire tag technology. Only available on iOS. 5.1.0
MifarePlus 'MIFARE_PLUS' The MIFARE Plus tag technology. Only available on iOS. 5.1.0
MifareUltralight 'MIFARE_ULTRALIGHT' The MIFARE Ultralight tag technology. Only available on Android and iOS. 0.0.1
NfcBarcode 'NFC_BARCODE' The technology of a tag containing just a barcode. Only available on Android. 0.0.1
NdefFormatable 'NDEF_FORMATABLE' The NDEF formatable tag technology. Only available on Android. 0.0.1

PollingOption

Members Value Description Since
iso14443 'iso14443' The option for detecting ISO 7816-compatible and MIFARE tags. 0.2.0
iso15693 'iso15693' The option for detecting ISO 15693 tags. 0.2.0
iso18092 'iso18092' The option for detecting FeliCa tags. 0.2.0

TypeNameFormat

Members Value Description Since
Empty 0 An empty record with no type or payload. 0.0.1
WellKnown 1 A predefined type defined in the RTD specification of the NFC Forum. 0.0.1
MimeMedia 2 An Internet media type as defined in RFC 2046. 0.0.1
AbsoluteUri 3 A URI as defined in RFC 3986. 0.0.1
External 4 A user-defined value that is based on the rules of the NFC Forum Record Type Definition specification. 0.0.1
Unknown 5 Type is unknown. 0.0.1
Unchanged 6 Indicates the payload is an intermediate or final chunk of a chunked NDEF Record. 0.0.1

Iso15693RequestFlag

Members Value Since
address 'address' 0.3.0
commandSpecificBit8 'commandSpecificBit8' 0.3.0
dualSubCarriers 'dualSubCarriers' 0.3.0
highDataRate 'highDataRate' 0.3.0
option 'option' 0.3.0
protocolExtension 'protocolExtension' 0.3.0
select 'select' 0.3.0

DeactivationReason

Members Value Description Since
LinkLoss 0 Indicates deactivation was due to the NFC link being lost. 6.3.0
Deselected 1 Indicates deactivation was due to a different AID being selected. 6.3.0

NfcTagType

Members Value Description Since
NfcForumType1 'NFC_FORUM_TYPE_1' Only available on Android. 0.0.1
NfcForumType2 'NFC_FORUM_TYPE_2' Only available on Android. 0.0.1
NfcForumType3 'NFC_FORUM_TYPE_3' Only available on Android and iOS. 0.0.1
NfcForumType4 'NFC_FORUM_TYPE_4' Only available on Android. 0.0.1
MifareClassic 'MIFARE_CLASSIC' Only available on Android. 0.0.1
MifareDesfire 'MIFARE_DESFIRE' 0.0.1
MifarePlus 'MIFARE_PLUS' Only available on Android. 0.0.1
MifarePro 'MIFARE_PRO' Only available on Android. 0.0.1
MifareUltralight 'MIFARE_ULTRALIGHT' Only available on Android. 0.0.1
MifareUltralightC 'MIFARE_ULTRALIGHT_C' Only available on Android. 0.0.1

Utils

See docs/utils/README.md.

Changelog

See CHANGELOG.md.

License

See LICENSE.