A NFC module for react native
react-native-nfc-manager
React Native NFC module for both Android & iOS.
Bring NFC feature to React Native. Inspired by phonegap-nfc and react-native-ble-manager
Supported Platforms
- Android (API 10+)
- iOS (iOS11 with iPhone 7/7+, 8/8+, 10)
iOS Setup
You will need to setup some capabilities / entitlement / plist stuff to enable NFC development on your device, this repo explains these requirements very well:
Install
npm i --save react-native-nfc-manager
Link Native Library with react-native link
react-native link react-native-nfc-manager
Install with cocopods
Include this line inside of your Podfile
pod 'react-native-nfc-manager', :path => '../node_modules/react-native-nfc-manager/'
Example
Look into example/App.js
as a starting point.
The easiest way to test is simple make your AppRegistry
point to our example component, like this:
// in your index.ios.js or index.android.js
import React, { Component } from 'react';
import {
AppRegistry,
} from 'react-native';
import App from 'react-native-nfc-manager/example/App'
AppRegistry.registerComponent('NfcManagerDev', () => App);
API
This library provide a default export NfcManager
and 2 named exports ByteParser
and NdefParser
, like this:
import NfcManager, {ByteParser, Ndef, NdefParser} from 'react-native-nfc-manager'
All methods in NfcManager
return a Promise
object and are resolved to different types of data according to individual API.
-
ByteParser
is an utility module to encode and decode byte[] arrays (used in Mifare Classic technology). -
Ndef
is an utility module to encode and decode some well-known NDEF format. -
NdefParser
is an old utility class to parse some well-known NDEF format, which will be deprecated later.
NfcManager API
start({onSessionClosedIOS})
Init the module. If the device doesn't support NFC, the returning promise will be rejected.
Arguments
onSessionClosedIOS
-function
- [iOS only] the callback to invoke when anNFCNDEFReaderSession
becomes invalidated
Examples
NfcManager.start({
onSessionClosedIOS: () => {
console.log('ios session closed');
}
})
.then(result => {
console.log('start OK', result);
})
.catch(error => {
console.warn('device does not support nfc!');
this.setState({supported: false});
})
stop()
Terminates the module. This will remove the onSessionClosedIOS listener that is attached in the start
function.
isSupported()
Chck if the NFC is supported by hardware.
Returned Promise
resolved to a boolean value to indicate whether NFC is supported.
isEnabled() [Android only]
Check if the NFC is enabled.
Returned Promise
resolved to a boolean value to indicate whether NFC is enabled.
goToNfcSetting() [Android only]
Direct the user to NFC setting.
getLaunchTagEvent() [Android only]
Get the NFC tag object which launches the app.
Returned Promise
resolved to the NFC tag object launching the app and resolved to null if the app isn't launched by NFC tag.
registerTagEvent(listener, alertMessage, invalidateAfterFirstRead)
Start to listen to ANY NFC tags.
Arguments
listener
-function
- the callback when discovering NFC tagsalertMessage
-string
- (iOS) the message to display on iOS when the NFCScanning pops upinvalidateAfterFirstRead
-boolean
- (iOS) when set to true this will not have you prompt to click done after NFC Scan.
Examples
NfcManager.registerTagEvent(tag => {
console.log('Tag Discovered', tag);
}, 'Hold your device over the tag', true)
unregisterTagEvent()
Stop listening to NFC tags.
requestNdefWrite(bytes, options) [Android only]
Request writing NdefMessage (constructed by bytes
array you passed) into next discovered tag.
Notice you must call registerTagEvent
first before calling this.
Arguments
bytes
-array
- the full NdefMessage, which is an array of numberoptions
-object
- optional argument used to trigger actions such asformat
orformatReadOnly
Examples
// write ndef
NfcManager.requestNdefWrite(bytes)
.then(() => console.log('write completed'))
.catch(err => console.warn(err))
// request ndef formating (first argument can be null in this case)
NfcManager.requestNdefWrite(null, {format: true})
.then(() => console.log('format completed'))
.catch(err => console.warn(err))
cancelNdefWrite() [Android only]
Cancel the pending ndef writing operation.
onStateChanged(listener) [Android only]
Listen to NFC state change (on/off/turning_on/turning_off)
Arguments
listener
-function
- the callback when NFC state changed
Examples
NfcManager.onStateChanged(
event => {
if (event.state === 'on') {
// do whatever you want
} else if (event.state === 'off') {
// do whatever you want
} else if (event.state === 'turning_on') {
// do whatever you want
} else if (event.state === 'turning_off') {
// do whatever you want
}
}
)
.then(sub => {
this._stateChangedSub = sub;
// remember to call this._stateChangedSub.remove()
// when you don't want to listen to this anymore
})
.catch(err => {
console.warn(err);
})
requestTechnology(tech) [Android only]
Request specific NFC Technology to perform advanced actions.
- Please refer to Android Advanced NFC Guide to understand what a
NFC Technology
means.
This method returns a promise:
- if resolved, it means you already find and connect to the tag supporting the requested technology, so the technology specific API can be called.
- if rejected, it means either the request is cancelled or the discovered tag doesn't support the requested technology.
Notice you must call registerTagEvent
first before calling this.
Arguments
tech
-string
- the NFC Technology you want to use- the available ones are defined in
NfcTech
(please doimport {NfcTech} from 'react-native-nfc-manager
)
- the available ones are defined in
Examples
Concrete examples using NFC Technology can be found in
example/AndroidTechTestNdef.js
andexample/AndroidMifareClassic.js
cancelTechnologyRequest() [Android only]
Cancel previous NFC Technology request.
closeTechnology() [Android only]
When all your NFC Technology operations are finished, you should call this API to disconnect from the tag and release resources.
setNdefPushMessage(bytes) [Android only]
This API triggers Android Beam, it can send Ndef (constructed by bytes
array you passed) to remote device.
Notice you must call registerTagEvent
first before calling this.
When you want to cancel the Ndef sending, simply call this API again and pass
null
to it.
Arguments
bytes
-array
- the full NdefMessage, which is an array of number
Examples
Please see
examples/App.js
for a concrete example
// register Android Beam
NfcManager.setNdefPushMessage(bytes)
.then(() => console.log('ready to beam'))
.catch(err => console.warn(err))
// cancel Android Beam
NfcManager.setNdefPushMessage(null)
.then(() => console.log('beam cancelled'))
.catch(err => console.warn(err))
Ndef API
This module is integrated from ndef-js
to perform Ndef encoding & decoding. Great thanks for their brilliant work!
We mainly remove the dependency to NodeJS Buffer
and maintain most of the original structure.
Encode example:
let bytes = Ndef.encodeMessage([
Ndef.textRecord("hello, world"),
Ndef.uriRecord("http://nodejs.org"),
]);
// then you can pass `bytes` into API such as NfcManager.requestNdefWrite()
}
Decode example:
_onTagDiscovered = tag => {
console.log('Tag Discovered', tag);
this.setState({ tag });
let parsed = null;
if (tag.ndefMessage && tag.ndefMessage.length > 0) {
// ndefMessage is actually an array of NdefRecords,
// and we can iterate through each NdefRecord, decode its payload
// according to its TNF & type
const ndefRecords = tag.ndefMessage;
function decodeNdefRecord(record) {
if (Ndef.isType(record, Ndef.TNF_WELL_KNOWN, Ndef.RTD_TEXT)) {
return ['text', Ndef.text.decodePayload(record.payload)];
} else if (Ndef.isType(record, Ndef.TNF_WELL_KNOWN, Ndef.RTD_URI)) {
return ['uri', Ndef.uri.decodePayload(record.payload)];
}
return ['unknown', '---']
}
parsed = ndefRecords.map(decodeNdefRecord);
}
this.setState({parsed});
}
NdefParser API (deprecated, please use Ndef
instead)
parseUri(ndef)
Try to parse RTD_URI from a NdefMessage, return an object with an uri
property.
Arguments
ndef
-object
- this object should be obtained from nfc tag object with this form:tag.ndefMessage[0]
. (NFC tag object can be obtained bygetLaunchTagEvent
orregisterTagEvent
)
Examples
let {uri} = NdefParser.parseUri(sampleTag.ndefMessage[0]);
console.log('parseUri: ' + uri);
parseText(ndef)
Try to parse RTD_TEXT from a NdefMessage, return parsed string or null if the operation fail. Currently only support utf8.
Arguments
ndef
-object
- this object should be obtained from nfc tag object with this form:tag.ndefMessage[0]
. (NFC tag object can be obtained bygetLaunchTagEvent
orregisterTagEvent
)
Examples
let text = NdefParser.parseText(sampleTag.ndefMessage[0]);
console.log('parsedText: ' + text);
Mifare Classic API [Android only]
This module enables you to read encrypted Mifare Classic cards (as long as you have the authentication keys). A concrete example can be found in example/AndroidMifareClassic.js
To find more information about the low level APIs of Mifare Classic on Android checkout this excellent blog post: MiFare Classic Detection on Android
At the time of writing, iOS 12 still doesn't support any Mifare cards, or any NFC technology that doesn't use the NDEF standards.
To use the Mifare Classic API, you first need to request the NfcTech.MifareClassic
technology (see requestTechnology
). Once you have the tech request, you can use the following methods to interact with the Mifare Classic cards:
mifareClassicAuthenticateA(sector, key) and mifareClassicAuthenticateB(sector, key) [Android only]
Authenticate to the Mifare Classic card using key A or key B.
This method returns a promise:
- if resolved, it means you successfully authenticated to the Mifare Classic card, and a read request can be called.
- if rejected, it means either the request is cancelled, the discovered tag doesn't support the requested technology or the authentication simply failed. The returned error should give you some insights about what went wrong.
Notice you must have successfully requested the Mifare Classic technology with the requestTechnology
call before using this method.
Arguments
sector
-number
- the Mifare Classic sector to authenticate to (e.g. 0 - 15 for Mifare Classic 1K cards)key
-byte[]
- an array of bytes (numbers) that contains the key
Examples
A concrete example using Mifare Classic can be found in
example/AndroidMifareClassic.js
NfcManager.mifareClassicAuthenticateA(0, [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]).then(() => {
/* ...do your stuff here... */
});
mifareClassicReadBlock(sector) [Android only]
Gets a block from a Mifare Classic card where you previously authenticated to.
This method returns a promise:
- if resolved, it returns the block (array of bytes (numbers)) from the specified sector.
- if rejected, it means either the request is cancelled, the discovered tag doesn't support the requested technology, the authentication failed or something else went wrong. The returned error should give you some insights about what went wrong.
Notice you must be successfully authenticated with the mifareClassicAuthenticateA
or mifareClassicAuthenticateB
call before using this method.
Arguments
sector
-number
- the Mifare Classic sector to authenticate to (0 - 15) for 1K cards
Return value
block
-byte[]
- an array of bytes (numbers)
For convenience, a class ByteParser
is included in the NfcManager exports. This class contains 2 methods byteToHexString
and byteToString
who can be used to get the raw data into a hex string or a string, depending on what data is stored on the card.
Examples
A concrete example using Mifare Classic can be found in
example/AndroidMifareClassic.js
NfcManager.mifareClassicReadBlock(0).then((message) => {
const str = ByteParser.byteToString(message);
/* ...do your stuff here... */
});
Read authenticated example:
The following is some wrapper code that uses the async/await
syntax.
const readAuthenticatedA = async (sector, code) => {
return new Promise((resolve, reject) => {
NfcManager.mifareClassicAuthenticateA(sector, code)
.then(() => {
console.log(`mifareClassicAuthenticateA(${sector}) completed`);
NfcManager.mifareClassicReadBlock(sector)
.then(data => {
console.log(`mifareClassicReadBlock(${sector}) completed`);
resolve(data);
})
.catch(err => {
console.log(`mifareClassicReadBlock(${sector}) failed:`, err);
reject(err);
});
})
.catch(err => {
console.log(`mifareClassicAuthenticateA(${sector}) failed:`, err);
reject(err);
});
});
};
const sector0Data = await readAuthenticatedA(0, [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]);
ByteParser API (simple utility for working with byte[] arrays like in Mifare Classic cards)
byteToHexString(bytes)
Converts a byte array byte[]
to a hex string.
Arguments
bytes
-byte[]
- the result of a mifareClassicReadBlock call.
Examples
let hexString = ByteParser.byteToHexString(result);
console.log('hex string: ' + hexString);
byteToString(bytes)
Converts a byte array byte[]
to a string (if the data represents an ASCII string).
Arguments
bytes
-byte[]
- the result of a mifareClassicReadBlock call.
Examples
let str = ByteParser.byteToString(result);
console.log('string: ' + str);
NFC Hardware requirement on Android
By default react-native-nfc-manager is set to not require NFC hardware on Android. This setting will overwrite what ever you put in your main AndroidManifest.xml file during react-native link
phase.
If you want to change this behavior to only have your app support NFC devices you have to override you app manifest manually.
Current setting is:
<uses-feature android:name="android.hardware.nfc" android:required="false" />
If you want to only have your app support NFC devices then you have to change required to true.