@exxili/capacitor-nfc 0.0.13 → 0.0.14
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/ExxiliCapacitorNfc.podspec +17 -17
- package/Package.swift +28 -28
- package/README.md +597 -595
- package/android/build.gradle +67 -67
- package/android/src/main/AndroidManifest.xml +2 -2
- package/android/src/main/kotlin/com/exxili/capacitornfc/MainActivity.kt +11 -11
- package/android/src/main/kotlin/com/exxili/capacitornfc/NFCPlugin.kt +492 -464
- package/dist/esm/definitions.d.ts +13 -0
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/web.d.ts +4 -1
- package/dist/esm/web.js +3 -0
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +4 -0
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +4 -0
- package/dist/plugin.js.map +1 -1
- package/ios/Sources/NFCPlugin/NFCPlugin.swift +181 -169
- package/ios/Sources/NFCPlugin/NFCReader.swift +507 -507
- package/ios/Sources/NFCPlugin/NFCWriter.swift +89 -89
- package/ios/Tests/NFCPluginTests/NFCPluginTests.swift +15 -15
- package/package.json +90 -90
package/README.md
CHANGED
|
@@ -1,595 +1,597 @@
|
|
|
1
|
-
# Capacitor NFC Plugin (@exxili/capacitor-nfc)
|
|
2
|
-
|
|
3
|
-
A Capacitor plugin for reading and writing NFC tags on iOS and Android devices. This plugin allows you to:
|
|
4
|
-
|
|
5
|
-
- Read NDEF messages from NFC tags.
|
|
6
|
-
- Write NDEF messages to NFC tags.
|
|
7
|
-
|
|
8
|
-
**Note**: NFC functionality is only available on compatible iOS devices running iOS 13.0 or later.
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
- [
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
- [
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
- [`
|
|
27
|
-
- [`
|
|
28
|
-
- [`
|
|
29
|
-
|
|
30
|
-
- [`
|
|
31
|
-
- [
|
|
32
|
-
- [`
|
|
33
|
-
|
|
34
|
-
- [`
|
|
35
|
-
- [`
|
|
36
|
-
- [`
|
|
37
|
-
- [`
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
- [
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
>
|
|
69
|
-
>
|
|
70
|
-
>
|
|
71
|
-
>
|
|
72
|
-
>
|
|
73
|
-
>
|
|
74
|
-
>
|
|
75
|
-
>
|
|
76
|
-
>
|
|
77
|
-
>
|
|
78
|
-
> <string>
|
|
79
|
-
> <string>
|
|
80
|
-
>
|
|
81
|
-
>
|
|
82
|
-
>
|
|
83
|
-
>
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
```
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
console.log('
|
|
143
|
-
|
|
144
|
-
console.log('Tag
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
- `mode: '
|
|
238
|
-
- `mode: '
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
await NFC.
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
-
|
|
282
|
-
- `
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
If you
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
- `
|
|
321
|
-
- `
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
const
|
|
334
|
-
const
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
offError();
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
- `
|
|
396
|
-
- `
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
```
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
if (
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
const
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
}
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
1
|
+
# Capacitor NFC Plugin (@exxili/capacitor-nfc)
|
|
2
|
+
|
|
3
|
+
A Capacitor plugin for reading and writing NFC tags on iOS and Android devices. This plugin allows you to:
|
|
4
|
+
|
|
5
|
+
- Read NDEF messages from NFC tags.
|
|
6
|
+
- Write NDEF messages to NFC tags.
|
|
7
|
+
|
|
8
|
+
**Note**: NFC functionality is only available on compatible iOS devices running iOS 13.0 or later.
|
|
9
|
+
|
|
10
|
+
This project is maintained on a best-effort basis. No response, review, or release timeframe is guaranteed
|
|
11
|
+
|
|
12
|
+
## Table of Contents
|
|
13
|
+
|
|
14
|
+
- [Capacitor NFC Plugin (@exxili/capacitor-nfc)](#capacitor-nfc-plugin-exxilicapacitor-nfc)
|
|
15
|
+
- [Table of Contents](#table-of-contents)
|
|
16
|
+
- [Installation](#installation)
|
|
17
|
+
- [iOS Setup](#ios-setup)
|
|
18
|
+
- [1. Enable NFC Capability](#1-enable-nfc-capability)
|
|
19
|
+
- [2. Add Usage Description](#2-add-usage-description)
|
|
20
|
+
- [Android Setup](#android-setup)
|
|
21
|
+
- [Usage](#usage)
|
|
22
|
+
- [Reading NFC Tags](#reading-nfc-tags)
|
|
23
|
+
- [Writing NFC Tags](#writing-nfc-tags)
|
|
24
|
+
- [API](#api)
|
|
25
|
+
- [Methods](#methods)
|
|
26
|
+
- [`isSupported()`](#issupported)
|
|
27
|
+
- [`startScan()`](#startscan)
|
|
28
|
+
- [`cancelScan()`](#cancelscan)
|
|
29
|
+
- [`writeNDEF(options: NDEFWriteOptions<T extends string | number[] | Uint8Array = string>)`](#writendefoptions-ndefwriteoptionst-extends-string--number--uint8array--string)
|
|
30
|
+
- [`cancelWriteAndroid()`](#cancelwriteandroid)
|
|
31
|
+
- [Listeners](#listeners)
|
|
32
|
+
- [`onRead(listener: (data: NDEFMessagesTransformable) => void)`](#onreadlistener-data-ndefmessagestransformable--void)
|
|
33
|
+
- [Interfaces](#interfaces)
|
|
34
|
+
- [`NDEFWriteOptions`](#ndefwriteoptions)
|
|
35
|
+
- [`NDEFMessagesTransformable`](#ndefmessagestransformable)
|
|
36
|
+
- [`NDEFMessages`](#ndefmessages)
|
|
37
|
+
- [`NDEFMessage`](#ndefmessage)
|
|
38
|
+
- [`NDEFRecord`](#ndefrecord)
|
|
39
|
+
- [`NFCError`](#nfcerror)
|
|
40
|
+
- [Integration into a Capacitor App](#integration-into-a-capacitor-app)
|
|
41
|
+
- [Example](#example)
|
|
42
|
+
- [License](#license)
|
|
43
|
+
|
|
44
|
+
## Installation
|
|
45
|
+
|
|
46
|
+
Install the plugin using npm:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
npm install @exxili/capacitor-nfc
|
|
50
|
+
npx cap sync
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## iOS Setup
|
|
54
|
+
|
|
55
|
+
To use NFC functionality on iOS, you need to perform some additional setup steps.
|
|
56
|
+
|
|
57
|
+
### 1. Enable NFC Capability
|
|
58
|
+
|
|
59
|
+
In Xcode:
|
|
60
|
+
|
|
61
|
+
1. Open your project (`.xcworkspace` file) in Xcode.
|
|
62
|
+
2. Select your project in the Project Navigator.
|
|
63
|
+
3. Select your app target.
|
|
64
|
+
4. Go to the **Signing & Capabilities** tab.
|
|
65
|
+
5. Click the `+ Capability` button.
|
|
66
|
+
6. Add **Near Field Communication Tag Reading**.
|
|
67
|
+
|
|
68
|
+
> **Advanced tag formats:** If you need ISO 7816, ISO 15693, or FeliCa access (to read raw UIDs, system codes, etc.), Apple requires additional entitlements in your provisioning profile and `Info.plist`. The plugin will fall back automatically when they are absent, but to unlock the full feature set add the relevant keys:
|
|
69
|
+
>
|
|
70
|
+
> ```xml
|
|
71
|
+
> <key>com.apple.developer.nfc.readersession.felica.systemcodes</key>
|
|
72
|
+
> <array>
|
|
73
|
+
> <string>12FC</string>
|
|
74
|
+
> <string>0000</string>
|
|
75
|
+
> </array>
|
|
76
|
+
> <key>com.apple.developer.nfc.readersession.iso7816.select-identifiers</key>
|
|
77
|
+
> <array>
|
|
78
|
+
> <string>D2760000850100</string>
|
|
79
|
+
> <string>D2760000850101</string>
|
|
80
|
+
> <string>D2760001180101</string>
|
|
81
|
+
> <string>00000000000000</string>
|
|
82
|
+
> </array>
|
|
83
|
+
> ```
|
|
84
|
+
>
|
|
85
|
+
> Replace the sample identifiers with the values required for your tags. Consult Apple's CoreNFC documentation for the complete list of entitlement keys.
|
|
86
|
+
|
|
87
|
+
### 2. Add Usage Description
|
|
88
|
+
|
|
89
|
+
Add the `NFCReaderUsageDescription` key to your `Info.plist` file to explain why your app needs access to NFC.
|
|
90
|
+
|
|
91
|
+
In your `Info.plist` file (usually located at `ios/App/App/Info.plist`), add:
|
|
92
|
+
|
|
93
|
+
```xml
|
|
94
|
+
<key>NFCReaderUsageDescription</key>
|
|
95
|
+
<string>This app requires access to NFC to read and write NFC tags.</string>
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Replace the description with a message that explains why your app needs NFC access.
|
|
99
|
+
|
|
100
|
+
## Android Setup
|
|
101
|
+
|
|
102
|
+
Add the following to your `AndroidManifest.xml` file:
|
|
103
|
+
|
|
104
|
+
```xml
|
|
105
|
+
<uses-permission android:name="android.permission.NFC" />
|
|
106
|
+
<uses-feature android:name="android.hardware.nfc" android:required="true" />
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Usage
|
|
110
|
+
|
|
111
|
+
Import the plugin into your code:
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
import { NFC } from '@exxili/capacitor-nfc';
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Reading NFC Tags
|
|
118
|
+
|
|
119
|
+
To read NFC tags, you need to listen for `nfcTag` events. On iOS, you must also start the NFC scanning session using `startScan()`.
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
import { NFC, NDEFMessagesTransformable, NFCError } from '@exxili/capacitor-nfc';
|
|
123
|
+
|
|
124
|
+
// Start NFC scanning (iOS only)
|
|
125
|
+
NFC.startScan().catch((error) => {
|
|
126
|
+
console.error('Error starting NFC scan:', error);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
// Listen for NFC tag detection
|
|
130
|
+
NFC.onRead((data: NDEFMessagesTransformable) => {
|
|
131
|
+
// Text (T) and URI (U) records decoded; others best-effort UTF-8
|
|
132
|
+
const asString = data.string();
|
|
133
|
+
console.log('First record text payload:', asString.messages[0]?.records[0]?.payload);
|
|
134
|
+
|
|
135
|
+
// Raw bytes
|
|
136
|
+
const asUint8 = data.uint8Array();
|
|
137
|
+
console.log('First record raw bytes length:', asUint8.messages[0]?.records[0]?.payload.length);
|
|
138
|
+
|
|
139
|
+
// Access tag information (UID, tech types, etc.)
|
|
140
|
+
const info = asString.tagInfo;
|
|
141
|
+
if (info?.fallback) {
|
|
142
|
+
console.log('Reader fallback mode:', info.fallbackMode, 'Reason:', info.reason);
|
|
143
|
+
} else if (info) {
|
|
144
|
+
console.log('Tag UID:', info.uid);
|
|
145
|
+
console.log('Tag technologies:', info.techTypes);
|
|
146
|
+
console.log('Tag type:', info.type);
|
|
147
|
+
if (info.maxSize) {
|
|
148
|
+
console.log('Max NDEF size:', info.maxSize);
|
|
149
|
+
}
|
|
150
|
+
console.log('Is writable:', info.isWritable);
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
// Handle NFC errors
|
|
155
|
+
NFC.onError((error: NFCError) => {
|
|
156
|
+
console.error('NFC Error:', error);
|
|
157
|
+
});
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Writing NFC Tags
|
|
161
|
+
|
|
162
|
+
To write NDEF messages to NFC tags, use the `writeNDEF` method and listen for `onWrite` events.
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
import { NFC, NDEFWriteOptions, NFCError } from '@exxili/capacitor-nfc';
|
|
166
|
+
|
|
167
|
+
const message: NDEFWriteOptions = {
|
|
168
|
+
records: [
|
|
169
|
+
{
|
|
170
|
+
type: 'T', // Well Known Text record. String payload will be encoded as: [status][lang='en'][UTF-8 text]
|
|
171
|
+
payload: 'Hello, NFC!',
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
type: 'U', // Well Known URI record. String payload encoded as: [0x00][URI bytes]
|
|
175
|
+
payload: 'https://example.com',
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
type: 'T',
|
|
179
|
+
payload: new Uint8Array([0x01, 0x65, 0x48, 0x69]), // Raw bytes preserved (DO NOT re-format)
|
|
180
|
+
},
|
|
181
|
+
],
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
// For complete control over binary content, use raw mode:
|
|
185
|
+
const rawMessage: NDEFWriteOptions = {
|
|
186
|
+
rawMode: true, // Bypasses automatic Text/URI formatting
|
|
187
|
+
records: [
|
|
188
|
+
{
|
|
189
|
+
type: 'T',
|
|
190
|
+
payload: 'Hello, NFC!', // Written as UTF-8 bytes without Text record prefix
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
type: 'custom',
|
|
194
|
+
payload: new Uint8Array([0x01, 0x02, 0x03, 0x04]), // Exact bytes written to tag
|
|
195
|
+
},
|
|
196
|
+
],
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
// Write NDEF message to NFC tag
|
|
200
|
+
NFC.writeNDEF(message)
|
|
201
|
+
.then(() => {
|
|
202
|
+
console.log('Write initiated');
|
|
203
|
+
})
|
|
204
|
+
.catch((error) => {
|
|
205
|
+
console.error('Error writing to NFC tag:', error);
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
// Listen for write success
|
|
209
|
+
NFC.onWrite(() => {
|
|
210
|
+
console.log('NDEF message written successfully.');
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
// Handle NFC errors
|
|
214
|
+
NFC.onError((error: NFCError) => {
|
|
215
|
+
console.error('NFC Error:', error);
|
|
216
|
+
});
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## API
|
|
220
|
+
|
|
221
|
+
### Methods
|
|
222
|
+
|
|
223
|
+
#### `isSupported()`
|
|
224
|
+
|
|
225
|
+
Returns if NFC is supported on the scanning device.
|
|
226
|
+
|
|
227
|
+
**Returns**: `Promise<{ supported: boolean }>`
|
|
228
|
+
|
|
229
|
+
#### `startScan()`
|
|
230
|
+
|
|
231
|
+
Starts the NFC scanning session on **_iOS only_**. Android devices are always in reading mode, so setting up the `nfcTag` listener is sufficient to handle tag reads on Android.
|
|
232
|
+
|
|
233
|
+
The iOS implementation now adapts automatically if the extended CoreNFC entitlements (ISO 7816, ISO 15693, FeliCa) are missing. The plugin first attempts the advanced tag reader so you can access UID/tech info. When iOS reports `Missing required entitlement`, the plugin downgrades to a compatibility mode (ISO 14443 only) and, if necessary, to the classic NDEF reader. A synthetic `nfcTag` event is emitted with `tagInfo.fallback`, `tagInfo.fallbackMode`, and `tagInfo.reason` so your UI can react immediately.
|
|
234
|
+
|
|
235
|
+
You can override the mode explicitly:
|
|
236
|
+
|
|
237
|
+
- `mode: 'auto'` (default) – advanced reader with automatic downgrade and caching.
|
|
238
|
+
- `mode: 'full'` – force a fresh attempt at the advanced reader, resetting cached fallback state.
|
|
239
|
+
- `mode: 'compat'` – skip the advanced probe and jump straight to the ISO 14443 compatibility reader.
|
|
240
|
+
- `mode: 'ndef'` – bypass tag sessions entirely and revert to the legacy NDEF-only reader.
|
|
241
|
+
|
|
242
|
+
Legacy booleans `forceFull`, `forceCompat`, and `forceNDEF` map to the options above for backwards compatibility.
|
|
243
|
+
|
|
244
|
+
**Returns**: `Promise<void>`
|
|
245
|
+
|
|
246
|
+
```typescript
|
|
247
|
+
NFC.startScan({ mode: 'auto' })
|
|
248
|
+
.then(() => {
|
|
249
|
+
// Scanning started
|
|
250
|
+
})
|
|
251
|
+
.catch((error) => {
|
|
252
|
+
console.error('Error starting NFC scan:', error);
|
|
253
|
+
});
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
#### `cancelScan()`
|
|
257
|
+
|
|
258
|
+
Immediately invalidates the active iOS CoreNFC reader session (if any). Useful when you want to abort a scan early instead of waiting for the user to cancel or for a tag detection timeout.
|
|
259
|
+
|
|
260
|
+
Platform notes:
|
|
261
|
+
|
|
262
|
+
- iOS: Actively ends the session. Calling `startScan()` again after the returned promise resolves is safe.
|
|
263
|
+
- Android: No-op (Android is always passively listening via foreground dispatch; you generally just ignore future events or control UI state).
|
|
264
|
+
|
|
265
|
+
```typescript
|
|
266
|
+
await NFC.cancelScan(); // iOS: ends session; Android: no-op
|
|
267
|
+
// Optionally restart
|
|
268
|
+
await NFC.startScan();
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
**Returns**: `Promise<void>`
|
|
272
|
+
|
|
273
|
+
#### `writeNDEF(options: NDEFWriteOptions<T extends string | number[] | Uint8Array = string>)`
|
|
274
|
+
|
|
275
|
+
Writes an NDEF message to an NFC tag.
|
|
276
|
+
|
|
277
|
+
Payload may be provided as a string, `Uint8Array`, or an array of numbers.
|
|
278
|
+
|
|
279
|
+
Automatic formatting rules (to aid interoperability):
|
|
280
|
+
|
|
281
|
+
- Text (`type: 'T'` + string payload): encoded per NFC Forum RTD Text spec `[status][lang=en][UTF-8 text]`.
|
|
282
|
+
- URI (`type: 'U'` + string payload): encoded as `[0x00][UTF-8 URI bytes]` (prefix compression not yet applied).
|
|
283
|
+
- Any other `type` + string payload: UTF-8 bytes only (no extra framing).
|
|
284
|
+
- `Uint8Array` or `number[]` payloads are treated as raw bytes and written verbatim (never altered).
|
|
285
|
+
|
|
286
|
+
**Raw Mode**: Set `rawMode: true` to bypass automatic Well Known Type formatting entirely. All string payloads will be written as UTF-8 bytes without Text ('T') or URI ('U') prefixes, giving you complete control over the binary content.
|
|
287
|
+
|
|
288
|
+
If you need full manual control of a Text or URI record, supply raw bytes (number[] / Uint8Array) and the plugin will not modify them.
|
|
289
|
+
|
|
290
|
+
If you attempt to write zero records the promise rejects with `Error("At least one NDEF record is required")`.
|
|
291
|
+
|
|
292
|
+
Android use: since Android has no default UI for reading and writing NFC tags, it is recommended that you add a UI indicator to your application when calling `writeNDEF` and remove it in the `nfcWriteSuccess` listener callback and the `nfcError` listener callback. This will prevent accidental writes to tags that your users intended to read from.
|
|
293
|
+
|
|
294
|
+
**Parameters**:
|
|
295
|
+
|
|
296
|
+
- `options: NDEFWriteOptions<T extends string | number[] | Uint8Array = string>` - The NDEF message to write. Must include at least one record.
|
|
297
|
+
|
|
298
|
+
**Returns**: `Promise<void>`
|
|
299
|
+
|
|
300
|
+
```typescript
|
|
301
|
+
NFC.writeNDEF(options)
|
|
302
|
+
.then(() => {
|
|
303
|
+
// Write initiated
|
|
304
|
+
})
|
|
305
|
+
.catch((error) => {
|
|
306
|
+
console.error('Error writing NDEF message:', error);
|
|
307
|
+
});
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
#### `cancelWriteAndroid()`
|
|
311
|
+
|
|
312
|
+
Cancels an Android NFC write operation. Android does not have a native UI for NFC tag writing, so this method allows developers to hook up a custom UI to cancel an in-progress scan.
|
|
313
|
+
|
|
314
|
+
### Listeners
|
|
315
|
+
|
|
316
|
+
#### `onRead(listener: (data: NDEFMessagesTransformable) => void)`
|
|
317
|
+
|
|
318
|
+
Adds a listener for NFC tag detection events. Returns type `NDEFMessagesTransformable`, which returns the following methods to provide the payload:
|
|
319
|
+
|
|
320
|
+
- `string()`: Returns `NDEFMessages<string>`, where all payloads are strings.
|
|
321
|
+
- `base64()`: Returns `NDEFMessages<string>`, where all payloads are the base64-encoded payloads read from the NFC tag.
|
|
322
|
+
- `uint8Array()`: Returns `NDEFMessages<Uint8Array>`, where all payloads are the `Uint8Array` bytes from the NFC tag.
|
|
323
|
+
- `numberArray()`: Returns `NDEFMessages<number[]>`, where all payloads' bytes from the NFC tag are represented as a `number[]`.
|
|
324
|
+
|
|
325
|
+
**Parameters**:
|
|
326
|
+
|
|
327
|
+
- `listener: (data: NDEFMessagesTransformable) => void` - The function to call when an NFC tag is detected.
|
|
328
|
+
|
|
329
|
+
**Returns**: `() => void` Unsubscribe function to remove just this listener.
|
|
330
|
+
|
|
331
|
+
```typescript
|
|
332
|
+
const offRead = NFC.onRead((data) => {
|
|
333
|
+
const textRecords = data.string(); // Decoded string representation
|
|
334
|
+
const base64Records = data.base64(); // Original base64 payloads
|
|
335
|
+
const bytesRecords = data.uint8Array(); // Uint8Array payloads
|
|
336
|
+
const numArrayRecords = data.numberArray(); // number[] representation
|
|
337
|
+
console.log(textRecords);
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
// Later (component unmount / cleanup)
|
|
341
|
+
offRead();
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
> Tip: Register listeners once per screen/component and always dispose them when unmounting to avoid duplicate callbacks.
|
|
345
|
+
|
|
346
|
+
````
|
|
347
|
+
|
|
348
|
+
#### On Error
|
|
349
|
+
|
|
350
|
+
Adds a listener for NFC error events.
|
|
351
|
+
|
|
352
|
+
**Parameters**:
|
|
353
|
+
|
|
354
|
+
- `listener: (error: NFCError) => void` - The function to call when an NFC error occurs.
|
|
355
|
+
|
|
356
|
+
**Returns**: `() => void` Unsubscribe function.
|
|
357
|
+
|
|
358
|
+
#### On Error
|
|
359
|
+
|
|
360
|
+
Adds a listener for NFC error events.
|
|
361
|
+
|
|
362
|
+
**Parameters**:
|
|
363
|
+
|
|
364
|
+
- `listener: (error: NFCError) => void` - The function to call when an NFC error occurs.
|
|
365
|
+
|
|
366
|
+
**Returns**: `() => void` Unsubscribe function.
|
|
367
|
+
|
|
368
|
+
```typescript
|
|
369
|
+
const offError = NFC.onError(err => console.error('NFC Error:', err));
|
|
370
|
+
// later
|
|
371
|
+
offError();
|
|
372
|
+
````
|
|
373
|
+
|
|
374
|
+
### Interfaces
|
|
375
|
+
|
|
376
|
+
#### `NDEFWriteOptions`
|
|
377
|
+
|
|
378
|
+
Options for writing an NDEF message.
|
|
379
|
+
|
|
380
|
+
```typescript
|
|
381
|
+
interface NDEFWriteOptions<T extends string | number[] | Uint8Array = string> {
|
|
382
|
+
records: NDEFRecord<T>[];
|
|
383
|
+
/**
|
|
384
|
+
* When true, bypasses automatic Well Known Type formatting (Text 'T' and URI 'U' prefixes).
|
|
385
|
+
* All payloads are written as raw bytes without additional framing.
|
|
386
|
+
*/
|
|
387
|
+
rawMode?: boolean;
|
|
388
|
+
}
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
#### `NDEFMessagesTransformable`
|
|
392
|
+
|
|
393
|
+
Returned by `onRead` and includes the following methods to provide the payload:
|
|
394
|
+
|
|
395
|
+
- `string()`: Returns `NDEFMessages<string>`, where all payloads are strings.
|
|
396
|
+
- `base64()`: Returns `NDEFMessages<string>`, where all payloads are the base64-encoded payloads read from the NFC tag.
|
|
397
|
+
- `uint8Array()`: Returns `NDEFMessages<Uint8Array>`, where all payloads are the `Uint8Array` bytes from the NFC tag.
|
|
398
|
+
- `numberArray()`: Returns `NDEFMessages<number[]>`, where all payloads bytes from the NFC tag represented as a `number[]`.
|
|
399
|
+
|
|
400
|
+
```typescript
|
|
401
|
+
interface NDEFMessagesTransformable {
|
|
402
|
+
base64: () => NDEFMessages<string>; // Original base64 strings
|
|
403
|
+
uint8Array: () => NDEFMessages<Uint8Array>; // Raw bytes
|
|
404
|
+
string: () => NDEFMessages<string>; // Decoded (T & U handled, others UTF-8 best-effort)
|
|
405
|
+
numberArray: () => NDEFMessages<number[]>; // Raw bytes as number[]
|
|
406
|
+
}
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
#### `NDEFMessages`
|
|
410
|
+
|
|
411
|
+
Data received from an NFC tag.
|
|
412
|
+
|
|
413
|
+
```typescript
|
|
414
|
+
interface NDEFMessages {
|
|
415
|
+
messages: NDEFMessage[];
|
|
416
|
+
tagInfo?: TagInfo;
|
|
417
|
+
}
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
#### `TagInfo`
|
|
421
|
+
|
|
422
|
+
Information about the NFC tag that was read.
|
|
423
|
+
|
|
424
|
+
```typescript
|
|
425
|
+
interface TagInfo {
|
|
426
|
+
/**
|
|
427
|
+
* The unique identifier of the tag (UID) as a hex string
|
|
428
|
+
*/
|
|
429
|
+
uid?: string;
|
|
430
|
+
|
|
431
|
+
/**
|
|
432
|
+
* The NFC tag technology types supported
|
|
433
|
+
*/
|
|
434
|
+
techTypes?: string[];
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* The maximum size of NDEF message that can be written to this tag (if applicable)
|
|
438
|
+
*/
|
|
439
|
+
maxSize?: number;
|
|
440
|
+
|
|
441
|
+
/**
|
|
442
|
+
* Whether the tag is writable
|
|
443
|
+
*/
|
|
444
|
+
isWritable?: boolean;
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* The tag type (e.g., "ISO14443-4", "MifareClassic", etc.)
|
|
448
|
+
*/
|
|
449
|
+
type?: string;
|
|
450
|
+
|
|
451
|
+
/**
|
|
452
|
+
* Present when the plugin downgraded capabilities for compatibility.
|
|
453
|
+
*/
|
|
454
|
+
fallback?: boolean;
|
|
455
|
+
|
|
456
|
+
/**
|
|
457
|
+
* Which fallback strategy is in use (`compat` or `ndef`).
|
|
458
|
+
*/
|
|
459
|
+
fallbackMode?: 'compat' | 'ndef';
|
|
460
|
+
|
|
461
|
+
/**
|
|
462
|
+
* Reason metadata (e.g., `missing-entitlement`).
|
|
463
|
+
*/
|
|
464
|
+
reason?: string;
|
|
465
|
+
}
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
#### `StartScanOptions`
|
|
469
|
+
|
|
470
|
+
Optional tweaks for the iOS reader behavior.
|
|
471
|
+
|
|
472
|
+
```typescript
|
|
473
|
+
interface StartScanOptions {
|
|
474
|
+
mode?: 'auto' | 'full' | 'compat' | 'ndef';
|
|
475
|
+
forceFull?: boolean;
|
|
476
|
+
forceCompat?: boolean;
|
|
477
|
+
forceNDEF?: boolean;
|
|
478
|
+
}
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
#### `NDEFMessage`
|
|
482
|
+
|
|
483
|
+
An NDEF message consisting of one or more records.
|
|
484
|
+
|
|
485
|
+
```typescript
|
|
486
|
+
interface NDEFMessage {
|
|
487
|
+
records: NDEFRecord[];
|
|
488
|
+
}
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
#### `NDEFRecord`
|
|
492
|
+
|
|
493
|
+
An NDEF record. `payload` is, by default, an array of bytes representing the data; this is how an `NDEFRecord` is read from an NFC tag. You can choose to provide an `NDEFRecord` as a string a `Uint8Array` also.
|
|
494
|
+
|
|
495
|
+
```typescript
|
|
496
|
+
interface NDEFRecord<T = number[]> {
|
|
497
|
+
/**
|
|
498
|
+
* The type of the record.
|
|
499
|
+
*/
|
|
500
|
+
type: string;
|
|
501
|
+
|
|
502
|
+
/**
|
|
503
|
+
* The payload of the record.
|
|
504
|
+
*/
|
|
505
|
+
payload: T;
|
|
506
|
+
}
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
#### `NFCError`
|
|
510
|
+
|
|
511
|
+
An NFC error.
|
|
512
|
+
|
|
513
|
+
```typescript
|
|
514
|
+
interface NFCError {
|
|
515
|
+
/**
|
|
516
|
+
* The error message.
|
|
517
|
+
*/
|
|
518
|
+
error: string;
|
|
519
|
+
}
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
## Integration into a Capacitor App
|
|
523
|
+
|
|
524
|
+
To integrate this plugin into your Capacitor app:
|
|
525
|
+
|
|
526
|
+
1. **Install the plugin:**
|
|
527
|
+
|
|
528
|
+
```bash
|
|
529
|
+
npm install @exxili/capacitor-nfc
|
|
530
|
+
npx cap sync
|
|
531
|
+
```
|
|
532
|
+
|
|
533
|
+
2. **Import the plugin in your code:**
|
|
534
|
+
|
|
535
|
+
```typescript
|
|
536
|
+
import { NFC } from '@exxili/capacitor-nfc';
|
|
537
|
+
```
|
|
538
|
+
|
|
539
|
+
3. **Use the plugin methods as described in the [Usage](#usage) section.**
|
|
540
|
+
|
|
541
|
+
## Example
|
|
542
|
+
|
|
543
|
+
Here's a complete example of how to read and write NFC tags in your app:
|
|
544
|
+
|
|
545
|
+
```typescript
|
|
546
|
+
import { NFC, NDEFWriteOptions, NFCError, NDEFMessagesTransformable } from '@exxili/capacitor-nfc';
|
|
547
|
+
|
|
548
|
+
// Check if NFC is supported (optional gating logic)
|
|
549
|
+
const { supported } = await NFC.isSupported();
|
|
550
|
+
if (!supported) {
|
|
551
|
+
console.warn('NFC not supported on this device');
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
// Start NFC scanning (needed on iOS only)
|
|
555
|
+
NFC.startScan().catch((err) => console.error('Failed to start scan', err));
|
|
556
|
+
|
|
557
|
+
// Read listener returns a transformable wrapper
|
|
558
|
+
const offRead = NFC.onRead((data: NDEFMessagesTransformable) => {
|
|
559
|
+
const textView = data.string(); // NDEFMessages<string>
|
|
560
|
+
const rawBytesView = data.uint8Array(); // NDEFMessages<Uint8Array>
|
|
561
|
+
|
|
562
|
+
const firstText = textView.messages[0]?.records[0]?.payload;
|
|
563
|
+
const firstLength = rawBytesView.messages[0]?.records[0]?.payload.length;
|
|
564
|
+
console.log('First text record:', firstText);
|
|
565
|
+
console.log('First record byte length:', firstLength);
|
|
566
|
+
});
|
|
567
|
+
|
|
568
|
+
// Error listener (covers read & write errors)
|
|
569
|
+
const offError = NFC.onError((error: NFCError) => console.error('NFC Error:', error));
|
|
570
|
+
|
|
571
|
+
// Prepare an NDEF message to write (auto-formats Text/URI if payload is string)
|
|
572
|
+
const message: NDEFWriteOptions = {
|
|
573
|
+
records: [
|
|
574
|
+
{ type: 'T', payload: 'Hello, NFC!' },
|
|
575
|
+
{ type: 'U', payload: 'https://example.com' },
|
|
576
|
+
],
|
|
577
|
+
};
|
|
578
|
+
|
|
579
|
+
await NFC.writeNDEF(message).catch((err) => console.error('Write failed', err));
|
|
580
|
+
|
|
581
|
+
const offWrite = NFC.onWrite(() => console.log('Write success'));
|
|
582
|
+
|
|
583
|
+
// Later (cleanup)
|
|
584
|
+
offRead();
|
|
585
|
+
offError();
|
|
586
|
+
offWrite();
|
|
587
|
+
```
|
|
588
|
+
|
|
589
|
+
## License
|
|
590
|
+
|
|
591
|
+
[MIT License](https://opensource.org/license/mit)
|
|
592
|
+
|
|
593
|
+
---
|
|
594
|
+
|
|
595
|
+
**Support**: If you encounter any issues or have questions, feel free to open an issue.
|
|
596
|
+
|
|
597
|
+
---
|