react-native-nfc-manager 3.13.1 → 3.13.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -0
- package/android/src/main/java/community/revteltech/nfc/NfcManager.java +131 -22
- package/index.d.ts +16 -0
- package/ios/NfcManager.m +5 -1
- package/package.json +1 -1
- package/react-native-nfc-manager.podspec +5 -1
- package/src/NfcManagerAndroid.js +5 -2
- package/src/NfcTech/MifareClassicHandlerAndroid.js +42 -0
package/README.md
CHANGED
|
@@ -69,6 +69,12 @@ We have a full featured NFC utility app using this library available for downloa
|
|
|
69
69
|
|
|
70
70
|
It also open sourced in this repo: [React Native NFC ReWriter App](https://github.com/revtel/react-native-nfc-rewriter)
|
|
71
71
|
|
|
72
|
+
## Learn
|
|
73
|
+
|
|
74
|
+
We have published a React Native NFC course with [newline.co](https://www.newline.co/), check it out!
|
|
75
|
+
- Free course (1 hour) about basic NFC setup and concept [here](https://www.youtube.com/watch?v=rAS-DvNUFck)
|
|
76
|
+
- Full course (3 hours) for more (NDEF, Deep Linking, NTAG password protection, signature with UID) [here](https://www.newline.co/courses/newline-guide-to-nfcs-with-react-native)
|
|
77
|
+
|
|
72
78
|
## Usage
|
|
73
79
|
|
|
74
80
|
The simplest (and most common) use case for this library is to read `NFC` tags containing `NDEF`, which can be achieved via the following codes:
|
|
@@ -536,6 +536,99 @@ class NfcManager extends ReactContextBaseJavaModule implements ActivityEventList
|
|
|
536
536
|
}
|
|
537
537
|
}
|
|
538
538
|
|
|
539
|
+
@ReactMethod
|
|
540
|
+
public void mifareClassicIncrementBlock(int blockIndex, int value, Callback callback) {
|
|
541
|
+
synchronized(this) {
|
|
542
|
+
if (techRequest != null) {
|
|
543
|
+
try {
|
|
544
|
+
MifareClassic mifareTag = (MifareClassic) techRequest.getTechHandle();
|
|
545
|
+
if (mifareTag == null || mifareTag.getType() == MifareClassic.TYPE_UNKNOWN) {
|
|
546
|
+
// Not a mifare card, fail
|
|
547
|
+
callback.invoke("mifareClassicIncrementBlock fail: TYPE_UNKNOWN");
|
|
548
|
+
return;
|
|
549
|
+
} else if (blockIndex >= mifareTag.getBlockCount()) {
|
|
550
|
+
// Check if in range
|
|
551
|
+
String msg = String.format("mifareClassicIncrementBlock fail: invalid block %d (max %d)", blockIndex, mifareTag.getBlockCount());
|
|
552
|
+
callback.invoke(msg);
|
|
553
|
+
return;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
mifareTag.increment(blockIndex, value);
|
|
557
|
+
|
|
558
|
+
callback.invoke(null, true);
|
|
559
|
+
} catch (TagLostException ex) {
|
|
560
|
+
callback.invoke("mifareClassicIncrementBlock fail: TAG_LOST");
|
|
561
|
+
} catch (Exception ex) {
|
|
562
|
+
callback.invoke("mifareClassicIncrementBlock fail: " + ex.toString());
|
|
563
|
+
}
|
|
564
|
+
} else {
|
|
565
|
+
callback.invoke(ERR_NO_TECH_REQ);
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
@ReactMethod
|
|
571
|
+
public void mifareClassicDecrementBlock(int blockIndex, int value, Callback callback) {
|
|
572
|
+
synchronized(this) {
|
|
573
|
+
if (techRequest != null) {
|
|
574
|
+
try {
|
|
575
|
+
MifareClassic mifareTag = (MifareClassic) techRequest.getTechHandle();
|
|
576
|
+
if (mifareTag == null || mifareTag.getType() == MifareClassic.TYPE_UNKNOWN) {
|
|
577
|
+
// Not a mifare card, fail
|
|
578
|
+
callback.invoke("mifareClassicDecrementBlock fail: TYPE_UNKNOWN");
|
|
579
|
+
return;
|
|
580
|
+
} else if (blockIndex >= mifareTag.getBlockCount()) {
|
|
581
|
+
// Check if in range
|
|
582
|
+
String msg = String.format("mifareClassicDecrementBlock fail: invalid block %d (max %d)", blockIndex, mifareTag.getBlockCount());
|
|
583
|
+
callback.invoke(msg);
|
|
584
|
+
return;
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
mifareTag.decrement(blockIndex, value);
|
|
588
|
+
|
|
589
|
+
callback.invoke(null, true);
|
|
590
|
+
} catch (TagLostException ex) {
|
|
591
|
+
callback.invoke("mifareClassicDecrementBlock fail: TAG_LOST");
|
|
592
|
+
} catch (Exception ex) {
|
|
593
|
+
callback.invoke("mifareClassicDecrementBlock fail: " + ex.toString());
|
|
594
|
+
}
|
|
595
|
+
} else {
|
|
596
|
+
callback.invoke(ERR_NO_TECH_REQ);
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
@ReactMethod
|
|
602
|
+
public void mifareClassicTransferBlock(int blockIndex, Callback callback) {
|
|
603
|
+
synchronized(this) {
|
|
604
|
+
if (techRequest != null) {
|
|
605
|
+
try {
|
|
606
|
+
MifareClassic mifareTag = (MifareClassic) techRequest.getTechHandle();
|
|
607
|
+
if (mifareTag == null || mifareTag.getType() == MifareClassic.TYPE_UNKNOWN) {
|
|
608
|
+
// Not a mifare card, fail
|
|
609
|
+
callback.invoke("mifareClassicTransferBlock fail: TYPE_UNKNOWN");
|
|
610
|
+
return;
|
|
611
|
+
} else if (blockIndex >= mifareTag.getBlockCount()) {
|
|
612
|
+
// Check if in range
|
|
613
|
+
String msg = String.format("mifareClassicTransferBlock fail: invalid block %d (max %d)", blockIndex, mifareTag.getBlockCount());
|
|
614
|
+
callback.invoke(msg);
|
|
615
|
+
return;
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
mifareTag.transfer(blockIndex);
|
|
619
|
+
|
|
620
|
+
callback.invoke(null, true);
|
|
621
|
+
} catch (TagLostException ex) {
|
|
622
|
+
callback.invoke("mifareClassicTransferBlock fail: TAG_LOST");
|
|
623
|
+
} catch (Exception ex) {
|
|
624
|
+
callback.invoke("mifareClassicTransferBlock fail: " + ex.toString());
|
|
625
|
+
}
|
|
626
|
+
} else {
|
|
627
|
+
callback.invoke(ERR_NO_TECH_REQ);
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
|
|
539
632
|
@ReactMethod
|
|
540
633
|
public void mifareUltralightReadPages(int pageOffset, Callback callback) {
|
|
541
634
|
synchronized(this) {
|
|
@@ -971,11 +1064,11 @@ class NfcManager extends ReactContextBaseJavaModule implements ActivityEventList
|
|
|
971
1064
|
|
|
972
1065
|
@ReactMethod
|
|
973
1066
|
private void registerTagEvent(ReadableMap options, Callback callback) {
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
1067
|
+
isReaderModeEnabled = options.getBoolean("isReaderModeEnabled");
|
|
1068
|
+
readerModeFlags = options.getInt("readerModeFlags");
|
|
1069
|
+
readerModeDelay = options.getInt("readerModeDelay");
|
|
977
1070
|
|
|
978
|
-
Log.d(LOG_TAG, "
|
|
1071
|
+
Log.d(LOG_TAG, "registerTagEvent");
|
|
979
1072
|
isForegroundEnabled = true;
|
|
980
1073
|
|
|
981
1074
|
// capture all mime-based dispatch NDEF
|
|
@@ -1002,18 +1095,23 @@ class NfcManager extends ReactContextBaseJavaModule implements ActivityEventList
|
|
|
1002
1095
|
|
|
1003
1096
|
@ReactMethod
|
|
1004
1097
|
private void unregisterTagEvent(Callback callback) {
|
|
1005
|
-
Log.d(LOG_TAG, "
|
|
1006
|
-
isForegroundEnabled = false;
|
|
1007
|
-
intentFilters.clear();
|
|
1098
|
+
Log.d(LOG_TAG, "unregisterTagEvent");
|
|
1008
1099
|
if (isResumed) {
|
|
1009
1100
|
enableDisableForegroundDispatch(false);
|
|
1010
1101
|
}
|
|
1102
|
+
|
|
1103
|
+
intentFilters.clear();
|
|
1104
|
+
isForegroundEnabled = false;
|
|
1105
|
+
isReaderModeEnabled = false;
|
|
1106
|
+
readerModeFlags = 0;
|
|
1107
|
+
readerModeDelay = 0;
|
|
1108
|
+
|
|
1011
1109
|
callback.invoke();
|
|
1012
1110
|
}
|
|
1013
1111
|
|
|
1014
1112
|
@ReactMethod
|
|
1015
1113
|
private void hasTagEventRegistration(Callback callback) {
|
|
1016
|
-
Log.d(LOG_TAG, "isSessionAvailable");
|
|
1114
|
+
Log.d(LOG_TAG, "isSessionAvailable: " + isForegroundEnabled);
|
|
1017
1115
|
callback.invoke(null, isForegroundEnabled);
|
|
1018
1116
|
}
|
|
1019
1117
|
|
|
@@ -1061,25 +1159,36 @@ class NfcManager extends ReactContextBaseJavaModule implements ActivityEventList
|
|
|
1061
1159
|
}
|
|
1062
1160
|
|
|
1063
1161
|
if (enable) {
|
|
1064
|
-
Log.i(LOG_TAG, "enableReaderMode");
|
|
1162
|
+
Log.i(LOG_TAG, "enableReaderMode: " + readerModeFlags);
|
|
1065
1163
|
Bundle readerModeExtras = new Bundle();
|
|
1066
1164
|
readerModeExtras.putInt(NfcAdapter.EXTRA_READER_PRESENCE_CHECK_DELAY, readerModeDelay * 1000);
|
|
1067
1165
|
nfcAdapter.enableReaderMode(currentActivity, new NfcAdapter.ReaderCallback() {
|
|
1068
1166
|
@Override
|
|
1069
1167
|
public void onTagDiscovered(Tag tag) {
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1168
|
+
synchronized (this) {
|
|
1169
|
+
manager.tag = tag;
|
|
1170
|
+
Log.d(LOG_TAG, "readerMode onTagDiscovered");
|
|
1171
|
+
WritableMap nfcTag = null;
|
|
1172
|
+
// if the tag contains NDEF, we want to report the content
|
|
1173
|
+
if (Arrays.asList(tag.getTechList()).contains(Ndef.class.getName())) {
|
|
1174
|
+
Ndef ndef = Ndef.get(tag);
|
|
1175
|
+
nfcTag = ndef2React(ndef, new NdefMessage[] { ndef.getCachedNdefMessage() });
|
|
1176
|
+
} else {
|
|
1177
|
+
nfcTag = tag2React(tag);
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
if (nfcTag != null) {
|
|
1181
|
+
sendEvent("NfcManagerDiscoverTag", nfcTag);
|
|
1182
|
+
if (techRequest!= null && !techRequest.isConnected()) {
|
|
1183
|
+
boolean result = techRequest.connect(tag);
|
|
1184
|
+
if (result) {
|
|
1185
|
+
techRequest.getPendingCallback().invoke(null, techRequest.getTechType());
|
|
1186
|
+
} else {
|
|
1187
|
+
// this indicates that we get a NFC tag, but none of the user required tech is matched
|
|
1188
|
+
techRequest.getPendingCallback().invoke(null, null);
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1083
1192
|
}
|
|
1084
1193
|
}
|
|
1085
1194
|
}, readerModeFlags, readerModeExtras);
|
package/index.d.ts
CHANGED
|
@@ -88,6 +88,7 @@ declare module 'react-native-nfc-manager' {
|
|
|
88
88
|
|
|
89
89
|
export interface CancelTechReqOpts {
|
|
90
90
|
throwOnError?: boolean = false;
|
|
91
|
+
delayMsAndroid?: number = 1000;
|
|
91
92
|
}
|
|
92
93
|
|
|
93
94
|
interface NdefHandler {
|
|
@@ -122,11 +123,26 @@ declare module 'react-native-nfc-manager' {
|
|
|
122
123
|
block: ArrayLike<number>,
|
|
123
124
|
simpliArr: any[],
|
|
124
125
|
) => Promise<void>;
|
|
126
|
+
mifareClassicIncrementBlock: (
|
|
127
|
+
block: ArrayLike<number>,
|
|
128
|
+
data: number,
|
|
129
|
+
) => Promise<void>;
|
|
130
|
+
mifareClassicDecrementBlock: (
|
|
131
|
+
block: ArrayLike<number>,
|
|
132
|
+
data: number,
|
|
133
|
+
) => Promise<void>;
|
|
134
|
+
mifareClassicTransferBlock: (
|
|
135
|
+
block: ArrayLike<number>,
|
|
136
|
+
) => Promise<void>;
|
|
125
137
|
mifareClassicGetSectorCount: () => Promise<number>;
|
|
126
138
|
mifareClassicAuthenticateA: (
|
|
127
139
|
sector: number,
|
|
128
140
|
keys: number[],
|
|
129
141
|
) => Promise<void>;
|
|
142
|
+
mifareClassicAuthenticateB: (
|
|
143
|
+
sector: number,
|
|
144
|
+
keys: number[],
|
|
145
|
+
) => Promise<void>;
|
|
130
146
|
}
|
|
131
147
|
|
|
132
148
|
interface MifareUltralightHandlerAndroid {
|
package/ios/NfcManager.m
CHANGED
|
@@ -286,8 +286,12 @@ RCT_EXPORT_METHOD(requestTechnology: (NSArray *)techs options: (NSDictionary *)o
|
|
|
286
286
|
{
|
|
287
287
|
if (@available(iOS 13.0, *)) {
|
|
288
288
|
if (tagSession == nil && session == nil) {
|
|
289
|
+
NFCPollingOption pollFlags = NFCPollingISO14443 | NFCPollingISO15693;
|
|
290
|
+
if ([techs containsObject:@"felica"]) {
|
|
291
|
+
pollFlags |= NFCPollingISO18092;
|
|
292
|
+
}
|
|
289
293
|
tagSession = [[NFCTagReaderSession alloc]
|
|
290
|
-
|
|
294
|
+
initWithPollingOption:pollFlags delegate:self queue:dispatch_get_main_queue()];
|
|
291
295
|
tagSession.alertMessage = [options objectForKey:@"alertMessage"];
|
|
292
296
|
[tagSession beginSession];
|
|
293
297
|
techRequestTypes = techs;
|
package/package.json
CHANGED
package/src/NfcManagerAndroid.js
CHANGED
|
@@ -15,6 +15,8 @@ const NfcAdapter = {
|
|
|
15
15
|
FLAG_READER_NO_PLATFORM_SOUNDS: 0x100,
|
|
16
16
|
};
|
|
17
17
|
|
|
18
|
+
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
|
|
19
|
+
|
|
18
20
|
class NfcManagerAndroid extends NfcManagerBase {
|
|
19
21
|
constructor() {
|
|
20
22
|
super();
|
|
@@ -42,12 +44,13 @@ class NfcManagerAndroid extends NfcManagerBase {
|
|
|
42
44
|
};
|
|
43
45
|
|
|
44
46
|
cancelTechnologyRequest = async (options = {}) => {
|
|
45
|
-
const {throwOnError = false} = options;
|
|
47
|
+
const {throwOnError = false, delayMsAndroid = 1000} = options;
|
|
46
48
|
|
|
47
49
|
try {
|
|
48
50
|
await callNative('cancelTechnologyRequest');
|
|
49
51
|
|
|
50
|
-
if (
|
|
52
|
+
if (this.cleanUpTagRegistration) {
|
|
53
|
+
await delay(delayMsAndroid);
|
|
51
54
|
await this.unregisterTagEvent();
|
|
52
55
|
this.cleanUpTagRegistration = false;
|
|
53
56
|
}
|
|
@@ -67,6 +67,48 @@ class MifareClassicHandlerAndroid {
|
|
|
67
67
|
callNative('mifareClassicWriteBlock', [block, data]),
|
|
68
68
|
);
|
|
69
69
|
}
|
|
70
|
+
|
|
71
|
+
async mifareClassicIncrementBlock(block, value) {
|
|
72
|
+
if (
|
|
73
|
+
!value ||
|
|
74
|
+
Number.isNaN(value)) {
|
|
75
|
+
throw new Error(
|
|
76
|
+
`value should be a number`,
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return handleNativeException(
|
|
81
|
+
callNative('mifareClassicIncrementBlock', [block, value]),
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async mifareClassicDecrementBlock(block, value) {
|
|
86
|
+
if (
|
|
87
|
+
!value ||
|
|
88
|
+
Number.isNaN(value)) {
|
|
89
|
+
throw new Error(
|
|
90
|
+
`value should be a number`,
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return handleNativeException(
|
|
95
|
+
callNative('mifareClassicDecrementBlock', [block, value]),
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
async mifareClassicTransferBlock(block) {
|
|
99
|
+
if (
|
|
100
|
+
!block ||
|
|
101
|
+
Number.isNaN(block)) {
|
|
102
|
+
throw new Error(
|
|
103
|
+
`block should be a number`,
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return handleNativeException(
|
|
108
|
+
callNative('mifareClassicTransferBlock', [block]),
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
70
112
|
}
|
|
71
113
|
|
|
72
114
|
export {MifareClassicHandlerAndroid};
|