@exxili/capacitor-nfc 0.0.2 → 0.0.9
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 -0
- package/README.md +96 -43
- package/android/build.gradle +11 -2
- package/android/src/main/kotlin/com/exxili/capacitornfc/MainActivity.kt +11 -0
- package/android/src/main/kotlin/com/exxili/capacitornfc/NFCPlugin.kt +315 -0
- package/dist/esm/definitions.d.ts +40 -12
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/index.d.ts +1 -2
- package/dist/esm/index.js +81 -2
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/web.d.ts +14 -0
- package/dist/esm/web.js +31 -0
- package/dist/esm/web.js.map +1 -0
- package/dist/plugin.cjs.js +116 -1
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +120 -5
- package/dist/plugin.js.map +1 -1
- package/ios/Sources/NFCPlugin/NFCPlugin.swift +28 -5
- package/ios/Sources/NFCPlugin/NFCReader.swift +1 -0
- package/package.json +2 -2
- package/android/src/main/java/com/exxili/capacitornfc/NFC.java +0 -11
- package/android/src/main/java/com/exxili/capacitornfc/NFCPlugin.java +0 -22
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
package com.exxili.capacitornfc
|
|
2
|
+
|
|
3
|
+
import android.app.PendingIntent
|
|
4
|
+
import android.content.Intent
|
|
5
|
+
import android.content.IntentFilter
|
|
6
|
+
import android.nfc.NdefMessage
|
|
7
|
+
import android.nfc.NdefRecord
|
|
8
|
+
import android.nfc.NfcAdapter
|
|
9
|
+
import android.nfc.NfcAdapter.ACTION_NDEF_DISCOVERED
|
|
10
|
+
import android.nfc.NfcAdapter.ACTION_TAG_DISCOVERED
|
|
11
|
+
import android.nfc.NfcAdapter.ACTION_TECH_DISCOVERED
|
|
12
|
+
import android.nfc.NfcAdapter.EXTRA_NDEF_MESSAGES
|
|
13
|
+
import android.nfc.NfcAdapter.getDefaultAdapter
|
|
14
|
+
import android.nfc.Tag
|
|
15
|
+
import android.nfc.tech.IsoDep
|
|
16
|
+
import android.nfc.tech.MifareClassic
|
|
17
|
+
import android.nfc.tech.MifareUltralight
|
|
18
|
+
import android.nfc.tech.Ndef
|
|
19
|
+
import android.nfc.tech.NdefFormatable
|
|
20
|
+
import android.nfc.tech.NfcA
|
|
21
|
+
import android.nfc.tech.NfcB
|
|
22
|
+
import android.nfc.tech.NfcBarcode
|
|
23
|
+
import android.nfc.tech.NfcF
|
|
24
|
+
import android.nfc.tech.NfcV
|
|
25
|
+
import android.util.Log
|
|
26
|
+
import com.getcapacitor.JSArray
|
|
27
|
+
import com.getcapacitor.JSObject
|
|
28
|
+
import com.getcapacitor.Plugin
|
|
29
|
+
import com.getcapacitor.PluginCall
|
|
30
|
+
import com.getcapacitor.PluginMethod
|
|
31
|
+
import com.getcapacitor.annotation.CapacitorPlugin
|
|
32
|
+
import org.json.JSONObject
|
|
33
|
+
import java.io.IOException
|
|
34
|
+
import java.io.UnsupportedEncodingException
|
|
35
|
+
import java.nio.charset.Charset
|
|
36
|
+
import java.util.Base64
|
|
37
|
+
|
|
38
|
+
@CapacitorPlugin(name = "NFC")
|
|
39
|
+
class NFCPlugin : Plugin() {
|
|
40
|
+
private var writeMode = false
|
|
41
|
+
private var recordsBuffer: JSArray? = null
|
|
42
|
+
|
|
43
|
+
private val techListsArray = arrayOf(arrayOf<String>(
|
|
44
|
+
IsoDep::class.java.name,
|
|
45
|
+
MifareClassic::class.java.name,
|
|
46
|
+
MifareUltralight::class.java.name,
|
|
47
|
+
Ndef::class.java.name,
|
|
48
|
+
NdefFormatable::class.java.name,
|
|
49
|
+
NfcBarcode::class.java.name,
|
|
50
|
+
NfcA::class.java.name,
|
|
51
|
+
NfcB::class.java.name,
|
|
52
|
+
NfcF::class.java.name,
|
|
53
|
+
NfcV::class.java.name
|
|
54
|
+
))
|
|
55
|
+
|
|
56
|
+
public override fun handleOnNewIntent(intent: Intent?) {
|
|
57
|
+
super.handleOnNewIntent(intent)
|
|
58
|
+
|
|
59
|
+
if (intent == null || intent.action.isNullOrBlank()) {
|
|
60
|
+
return
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (writeMode) {
|
|
64
|
+
Log.d("NFC", "WRITE MODE START")
|
|
65
|
+
handleWriteTag(intent)
|
|
66
|
+
writeMode = false
|
|
67
|
+
recordsBuffer = null
|
|
68
|
+
}
|
|
69
|
+
else if (ACTION_NDEF_DISCOVERED == intent.action) {
|
|
70
|
+
Log.d("NFC", "READ MODE START")
|
|
71
|
+
handleReadTag(intent)
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
@PluginMethod
|
|
76
|
+
fun isSupported(call: PluginCall) {
|
|
77
|
+
val adapter = NfcAdapter.getDefaultAdapter(this.activity)
|
|
78
|
+
val ret = JSObject()
|
|
79
|
+
ret.put("supported", adapter != null)
|
|
80
|
+
call.resolve(ret)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
@PluginMethod
|
|
84
|
+
fun cancelWriteAndroid(call: PluginCall) {
|
|
85
|
+
this.writeMode = false
|
|
86
|
+
call.resolve()
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
@PluginMethod
|
|
90
|
+
fun startScan(call: PluginCall) {
|
|
91
|
+
print("startScan called")
|
|
92
|
+
call.reject("Android NFC scanning does not require 'startScan' method.")
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
@PluginMethod
|
|
96
|
+
fun writeNDEF(call: PluginCall) {
|
|
97
|
+
print("writeNDEF called")
|
|
98
|
+
|
|
99
|
+
writeMode = true
|
|
100
|
+
recordsBuffer = call.getArray("records")
|
|
101
|
+
|
|
102
|
+
call.resolve()
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
override fun handleOnPause() {
|
|
106
|
+
super.handleOnPause()
|
|
107
|
+
getDefaultAdapter(this.activity)?.disableForegroundDispatch(this.activity)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
override fun handleOnResume() {
|
|
111
|
+
super.handleOnResume()
|
|
112
|
+
if(getDefaultAdapter(this.activity) == null) return;
|
|
113
|
+
|
|
114
|
+
val intent = Intent(context, this.activity.javaClass).apply {
|
|
115
|
+
addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
val pendingIntent =
|
|
119
|
+
PendingIntent.getActivity(this.activity, 0, intent, PendingIntent.FLAG_MUTABLE)
|
|
120
|
+
|
|
121
|
+
val intentFilter: Array<IntentFilter> =
|
|
122
|
+
arrayOf(
|
|
123
|
+
IntentFilter(ACTION_NDEF_DISCOVERED).apply {
|
|
124
|
+
try {
|
|
125
|
+
addDataType("text/plain")
|
|
126
|
+
} catch (e: IntentFilter.MalformedMimeTypeException) {
|
|
127
|
+
throw RuntimeException("failed", e)
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
IntentFilter(ACTION_TECH_DISCOVERED),
|
|
131
|
+
IntentFilter(ACTION_TAG_DISCOVERED)
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
getDefaultAdapter(this.activity).enableForegroundDispatch(
|
|
135
|
+
this.activity,
|
|
136
|
+
pendingIntent,
|
|
137
|
+
intentFilter,
|
|
138
|
+
techListsArray
|
|
139
|
+
)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
private fun handleWriteTag(intent: Intent) {
|
|
143
|
+
val records = recordsBuffer?.toList<JSONObject>()
|
|
144
|
+
if(records != null) {
|
|
145
|
+
val ndefRecords = mutableListOf<NdefRecord>()
|
|
146
|
+
|
|
147
|
+
try {
|
|
148
|
+
for (record in records) {
|
|
149
|
+
val payload = record.getJSONArray("payload")
|
|
150
|
+
val type: String? = record.getString("type")
|
|
151
|
+
|
|
152
|
+
if (payload.length() == 0 || type == null) {
|
|
153
|
+
notifyListeners(
|
|
154
|
+
"nfcError",
|
|
155
|
+
JSObject().put(
|
|
156
|
+
"error",
|
|
157
|
+
"Invalid record: payload or type is missing."
|
|
158
|
+
)
|
|
159
|
+
)
|
|
160
|
+
return
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
val typeBytes = type.toByteArray(Charsets.UTF_8)
|
|
164
|
+
val payloadBytes = ByteArray(payload.length())
|
|
165
|
+
for(i in 0 until payload.length()) {
|
|
166
|
+
payloadBytes[i] = payload.getInt(i).toByte()
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
ndefRecords.add(
|
|
170
|
+
NdefRecord(
|
|
171
|
+
NdefRecord.TNF_WELL_KNOWN,
|
|
172
|
+
typeBytes,
|
|
173
|
+
ByteArray(0),
|
|
174
|
+
payloadBytes
|
|
175
|
+
)
|
|
176
|
+
)
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
val ndefMessage = NdefMessage(ndefRecords.toTypedArray())
|
|
180
|
+
val tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG, Tag::class.java)
|
|
181
|
+
var ndef = Ndef.get(tag)
|
|
182
|
+
|
|
183
|
+
if (ndef == null) {
|
|
184
|
+
val formatable = NdefFormatable.get(tag)
|
|
185
|
+
if (formatable != null) {
|
|
186
|
+
try {
|
|
187
|
+
formatable.connect()
|
|
188
|
+
val mimeRecord = NdefRecord.createMime("text/plain", "INIT".toByteArray(
|
|
189
|
+
Charset.forName("US-ASCII")))
|
|
190
|
+
val msg = NdefMessage(mimeRecord)
|
|
191
|
+
formatable.format(msg)
|
|
192
|
+
// Success!
|
|
193
|
+
// Emit event to Capacitor plugin for success
|
|
194
|
+
println("Successfully formatted and wrote NDEF message to tag!")
|
|
195
|
+
} catch (e: IOException) {
|
|
196
|
+
// Error connecting or formatting
|
|
197
|
+
// Emit event to Capacitor plugin for error
|
|
198
|
+
println("Error formatting or writing to NDEF-formatable tag: ${e.message}")
|
|
199
|
+
} catch (e: Exception) { // Catch other potential exceptions during format, like TagLostException
|
|
200
|
+
println("Error during NDEF formatting: ${e.message}")
|
|
201
|
+
} finally {
|
|
202
|
+
try {
|
|
203
|
+
formatable.close()
|
|
204
|
+
} catch (e: IOException) {
|
|
205
|
+
println("Error closing NdefFormatable connection: ${e.message}")
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
ndef = Ndef.get(formatable.tag)
|
|
210
|
+
} else {
|
|
211
|
+
notifyListeners(
|
|
212
|
+
"nfcError",
|
|
213
|
+
JSObject().put(
|
|
214
|
+
"error",
|
|
215
|
+
"Tag does not support NDEF writing."
|
|
216
|
+
)
|
|
217
|
+
)
|
|
218
|
+
return
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
ndef.use { // Use block ensures ndef.close() is called
|
|
223
|
+
ndef.connect()
|
|
224
|
+
if (!ndef.isWritable) {
|
|
225
|
+
notifyListeners(
|
|
226
|
+
"nfcError",
|
|
227
|
+
JSObject().put(
|
|
228
|
+
"error",
|
|
229
|
+
"NFC tag is not writable"
|
|
230
|
+
)
|
|
231
|
+
)
|
|
232
|
+
return
|
|
233
|
+
}
|
|
234
|
+
if (ndef.maxSize < ndefMessage.toByteArray().size) {
|
|
235
|
+
notifyListeners(
|
|
236
|
+
"nfcError",
|
|
237
|
+
JSObject().put(
|
|
238
|
+
"error",
|
|
239
|
+
"Message too large for this NFC Tag (max ${ndef.maxSize} bytes)."
|
|
240
|
+
)
|
|
241
|
+
)
|
|
242
|
+
return
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
ndef.writeNdefMessage(ndefMessage)
|
|
246
|
+
Log.d("NFC", "NDEF message successfully written to tag.")
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
notifyListeners("nfcWriteSuccess", JSObject().put("success", true))
|
|
250
|
+
}
|
|
251
|
+
catch (e: UnsupportedEncodingException) {
|
|
252
|
+
Log.e("NFC", "Encoding error during NDEF record creation: ${e.message}")
|
|
253
|
+
notifyListeners(
|
|
254
|
+
"nfcError",
|
|
255
|
+
JSObject().put(
|
|
256
|
+
"error",
|
|
257
|
+
"Encoding error: ${e.message}"
|
|
258
|
+
)
|
|
259
|
+
)
|
|
260
|
+
}
|
|
261
|
+
catch (e: IOException) {
|
|
262
|
+
Log.e("NFC", "I/O error during NFC write: ${e.message}")
|
|
263
|
+
notifyListeners(
|
|
264
|
+
"nfcError",
|
|
265
|
+
JSObject().put(
|
|
266
|
+
"error",
|
|
267
|
+
"NFC I/O error: ${e.message}"
|
|
268
|
+
)
|
|
269
|
+
)
|
|
270
|
+
}
|
|
271
|
+
catch (e: Exception) {
|
|
272
|
+
Log.e("NFC", "Error writing NDEF message: ${e.message}", e)
|
|
273
|
+
notifyListeners(
|
|
274
|
+
"nfcError",
|
|
275
|
+
JSObject().put(
|
|
276
|
+
"error",
|
|
277
|
+
"Failed to write NDEF message: ${e.message}"
|
|
278
|
+
)
|
|
279
|
+
)
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
else {
|
|
283
|
+
notifyListeners("nfcError", JSObject().put("error", "Failed to write NFC tag"))
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
private fun handleReadTag(intent: Intent) {
|
|
288
|
+
val jsResponse = JSObject()
|
|
289
|
+
|
|
290
|
+
val ndefMessages = JSArray()
|
|
291
|
+
val receivedMessages = intent.getParcelableArrayExtra(
|
|
292
|
+
EXTRA_NDEF_MESSAGES,
|
|
293
|
+
NdefMessage::class.java
|
|
294
|
+
)
|
|
295
|
+
|
|
296
|
+
receivedMessages?.also { rawMessages ->
|
|
297
|
+
for (message in rawMessages) {
|
|
298
|
+
val ndefRecords = JSArray()
|
|
299
|
+
for (record in message.records) {
|
|
300
|
+
val rec = JSObject()
|
|
301
|
+
rec.put("type", String(record.type, Charsets.UTF_8))
|
|
302
|
+
rec.put("payload", Base64.getEncoder().encodeToString(record.payload))
|
|
303
|
+
ndefRecords.put(rec)
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
val msg = JSObject()
|
|
307
|
+
msg.put("records", ndefRecords)
|
|
308
|
+
ndefMessages.put(msg)
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
jsResponse.put("messages", ndefMessages)
|
|
313
|
+
this.notifyListeners("nfcTag", jsResponse)
|
|
314
|
+
}
|
|
315
|
+
}
|
|
@@ -1,20 +1,34 @@
|
|
|
1
|
-
import { PluginListenerHandle } from '@capacitor/core';
|
|
2
|
-
export
|
|
1
|
+
import type { PluginListenerHandle } from '@capacitor/core';
|
|
2
|
+
export declare type PayloadType = string | number[] | Uint8Array;
|
|
3
|
+
export interface NFCPluginBasic {
|
|
3
4
|
/**
|
|
4
|
-
*
|
|
5
|
+
* Checks if NFC is supported on the device. Returns true on all iOS devices, and checks for support on Android.
|
|
5
6
|
*/
|
|
7
|
+
isSupported(): Promise<{
|
|
8
|
+
supported: boolean;
|
|
9
|
+
}>;
|
|
6
10
|
startScan(): Promise<void>;
|
|
7
11
|
/**
|
|
8
12
|
* Writes an NDEF message to an NFC tag.
|
|
9
13
|
* @param options The NDEF message to write.
|
|
10
14
|
*/
|
|
11
|
-
writeNDEF(options: NDEFWriteOptions): Promise<void>;
|
|
15
|
+
writeNDEF<T extends PayloadType = number[]>(options: NDEFWriteOptions<T>): Promise<void>;
|
|
16
|
+
/**
|
|
17
|
+
* Cancels writeNDEF on Android (exits "write mode").
|
|
18
|
+
*/
|
|
19
|
+
cancelWriteAndroid(): Promise<void>;
|
|
12
20
|
/**
|
|
13
21
|
* Adds a listener for NFC tag detection events.
|
|
14
22
|
* @param eventName The name of the event ('nfcTag').
|
|
15
23
|
* @param listenerFunc The function to call when an NFC tag is detected.
|
|
16
24
|
*/
|
|
17
25
|
addListener(eventName: 'nfcTag', listenerFunc: (data: NDEFMessages) => void): Promise<PluginListenerHandle> & PluginListenerHandle;
|
|
26
|
+
/**
|
|
27
|
+
* Adds a listener for NFC tag write events.
|
|
28
|
+
* @param eventName The name of the event ('nfcWriteSuccess').
|
|
29
|
+
* @param listenerFunc The function to call when an NFC tag is written.
|
|
30
|
+
*/
|
|
31
|
+
addListener(eventName: 'nfcWriteSuccess', listenerFunc: () => void): Promise<PluginListenerHandle> & PluginListenerHandle;
|
|
18
32
|
/**
|
|
19
33
|
* Adds a listener for NFC error events.
|
|
20
34
|
* @param eventName The name of the event ('nfcError').
|
|
@@ -27,13 +41,13 @@ export interface NFCPlugin {
|
|
|
27
41
|
*/
|
|
28
42
|
removeAllListeners(eventName: 'nfcTag' | 'nfcError'): Promise<void>;
|
|
29
43
|
}
|
|
30
|
-
export interface NDEFMessages {
|
|
31
|
-
messages: NDEFMessage[];
|
|
44
|
+
export interface NDEFMessages<T extends PayloadType = string> {
|
|
45
|
+
messages: NDEFMessage<T>[];
|
|
32
46
|
}
|
|
33
|
-
export interface NDEFMessage {
|
|
34
|
-
records: NDEFRecord[];
|
|
47
|
+
export interface NDEFMessage<T extends PayloadType = string> {
|
|
48
|
+
records: NDEFRecord<T>[];
|
|
35
49
|
}
|
|
36
|
-
export interface NDEFRecord {
|
|
50
|
+
export interface NDEFRecord<T extends PayloadType = string> {
|
|
37
51
|
/**
|
|
38
52
|
* The type of the record.
|
|
39
53
|
*/
|
|
@@ -41,7 +55,7 @@ export interface NDEFRecord {
|
|
|
41
55
|
/**
|
|
42
56
|
* The payload of the record.
|
|
43
57
|
*/
|
|
44
|
-
payload:
|
|
58
|
+
payload: T;
|
|
45
59
|
}
|
|
46
60
|
export interface NFCError {
|
|
47
61
|
/**
|
|
@@ -49,6 +63,20 @@ export interface NFCError {
|
|
|
49
63
|
*/
|
|
50
64
|
error: string;
|
|
51
65
|
}
|
|
52
|
-
export interface NDEFWriteOptions {
|
|
53
|
-
records: NDEFRecord[];
|
|
66
|
+
export interface NDEFWriteOptions<T extends PayloadType = Uint8Array> {
|
|
67
|
+
records: NDEFRecord<T>[];
|
|
68
|
+
}
|
|
69
|
+
export declare type NDEFMessagesTransformable = {
|
|
70
|
+
base64: () => NDEFMessages;
|
|
71
|
+
uint8Array: () => NDEFMessages<Uint8Array>;
|
|
72
|
+
string: () => NDEFMessages;
|
|
73
|
+
numberArray: () => NDEFMessages<number[]>;
|
|
74
|
+
};
|
|
75
|
+
export declare type TagResultListenerFunc = (data: NDEFMessagesTransformable) => void;
|
|
76
|
+
export interface NFCPlugin extends Omit<NFCPluginBasic, "writeNDEF" | "addListener"> {
|
|
77
|
+
writeNDEF: <T extends PayloadType = Uint8Array>(record?: NDEFWriteOptions<T>) => Promise<void>;
|
|
78
|
+
wrapperListeners: TagResultListenerFunc[];
|
|
79
|
+
onRead: (listenerFunc: TagResultListenerFunc) => void;
|
|
80
|
+
onWrite: (listenerFunc: () => void) => void;
|
|
81
|
+
onError: (listenerFunc: (error: NFCError) => void) => void;
|
|
54
82
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"","sourcesContent":["import { PluginListenerHandle } from '@capacitor/core';\n\nexport interface
|
|
1
|
+
{"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"","sourcesContent":["import type { PluginListenerHandle } from '@capacitor/core';\n\n// Payload from a new NFC scan is a base64 encoded string\nexport type PayloadType = string | number[] | Uint8Array\n\nexport interface NFCPluginBasic {\n /**\n * Checks if NFC is supported on the device. Returns true on all iOS devices, and checks for support on Android.\n */\n isSupported(): Promise<{ supported: boolean }>;\n\n startScan(): Promise<void>;\n\n /**\n * Writes an NDEF message to an NFC tag.\n * @param options The NDEF message to write.\n */\n writeNDEF<T extends PayloadType = number[]>(options: NDEFWriteOptions<T>): Promise<void>;\n\n /**\n * Cancels writeNDEF on Android (exits \"write mode\").\n */\n cancelWriteAndroid(): Promise<void>;\n\n /**\n * Adds a listener for NFC tag detection events.\n * @param eventName The name of the event ('nfcTag').\n * @param listenerFunc The function to call when an NFC tag is detected.\n */\n addListener(\n eventName: 'nfcTag',\n listenerFunc: (data: NDEFMessages) => void,\n ): Promise<PluginListenerHandle> & PluginListenerHandle;\n\n /**\n * Adds a listener for NFC tag write events.\n * @param eventName The name of the event ('nfcWriteSuccess').\n * @param listenerFunc The function to call when an NFC tag is written.\n */\n addListener(\n eventName: 'nfcWriteSuccess',\n listenerFunc: ()=> void,\n ): Promise<PluginListenerHandle> & PluginListenerHandle;\n\n /**\n * Adds a listener for NFC error events.\n * @param eventName The name of the event ('nfcError').\n * @param listenerFunc The function to call when an NFC error occurs.\n */\n addListener(\n eventName: 'nfcError',\n listenerFunc: (error: NFCError) => void,\n ): Promise<PluginListenerHandle> & PluginListenerHandle;\n\n /**\n * Removes all listeners for the specified event.\n * @param eventName The name of the event.\n */\n removeAllListeners(eventName: 'nfcTag' | 'nfcError'): Promise<void>;\n}\n\nexport interface NDEFMessages<T extends PayloadType = string> {\n messages: NDEFMessage<T>[];\n}\n\nexport interface NDEFMessage<T extends PayloadType = string> {\n records: NDEFRecord<T>[];\n}\n\nexport interface NDEFRecord<T extends PayloadType = string> {\n /**\n * The type of the record.\n */\n type: string;\n\n /**\n * The payload of the record.\n */\n payload: T;\n}\n\n\nexport interface NFCError {\n /**\n * The error message.\n */\n error: string;\n}\n\nexport interface NDEFWriteOptions<T extends PayloadType = Uint8Array> {\n records: NDEFRecord<T>[];\n}\n\nexport type NDEFMessagesTransformable = {\n base64: ()=> NDEFMessages;\n uint8Array: ()=> NDEFMessages<Uint8Array>;\n string: ()=> NDEFMessages;\n numberArray: ()=> NDEFMessages<number[]>;\n}\n\nexport type TagResultListenerFunc = (data: NDEFMessagesTransformable) => void\n\nexport interface NFCPlugin extends Omit<NFCPluginBasic, \"writeNDEF\" | \"addListener\"> {\n writeNDEF: <T extends PayloadType = Uint8Array>(record?: NDEFWriteOptions<T>) => Promise<void>;\n wrapperListeners: TagResultListenerFunc[],\n onRead: (listenerFunc: TagResultListenerFunc)=> void,\n onWrite: (listenerFunc: ()=> void) => void,\n onError: (listenerFunc: (error: NFCError)=> void)=> void,\n}"]}
|
package/dist/esm/index.d.ts
CHANGED
package/dist/esm/index.js
CHANGED
|
@@ -1,5 +1,84 @@
|
|
|
1
1
|
import { registerPlugin } from '@capacitor/core';
|
|
2
|
-
const
|
|
2
|
+
const NFCPlug = registerPlugin('NFC', {
|
|
3
|
+
web: () => import('./web').then(m => new m.NFCWeb()),
|
|
4
|
+
});
|
|
3
5
|
export * from './definitions';
|
|
4
|
-
export
|
|
6
|
+
export const NFC = {
|
|
7
|
+
isSupported: NFCPlug.isSupported.bind(NFCPlug),
|
|
8
|
+
startScan: NFCPlug.startScan.bind(NFCPlug),
|
|
9
|
+
cancelWriteAndroid: NFCPlug.cancelWriteAndroid.bind(NFCPlug),
|
|
10
|
+
onRead: (func) => NFC.wrapperListeners.push(func),
|
|
11
|
+
onWrite: (func) => NFCPlug.addListener(`nfcWriteSuccess`, func),
|
|
12
|
+
onError: (errorFn) => {
|
|
13
|
+
NFCPlug.addListener(`nfcError`, errorFn);
|
|
14
|
+
},
|
|
15
|
+
removeAllListeners: (eventName) => {
|
|
16
|
+
NFC.wrapperListeners = [];
|
|
17
|
+
return NFCPlug.removeAllListeners(eventName);
|
|
18
|
+
},
|
|
19
|
+
wrapperListeners: [],
|
|
20
|
+
async writeNDEF(options) {
|
|
21
|
+
var _a;
|
|
22
|
+
const ndefMessage = {
|
|
23
|
+
records: (_a = options === null || options === void 0 ? void 0 : options.records.map((record) => {
|
|
24
|
+
const payload = typeof record.payload === 'string'
|
|
25
|
+
? Array.from(new TextEncoder().encode(record.payload))
|
|
26
|
+
: Array.isArray(record.payload)
|
|
27
|
+
? record.payload
|
|
28
|
+
: record.payload instanceof Uint8Array
|
|
29
|
+
? Array.from(record.payload)
|
|
30
|
+
: null;
|
|
31
|
+
if (!payload)
|
|
32
|
+
throw 'Unsupported payload type';
|
|
33
|
+
return {
|
|
34
|
+
type: record.type,
|
|
35
|
+
payload,
|
|
36
|
+
};
|
|
37
|
+
})) !== null && _a !== void 0 ? _a : [],
|
|
38
|
+
};
|
|
39
|
+
await NFCPlug.writeNDEF(ndefMessage);
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
const decodeBase64 = (base64Payload) => {
|
|
43
|
+
return atob(base64Payload)
|
|
44
|
+
.split('')
|
|
45
|
+
.map((char) => char.charCodeAt(0));
|
|
46
|
+
};
|
|
47
|
+
const mapPayloadTo = (type, data) => {
|
|
48
|
+
return {
|
|
49
|
+
messages: data.messages.map(message => ({
|
|
50
|
+
records: message.records.map(record => ({
|
|
51
|
+
type: record.type,
|
|
52
|
+
payload: type === "b64"
|
|
53
|
+
? record.payload
|
|
54
|
+
: type === "string"
|
|
55
|
+
? decodeBase64(record.payload)
|
|
56
|
+
: type === "uint8Array"
|
|
57
|
+
? new Uint8Array(decodeBase64(record.payload))
|
|
58
|
+
: type === "numberArray"
|
|
59
|
+
? Array.from(decodeBase64(record.payload))
|
|
60
|
+
: record.payload
|
|
61
|
+
}))
|
|
62
|
+
}))
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
NFCPlug.addListener(`nfcTag`, data => {
|
|
66
|
+
const wrappedData = {
|
|
67
|
+
base64() {
|
|
68
|
+
return mapPayloadTo("b64", data);
|
|
69
|
+
},
|
|
70
|
+
string() {
|
|
71
|
+
return mapPayloadTo("string", data);
|
|
72
|
+
},
|
|
73
|
+
uint8Array() {
|
|
74
|
+
return mapPayloadTo("uint8Array", data);
|
|
75
|
+
},
|
|
76
|
+
numberArray() {
|
|
77
|
+
return mapPayloadTo("numberArray", data);
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
for (const listener of NFC.wrapperListeners) {
|
|
81
|
+
listener(wrappedData);
|
|
82
|
+
}
|
|
83
|
+
});
|
|
5
84
|
//# sourceMappingURL=index.js.map
|
package/dist/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAajD,MAAM,OAAO,GAAG,cAAc,CAAiB,KAAK,EAAE;IACpD,GAAG,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC;CACrD,CAAC,CAAC;AACH,cAAc,eAAe,CAAC;AAC9B,MAAM,CAAC,MAAM,GAAG,GAAc;IAC5B,WAAW,EAAE,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC;IAC9C,SAAS,EAAE,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC;IAC1C,kBAAkB,EAAE,OAAO,CAAC,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC;IAC5D,MAAM,EAAE,CAAC,IAA2B,EAAE,EAAE,CAAC,GAAG,CAAC,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC;IACxE,OAAO,EAAE,CAAC,IAAe,EAAE,EAAE,CAAC,OAAO,CAAC,WAAW,CAAC,iBAAiB,EAAE,IAAI,CAAC;IAC1E,OAAO,EAAE,CAAC,OAAkC,EAAE,EAAE;QAC9C,OAAO,CAAC,WAAW,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IAC3C,CAAC;IACD,kBAAkB,EAAE,CAAC,SAAgC,EAAE,EAAE;QACvD,GAAG,CAAC,gBAAgB,GAAG,EAAE,CAAC;QAC1B,OAAO,OAAO,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC;IAC/C,CAAC;IACD,gBAAgB,EAAE,EAAE;IAEpB,KAAK,CAAC,SAAS,CAAqC,OAA6B;;QAC/E,MAAM,WAAW,GAA+B;YAC9C,OAAO,QACL,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;gBAC9B,MAAM,OAAO,GACX,OAAO,MAAM,CAAC,OAAO,KAAK,QAAQ;oBAChC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;oBACtD,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC;wBAC7B,CAAC,CAAC,MAAM,CAAC,OAAO;wBAChB,CAAC,CAAC,MAAM,CAAC,OAAO,YAAY,UAAU;4BACpC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC;4BAC5B,CAAC,CAAC,IAAI,CAAC;gBAEf,IAAI,CAAC,OAAO;oBAAE,MAAM,0BAA0B,CAAC;gBAE/C,OAAO;oBACL,IAAI,EAAE,MAAM,CAAC,IAAI;oBACjB,OAAO;iBACR,CAAC;YACJ,CAAC,oCAAK,EAAE;SACX,CAAC;QAEF,MAAM,OAAO,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;IACvC,CAAC;CACF,CAAC;AAIF,MAAM,YAAY,GAAG,CAAC,aAAqB,EAAC,EAAE;IAC5C,OAAO,IAAI,CAAC,aAAa,CAAC;SACvB,KAAK,CAAC,EAAE,CAAC;SACT,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;AACvC,CAAC,CAAA;AACD,MAAM,YAAY,GAAG,CAA4B,IAAO,EAAE,IAAkB,EAAkB,EAAE;IAC9F,OAAO;QACL,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YACtC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;gBACtC,IAAI,EAAE,MAAM,CAAC,IAAI;gBACjB,OAAO,EACL,IAAI,KAAK,KAAK;oBACZ,CAAC,CAAC,MAAM,CAAC,OAAO;oBAChB,CAAC,CAAA,IAAI,KAAK,QAAQ;wBAChB,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC,OAAO,CAAC;wBAC9B,CAAC,CAAC,IAAI,KAAK,YAAY;4BACrB,CAAC,CAAC,IAAI,UAAU,CAAC,YAAY,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;4BAC9C,CAAC,CAAC,IAAI,KAAK,aAAa;gCACtB,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;gCAC1C,CAAC,CAAC,MAAM,CAAC,OAAO;aAC3B,CAAC,CAAC;SACJ,CAAC,CAAC;KACc,CAAA;AACrB,CAAC,CAAA;AAED,OAAO,CAAC,WAAW,CAAC,QAAQ,EAAE,IAAI,CAAA,EAAE;IAClC,MAAM,WAAW,GAA8B;QAC7C,MAAM;YACJ,OAAO,YAAY,CAAC,KAAK,EAAE,IAAI,CAAC,CAAA;QAClC,CAAC;QACD,MAAM;YACJ,OAAO,YAAY,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAA;QACrC,CAAC;QACD,UAAU;YACR,OAAO,YAAY,CAAC,YAAY,EAAE,IAAI,CAAC,CAAA;QACzC,CAAC;QACD,WAAW;YACT,OAAO,YAAY,CAAC,aAAa,EAAE,IAAI,CAAC,CAAA;QAC1C,CAAC;KACF,CAAA;IAED,KAAI,MAAM,QAAQ,IAAI,GAAG,CAAC,gBAAgB,EAAE;QAC1C,QAAQ,CAAC,WAAW,CAAC,CAAC;KACvB;AACH,CAAC,CAAC,CAAA","sourcesContent":["import { registerPlugin } from '@capacitor/core';\n\nimport type {\n NDEFMessagesTransformable,\n NDEFWriteOptions,\n NFCPlugin,\n NFCPluginBasic,\n PayloadType,\n TagResultListenerFunc,\n NFCError,\n NDEFMessages\n} from './definitions';\n\nconst NFCPlug = registerPlugin<NFCPluginBasic>('NFC', {\n web: () => import('./web').then(m => new m.NFCWeb()),\n});\nexport * from './definitions';\nexport const NFC: NFCPlugin = {\n isSupported: NFCPlug.isSupported.bind(NFCPlug),\n startScan: NFCPlug.startScan.bind(NFCPlug),\n cancelWriteAndroid: NFCPlug.cancelWriteAndroid.bind(NFCPlug),\n onRead: (func: TagResultListenerFunc) => NFC.wrapperListeners.push(func),\n onWrite: (func: ()=> void) => NFCPlug.addListener(`nfcWriteSuccess`, func),\n onError: (errorFn: (error: NFCError) => void) => {\n NFCPlug.addListener(`nfcError`, errorFn);\n },\n removeAllListeners: (eventName: 'nfcTag' | 'nfcError') => {\n NFC.wrapperListeners = [];\n return NFCPlug.removeAllListeners(eventName);\n },\n wrapperListeners: [],\n\n async writeNDEF<T extends PayloadType = Uint8Array>(options?: NDEFWriteOptions<T>): Promise<void> {\n const ndefMessage: NDEFWriteOptions<number[]> = {\n records:\n options?.records.map((record) => {\n const payload: number[] | null =\n typeof record.payload === 'string'\n ? Array.from(new TextEncoder().encode(record.payload))\n : Array.isArray(record.payload)\n ? record.payload\n : record.payload instanceof Uint8Array\n ? Array.from(record.payload)\n : null;\n\n if (!payload) throw 'Unsupported payload type';\n\n return {\n type: record.type,\n payload,\n };\n }) ?? [],\n };\n\n await NFCPlug.writeNDEF(ndefMessage);\n },\n};\n\ntype DecodeSpecifier = \"b64\" | \"string\" | \"uint8Array\" | \"numberArray\";\ntype decodedType<T extends DecodeSpecifier> = NDEFMessages<T extends \"b64\" ? string : T extends \"string\" ? string : T extends \"uint8Array\" ? Uint8Array : number[]>\nconst decodeBase64 = (base64Payload: string)=> {\n return atob(base64Payload)\n .split('')\n .map((char) => char.charCodeAt(0));\n}\nconst mapPayloadTo = <T extends DecodeSpecifier>(type: T, data: NDEFMessages): decodedType<T> => {\n return {\n messages: data.messages.map(message => ({\n records: message.records.map(record => ({\n type: record.type,\n payload:\n type === \"b64\"\n ? record.payload\n :type === \"string\"\n ? decodeBase64(record.payload)\n : type === \"uint8Array\"\n ? new Uint8Array(decodeBase64(record.payload))\n : type === \"numberArray\"\n ? Array.from(decodeBase64(record.payload))\n : record.payload\n }))\n }))\n } as decodedType<T>\n}\n\nNFCPlug.addListener(`nfcTag`, data=> {\n const wrappedData: NDEFMessagesTransformable = {\n base64() {\n return mapPayloadTo(\"b64\", data)\n },\n string() {\n return mapPayloadTo(\"string\", data)\n },\n uint8Array() {\n return mapPayloadTo(\"uint8Array\", data)\n },\n numberArray() {\n return mapPayloadTo(\"numberArray\", data)\n }\n }\n\n for(const listener of NFC.wrapperListeners) {\n listener(wrappedData);\n }\n})"]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { WebPlugin } from '@capacitor/core';
|
|
2
|
+
import type { NFCPlugin, TagResultListenerFunc } from './definitions';
|
|
3
|
+
export declare class NFCWeb extends WebPlugin implements NFCPlugin {
|
|
4
|
+
wrapperListeners: never[];
|
|
5
|
+
isSupported(): Promise<{
|
|
6
|
+
supported: boolean;
|
|
7
|
+
}>;
|
|
8
|
+
startScan(): Promise<void>;
|
|
9
|
+
cancelWriteAndroid(): Promise<void>;
|
|
10
|
+
writeNDEF(): Promise<void>;
|
|
11
|
+
onRead(_func: TagResultListenerFunc): Promise<void>;
|
|
12
|
+
onWrite(): Promise<void>;
|
|
13
|
+
onError(_errorFn: (error: any) => void): Promise<void>;
|
|
14
|
+
}
|
package/dist/esm/web.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { WebPlugin } from '@capacitor/core';
|
|
2
|
+
export class NFCWeb extends WebPlugin {
|
|
3
|
+
constructor() {
|
|
4
|
+
super(...arguments);
|
|
5
|
+
this.wrapperListeners = [];
|
|
6
|
+
}
|
|
7
|
+
isSupported() {
|
|
8
|
+
return Promise.resolve({ supported: false });
|
|
9
|
+
}
|
|
10
|
+
startScan() {
|
|
11
|
+
return Promise.reject(new Error('NFC is not supported on web'));
|
|
12
|
+
}
|
|
13
|
+
cancelWriteAndroid() {
|
|
14
|
+
return Promise.reject(new Error('NFC is not supported on web'));
|
|
15
|
+
}
|
|
16
|
+
writeNDEF() {
|
|
17
|
+
return Promise.reject(new Error('NFC is not supported on web'));
|
|
18
|
+
}
|
|
19
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
20
|
+
onRead(_func) {
|
|
21
|
+
return Promise.reject(new Error('NFC is not supported on web'));
|
|
22
|
+
}
|
|
23
|
+
onWrite() {
|
|
24
|
+
return Promise.reject(new Error('NFC is not supported on web'));
|
|
25
|
+
}
|
|
26
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
27
|
+
onError(_errorFn) {
|
|
28
|
+
return Promise.reject(new Error('NFC is not supported on web'));
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=web.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAI5C,MAAM,OAAO,MAAO,SAAQ,SAAS;IAArC;;QACE,qBAAgB,GAAG,EAAE,CAAC;IA+BxB,CAAC;IA7BC,WAAW;QACT,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;IAC/C,CAAC;IAED,SAAS;QACP,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC,CAAC;IAClE,CAAC;IAED,kBAAkB;QAChB,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC,CAAC;IAClE,CAAC;IAED,SAAS;QACP,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC,CAAC;IAClE,CAAC;IAED,6DAA6D;IAC7D,MAAM,CAAC,KAA4B;QACjC,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC,CAAC;IAClE,CAAC;IAED,OAAO;QACL,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC,CAAC;IAClE,CAAC;IAED,6DAA6D;IAC7D,OAAO,CAAC,QAA8B;QACpC,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC,CAAC;IAClE,CAAC;CACF","sourcesContent":["import { WebPlugin } from '@capacitor/core';\n\nimport type { NFCPlugin, TagResultListenerFunc } from './definitions';\n\nexport class NFCWeb extends WebPlugin implements NFCPlugin {\n wrapperListeners = [];\n \n isSupported(): Promise<{ supported: boolean }> {\n return Promise.resolve({ supported: false });\n }\n\n startScan(): Promise<void> {\n return Promise.reject(new Error('NFC is not supported on web'));\n }\n\n cancelWriteAndroid(): Promise<void> {\n return Promise.reject(new Error('NFC is not supported on web'));\n }\n\n writeNDEF(): Promise<void> {\n return Promise.reject(new Error('NFC is not supported on web'));\n }\n \n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n onRead(_func: TagResultListenerFunc): Promise<void> {\n return Promise.reject(new Error('NFC is not supported on web'));\n }\n\n onWrite(): Promise<void> {\n return Promise.reject(new Error('NFC is not supported on web'));\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n onError(_errorFn: (error: any) => void): Promise<void> {\n return Promise.reject(new Error('NFC is not supported on web'));\n }\n}"]}
|