@iotize/device-com-nfc.cordova 3.7.0 → 3.7.1

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.
@@ -1,911 +1,911 @@
1
- /*jshint bitwise: false, camelcase: false, quotmark: false, unused: vars, esversion: 6, browser: true*/
2
- /*global cordova, console, require */
3
-
4
- function handleNfcFromIntentFilter() {
5
-
6
- // This was historically done in cordova.addConstructor but broke with PhoneGap-2.2.0.
7
- // We need to handle NFC from an Intent that launched the application, but *after*
8
- // the code in the application's deviceready has run. After upgrading to 2.2.0,
9
- // addConstructor was finishing *before* deviceReady was complete and the
10
- // ndef listeners had not been registered.
11
- // It seems like there should be a better solution.
12
- if (cordova.platformId === "android" || cordova.platformId === "windows") {
13
- setTimeout(
14
- function () {
15
- cordova.exec(
16
- function () {
17
- console.log("Initialized the NfcPlugin");
18
- },
19
- function (reason) {
20
- console.log("Failed to initialize the NfcPlugin " + reason);
21
- },
22
- "NfcPlugin", "init", []
23
- );
24
- }, 10
25
- );
26
- }
27
- }
28
-
29
- document.addEventListener('deviceready', handleNfcFromIntentFilter, false);
30
-
31
- var ndef = {
32
-
33
- // see android.nfc.NdefRecord for documentation about constants
34
- // http://developer.android.com/reference/android/nfc/NdefRecord.html
35
- TNF_EMPTY: 0x0,
36
- TNF_WELL_KNOWN: 0x01,
37
- TNF_MIME_MEDIA: 0x02,
38
- TNF_ABSOLUTE_URI: 0x03,
39
- TNF_EXTERNAL_TYPE: 0x04,
40
- TNF_UNKNOWN: 0x05,
41
- TNF_UNCHANGED: 0x06,
42
- TNF_RESERVED: 0x07,
43
-
44
- RTD_TEXT: [0x54], // "T"
45
- RTD_URI: [0x55], // "U"
46
- RTD_SMART_POSTER: [0x53, 0x70], // "Sp"
47
- RTD_ALTERNATIVE_CARRIER: [0x61, 0x63], // "ac"
48
- RTD_HANDOVER_CARRIER: [0x48, 0x63], // "Hc"
49
- RTD_HANDOVER_REQUEST: [0x48, 0x72], // "Hr"
50
- RTD_HANDOVER_SELECT: [0x48, 0x73], // "Hs"
51
-
52
- /**
53
- * Creates a JSON representation of a NDEF Record.
54
- *
55
- * @tnf 3-bit TNF (Type Name Format) - use one of the TNF_* constants
56
- * @type byte array, containing zero to 255 bytes, must not be null
57
- * @id byte array, containing zero to 255 bytes, must not be null
58
- * @payload byte array, containing zero to (2 ** 32 - 1) bytes, must not be null
59
- *
60
- * @returns JSON representation of a NDEF record
61
- *
62
- * @see Ndef.textRecord, Ndef.uriRecord and Ndef.mimeMediaRecord for examples
63
- */
64
- record: function (tnf, type, id, payload) {
65
-
66
- // handle null values
67
- if (!tnf) { tnf = ndef.TNF_EMPTY; }
68
- if (!type) { type = []; }
69
- if (!id) { id = []; }
70
- if (!payload) { payload = []; }
71
-
72
- // convert strings to arrays
73
- if (!(type instanceof Array)) {
74
- type = nfc.stringToBytes(type);
75
- }
76
- if (!(id instanceof Array)) {
77
- id = nfc.stringToBytes(id);
78
- }
79
- if (!(payload instanceof Array)) {
80
- payload = nfc.stringToBytes(payload);
81
- }
82
-
83
- return {
84
- tnf: tnf,
85
- type: type,
86
- id: id,
87
- payload: payload
88
- };
89
- },
90
-
91
- /**
92
- * Helper that creates an NDEF record containing plain text.
93
- *
94
- * @text String of text to encode
95
- * @languageCode ISO/IANA language code. Examples: “fi”, “en-US”, “fr- CA”, “jp”. (optional)
96
- * @id byte[] (optional)
97
- */
98
- textRecord: function (text, languageCode, id) {
99
- var payload = textHelper.encodePayload(text, languageCode);
100
- if (!id) { id = []; }
101
- return ndef.record(ndef.TNF_WELL_KNOWN, ndef.RTD_TEXT, id, payload);
102
- },
103
-
104
- /**
105
- * Helper that creates a NDEF record containing a URI.
106
- *
107
- * @uri String
108
- * @id byte[] (optional)
109
- */
110
- uriRecord: function (uri, id) {
111
- var payload = uriHelper.encodePayload(uri);
112
- if (!id) { id = []; }
113
- return ndef.record(ndef.TNF_WELL_KNOWN, ndef.RTD_URI, id, payload);
114
- },
115
-
116
- /**
117
- * Helper that creates a NDEF record containing an absolute URI.
118
- *
119
- * An Absolute URI record means the URI describes the payload of the record.
120
- *
121
- * For example a SOAP message could use "http://schemas.xmlsoap.org/soap/envelope/"
122
- * as the type and XML content for the payload.
123
- *
124
- * Absolute URI can also be used to write LaunchApp records for Windows.
125
- *
126
- * See 2.4.2 Payload Type of the NDEF Specification
127
- * http://www.nfc-forum.org/specs/spec_list#ndefts
128
- *
129
- * Note that by default, Android will open the URI defined in the type
130
- * field of an Absolute URI record (TNF=3) and ignore the payload.
131
- * BlackBerry and Windows do not open the browser for TNF=3.
132
- *
133
- * To write a URI as the payload use ndef.uriRecord(uri)
134
- *
135
- * @uri String
136
- * @payload byte[] or String
137
- * @id byte[] (optional)
138
- */
139
- absoluteUriRecord: function (uri, payload, id) {
140
- if (!id) { id = []; }
141
- if (!payload) { payload = []; }
142
- return ndef.record(ndef.TNF_ABSOLUTE_URI, uri, id, payload);
143
- },
144
-
145
- /**
146
- * Helper that creates a NDEF record containing an mimeMediaRecord.
147
- *
148
- * @mimeType String
149
- * @payload byte[]
150
- * @id byte[] (optional)
151
- */
152
- mimeMediaRecord: function (mimeType, payload, id) {
153
- if (!id) { id = []; }
154
- return ndef.record(ndef.TNF_MIME_MEDIA, nfc.stringToBytes(mimeType), id, payload);
155
- },
156
-
157
- /**
158
- * Helper that creates an NDEF record containing an Smart Poster.
159
- *
160
- * @ndefRecords array of NDEF Records
161
- * @id byte[] (optional)
162
- */
163
- smartPoster: function (ndefRecords, id) {
164
- var payload = [];
165
-
166
- if (!id) { id = []; }
167
-
168
- if (ndefRecords)
169
- {
170
- // make sure we have an array of something like NDEF records before encoding
171
- if (ndefRecords[0] instanceof Object && ndefRecords[0].hasOwnProperty('tnf')) {
172
- payload = ndef.encodeMessage(ndefRecords);
173
- } else {
174
- // assume the caller has already encoded the NDEF records into a byte array
175
- payload = ndefRecords;
176
- }
177
- } else {
178
- console.log("WARNING: Expecting an array of NDEF records");
179
- }
180
-
181
- return ndef.record(ndef.TNF_WELL_KNOWN, ndef.RTD_SMART_POSTER, id, payload);
182
- },
183
-
184
- /**
185
- * Helper that creates an empty NDEF record.
186
- *
187
- */
188
- emptyRecord: function() {
189
- return ndef.record(ndef.TNF_EMPTY, [], [], []);
190
- },
191
-
192
- /**
193
- * Helper that creates an Android Application Record (AAR).
194
- * http://developer.android.com/guide/topics/connectivity/nfc/nfc.html#aar
195
- *
196
- */
197
- androidApplicationRecord: function(packageName) {
198
- return ndef.record(ndef.TNF_EXTERNAL_TYPE, "android.com:pkg", [], packageName);
199
- },
200
-
201
- /**
202
- * Encodes an NDEF Message into bytes that can be written to a NFC tag.
203
- *
204
- * @ndefRecords an Array of NDEF Records
205
- *
206
- * @returns byte array
207
- *
208
- * @see NFC Data Exchange Format (NDEF) http://www.nfc-forum.org/specs/spec_list/
209
- */
210
- encodeMessage: function (ndefRecords) {
211
-
212
- var encoded = [],
213
- tnf_byte,
214
- type_length,
215
- payload_length,
216
- id_length,
217
- i,
218
- mb, me, // messageBegin, messageEnd
219
- cf = false, // chunkFlag TODO implement
220
- sr, // boolean shortRecord
221
- il; // boolean idLengthFieldIsPresent
222
-
223
- for(i = 0; i < ndefRecords.length; i++) {
224
-
225
- mb = (i === 0);
226
- me = (i === (ndefRecords.length - 1));
227
- sr = (ndefRecords[i].payload.length < 0xFF);
228
- il = (ndefRecords[i].id.length > 0);
229
- tnf_byte = ndef.encodeTnf(mb, me, cf, sr, il, ndefRecords[i].tnf);
230
- encoded.push(tnf_byte);
231
-
232
- type_length = ndefRecords[i].type.length;
233
- encoded.push(type_length);
234
-
235
- if (sr) {
236
- payload_length = ndefRecords[i].payload.length;
237
- encoded.push(payload_length);
238
- } else {
239
- payload_length = ndefRecords[i].payload.length;
240
- // 4 bytes
241
- encoded.push((payload_length >> 24));
242
- encoded.push((payload_length >> 16));
243
- encoded.push((payload_length >> 8));
244
- encoded.push((payload_length & 0xFF));
245
- }
246
-
247
- if (il) {
248
- id_length = ndefRecords[i].id.length;
249
- encoded.push(id_length);
250
- }
251
-
252
- encoded = encoded.concat(ndefRecords[i].type);
253
-
254
- if (il) {
255
- encoded = encoded.concat(ndefRecords[i].id);
256
- }
257
-
258
- encoded = encoded.concat(ndefRecords[i].payload);
259
- }
260
-
261
- return encoded;
262
- },
263
-
264
- /**
265
- * Decodes an array bytes into an NDEF Message
266
- *
267
- * @bytes an array bytes read from a NFC tag
268
- *
269
- * @returns array of NDEF Records
270
- *
271
- * @see NFC Data Exchange Format (NDEF) http://www.nfc-forum.org/specs/spec_list/
272
- */
273
- decodeMessage: function (ndefBytes) {
274
-
275
- var bytes = ndefBytes.slice(0), // clone since parsing is destructive
276
- ndef_message = [],
277
- tnf_byte,
278
- header,
279
- type_length = 0,
280
- payload_length = 0,
281
- id_length = 0,
282
- record_type = [],
283
- id = [],
284
- payload = [];
285
-
286
- while(bytes.length) {
287
- tnf_byte = bytes.shift();
288
- header = ndef.decodeTnf(tnf_byte);
289
-
290
- type_length = bytes.shift();
291
-
292
- if (header.sr) {
293
- payload_length = bytes.shift();
294
- } else {
295
- // next 4 bytes are length
296
- payload_length = ((0xFF & bytes.shift()) << 24) |
297
- ((0xFF & bytes.shift()) << 26) |
298
- ((0xFF & bytes.shift()) << 8) |
299
- (0xFF & bytes.shift());
300
- }
301
-
302
- if (header.il) {
303
- id_length = bytes.shift();
304
- }
305
-
306
- record_type = bytes.splice(0, type_length);
307
- id = bytes.splice(0, id_length);
308
- payload = bytes.splice(0, payload_length);
309
-
310
- ndef_message.push(
311
- ndef.record(header.tnf, record_type, id, payload)
312
- );
313
-
314
- if (header.me) { break; } // last message
315
- }
316
-
317
- return ndef_message;
318
- },
319
-
320
- /**
321
- * Decode the bit flags from a TNF Byte.
322
- *
323
- * @returns object with decoded data
324
- *
325
- * See NFC Data Exchange Format (NDEF) Specification Section 3.2 RecordLayout
326
- */
327
- decodeTnf: function (tnf_byte) {
328
- return {
329
- mb: (tnf_byte & 0x80) !== 0,
330
- me: (tnf_byte & 0x40) !== 0,
331
- cf: (tnf_byte & 0x20) !== 0,
332
- sr: (tnf_byte & 0x10) !== 0,
333
- il: (tnf_byte & 0x8) !== 0,
334
- tnf: (tnf_byte & 0x7)
335
- };
336
- },
337
-
338
- /**
339
- * Encode NDEF bit flags into a TNF Byte.
340
- *
341
- * @returns tnf byte
342
- *
343
- * See NFC Data Exchange Format (NDEF) Specification Section 3.2 RecordLayout
344
- */
345
- encodeTnf: function (mb, me, cf, sr, il, tnf) {
346
-
347
- var value = tnf;
348
-
349
- if (mb) {
350
- value = value | 0x80;
351
- }
352
-
353
- if (me) {
354
- value = value | 0x40;
355
- }
356
-
357
- // note if cf: me, mb, li must be false and tnf must be 0x6
358
- if (cf) {
359
- value = value | 0x20;
360
- }
361
-
362
- if (sr) {
363
- value = value | 0x10;
364
- }
365
-
366
- if (il) {
367
- value = value | 0x8;
368
- }
369
-
370
- return value;
371
- },
372
-
373
- /**
374
- * Convert TNF to String for user friendly display
375
- *
376
- */
377
- tnfToString: function (tnf) {
378
- var value = tnf;
379
-
380
- switch (tnf) {
381
- case ndef.TNF_EMPTY:
382
- value = "Empty";
383
- break;
384
- case ndef.TNF_WELL_KNOWN:
385
- value = "Well Known";
386
- break;
387
- case ndef.TNF_MIME_MEDIA:
388
- value = "Mime Media";
389
- break;
390
- case ndef.TNF_ABSOLUTE_URI:
391
- value = "Absolute URI";
392
- break;
393
- case ndef.TNF_EXTERNAL_TYPE:
394
- value = "External";
395
- break;
396
- case ndef.TNF_UNKNOWN:
397
- value = "Unknown";
398
- break;
399
- case ndef.TNF_UNCHANGED:
400
- value = "Unchanged";
401
- break;
402
- case ndef.TNF_RESERVED:
403
- value = "Reserved";
404
- break;
405
- }
406
- return value;
407
- }
408
-
409
- };
410
-
411
- // nfc provides javascript wrappers to the native phonegap implementation
412
- var nfc = {
413
-
414
- addTagDiscoveredListener: function (callback, win, fail) {
415
- document.addEventListener("tag", callback, false);
416
- cordova.exec(win, fail, "NfcPlugin", "registerTag", []);
417
- },
418
-
419
- addMimeTypeListener: function (mimeType, callback, win, fail) {
420
- document.addEventListener("ndef-mime", callback, false);
421
- cordova.exec(win, fail, "NfcPlugin", "registerMimeType", [mimeType]);
422
- },
423
-
424
- addNdefListener: function (callback, win, fail) {
425
- document.addEventListener("ndef", callback, false);
426
- cordova.exec(win, fail, "NfcPlugin", "registerNdef", []);
427
- },
428
-
429
- addTapDeviceListener: function (callback, win, fail) {
430
- document.addEventListener("nfc-tap-device", callback, false);
431
- win();
432
- // cordova.exec(win, fail, "NfcPlugin", "registerTapDevice", [
433
- // JSON.stringify(options)
434
- // ]);
435
- },
436
-
437
- addNdefFormatableListener: function (callback, win, fail) {
438
- document.addEventListener("ndef-formatable", callback, false);
439
- cordova.exec(win, fail, "NfcPlugin", "registerNdefFormatable", []);
440
- },
441
-
442
- write: function (ndefMessage, win, fail) {
443
- cordova.exec(win, fail, "NfcPlugin", "writeTag", [ndefMessage]);
444
- },
445
-
446
- erase: function (win, fail) {
447
- cordova.exec(win, fail, "NfcPlugin", "eraseTag", [[]]);
448
- },
449
-
450
- enabled: function (win, fail) {
451
- cordova.exec(win, fail, "NfcPlugin", "enabled", [[]]);
452
- },
453
-
454
- removeTagDiscoveredListener: function (callback, win, fail) {
455
- document.removeEventListener("tag", callback, false);
456
- cordova.exec(win, fail, "NfcPlugin", "removeTag", []);
457
- },
458
-
459
- removeMimeTypeListener: function(mimeType, callback, win, fail) {
460
- document.removeEventListener("ndef-mime", callback, false);
461
- cordova.exec(win, fail, "NfcPlugin", "removeMimeType", [mimeType]);
462
- },
463
-
464
- removeNdefListener: function (callback, win, fail) {
465
- document.removeEventListener("ndef", callback, false);
466
- cordova.exec(win, fail, "NfcPlugin", "removeNdef", []);
467
- },
468
-
469
- showSettings: function (win, fail) {
470
- cordova.exec(win, fail, "NfcPlugin", "showSettings", []);
471
- },
472
-
473
- // iOS only
474
-
475
- beginNDEFSession: function (win, fail) {
476
- cordova.exec(win, fail, "NfcPlugin", "beginNDEFSession", []);
477
- },
478
-
479
- // iOS only
480
-
481
- invalidateNDEFSession: function (win, fail) {
482
- cordova.exec(win, fail, 'NfcPlugin', 'invalidateNDEFSession', []);
483
- },
484
-
485
- connect: function(tech, timeout) {
486
- return new Promise(function(resolve, reject) {
487
- cordova.exec(resolve, reject, 'NfcPlugin', 'connect', [tech, timeout]);
488
- });
489
- },
490
-
491
-
492
- connectRaw: function(tech, timeout) {
493
- return new Promise(function(resolve, reject) {
494
- cordova.exec(resolve, reject, 'NfcPlugin', 'connectRaw', [tech, timeout]);
495
- });
496
- },
497
-
498
- close: function() {
499
- return new Promise(function(resolve, reject) {
500
- cordova.exec(resolve, reject, 'NfcPlugin', 'close', []);
501
- });
502
- },
503
-
504
- // data - ArrayBuffer or string of hex data for transcieve
505
- // the results of transcieve are returned in the promise success as an ArrayBuffer
506
- transceiveTap: function(data) {
507
- return new Promise(function(resolve, reject) {
508
-
509
- var buffer;
510
- if (typeof data === 'string') {
511
- buffer = util.hexStringToArrayBuffer(data);
512
- } else if (data instanceof ArrayBuffer) {
513
- buffer = data;
514
- } else if (data instanceof Uint8Array) {
515
- buffer = data.buffer;
516
- } else {
517
- reject("Expecting an ArrayBuffer or String");
518
- }
519
-
520
- cordova.exec(resolve, reject, 'NfcPlugin', 'transceiveTap', [buffer]);
521
- });
522
- },
523
-
524
- // data - ArrayBuffer or string of hex data for transcieve
525
- // the results of transcieve are returned in the promise success as an ArrayBuffer
526
- transceive: function(data) {
527
- return new Promise(function(resolve, reject) {
528
-
529
- var buffer;
530
- if (typeof data === 'string') {
531
- buffer = util.hexStringToArrayBuffer(data);
532
- } else if (data instanceof ArrayBuffer) {
533
- buffer = data;
534
- } else if (data instanceof Uint8Array) {
535
- buffer = data.buffer;
536
- } else {
537
- reject("Expecting an ArrayBuffer or String");
538
- }
539
-
540
- cordova.exec(resolve, reject, 'NfcPlugin', 'transceive', [buffer]);
541
- });
542
- },
543
-
544
- // // Android NfcAdapter.enableReaderMode flags
545
- // FLAG_READER_NFC_A: 0x1,
546
- // FLAG_READER_NFC_B: 0x2,
547
- // FLAG_READER_NFC_F: 0x4,
548
- // FLAG_READER_NFC_V: 0x8,
549
- // FLAG_READER_NFC_BARCODE: 0x10,
550
- // FLAG_READER_SKIP_NDEF_CHECK: 0x80,
551
- // FLAG_READER_NO_PLATFORM_SOUNDS: 0x100,
552
-
553
- // // Android NfcAdapter.enabledReaderMode
554
- readerMode: function(flags, readCallback, errorCallback) {
555
- cordova.exec(readCallback, errorCallback, 'NfcPlugin', 'readerMode', [flags]);
556
- },
557
-
558
- disableReaderMode: function(successCallback, errorCallback) {
559
- cordova.exec(successCallback, errorCallback, 'NfcPlugin', 'disableReaderMode', []);
560
- },
561
-
562
- setTapDeviceDiscoveryEnabled: function(enabled) {
563
- return new Promise(function(resolve, reject) {
564
- cordova.exec(resolve, reject, 'NfcPlugin', 'setTapDeviceDiscoveryEnabled', [!!enabled]);
565
- });
566
- },
567
-
568
- beginSessionFromTech: function(tech, alertMessage = undefined) {
569
- const args = [tech];
570
- if (alertMessage) {
571
- args.push(alertMessage);
572
- }
573
- return new Promise(function(resolve, reject) {
574
- cordova.exec(resolve, reject, 'NfcPlugin', 'beginSessionFromTech', args);
575
- });
576
- },
577
-
578
- endSession: function() {
579
- return new Promise(function(resolve, reject) {
580
- cordova.exec(resolve,reject, 'NfcPlugin', 'endSession', []);
581
- })
582
- }
583
-
584
-
585
- };
586
-
587
- var util = {
588
- // i must be <= 256
589
- toHex: function (i) {
590
- var hex;
591
-
592
- if (i < 0) {
593
- i += 256;
594
- }
595
-
596
- hex = i.toString(16);
597
-
598
- // zero padding
599
- if (hex.length === 1) {
600
- hex = "0" + hex;
601
- }
602
-
603
- return hex;
604
- },
605
-
606
- toPrintable: function(i) {
607
-
608
- if (i >= 0x20 & i <= 0x7F) {
609
- return String.fromCharCode(i);
610
- } else {
611
- return '.';
612
- }
613
- },
614
-
615
- bytesToString: function(bytes) {
616
- // based on http://ciaranj.blogspot.fr/2007/11/utf8-characters-encoding-in-javascript.html
617
-
618
- var result = "";
619
- var i, c, c1, c2, c3;
620
- i = c = c1 = c2 = c3 = 0;
621
-
622
- // Perform byte-order check.
623
- if( bytes.length >= 3 ) {
624
- if( (bytes[0] & 0xef) == 0xef && (bytes[1] & 0xbb) == 0xbb && (bytes[2] & 0xbf) == 0xbf ) {
625
- // stream has a BOM at the start, skip over
626
- i = 3;
627
- }
628
- }
629
-
630
- while ( i < bytes.length ) {
631
- c = bytes[i] & 0xff;
632
-
633
- if ( c < 128 ) {
634
-
635
- result += String.fromCharCode(c);
636
- i++;
637
-
638
- } else if ( (c > 191) && (c < 224) ) {
639
-
640
- if ( i + 1 >= bytes.length ) {
641
- throw "Un-expected encoding error, UTF-8 stream truncated, or incorrect";
642
- }
643
- c2 = bytes[i + 1] & 0xff;
644
- result += String.fromCharCode( ((c & 31) << 6) | (c2 & 63) );
645
- i += 2;
646
-
647
- } else {
648
-
649
- if ( i + 2 >= bytes.length || i + 1 >= bytes.length ) {
650
- throw "Un-expected encoding error, UTF-8 stream truncated, or incorrect";
651
- }
652
- c2 = bytes[i + 1] & 0xff;
653
- c3 = bytes[i + 2] & 0xff;
654
- result += String.fromCharCode( ((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63) );
655
- i += 3;
656
-
657
- }
658
- }
659
- return result;
660
- },
661
-
662
- stringToBytes: function(string) {
663
- // based on http://ciaranj.blogspot.fr/2007/11/utf8-characters-encoding-in-javascript.html
664
-
665
- var bytes = [];
666
-
667
- for (var n = 0; n < string.length; n++) {
668
-
669
- var c = string.charCodeAt(n);
670
-
671
- if (c < 128) {
672
-
673
- bytes[bytes.length]= c;
674
-
675
- } else if((c > 127) && (c < 2048)) {
676
-
677
- bytes[bytes.length] = (c >> 6) | 192;
678
- bytes[bytes.length] = (c & 63) | 128;
679
-
680
- } else {
681
-
682
- bytes[bytes.length] = (c >> 12) | 224;
683
- bytes[bytes.length] = ((c >> 6) & 63) | 128;
684
- bytes[bytes.length] = (c & 63) | 128;
685
-
686
- }
687
-
688
- }
689
-
690
- return bytes;
691
- },
692
-
693
- bytesToHexString: function (bytes) {
694
- var dec, hexstring, bytesAsHexString = "";
695
- for (var i = 0; i < bytes.length; i++) {
696
- if (bytes[i] >= 0) {
697
- dec = bytes[i];
698
- } else {
699
- dec = 256 + bytes[i];
700
- }
701
- hexstring = dec.toString(16);
702
- // zero padding
703
- if (hexstring.length === 1) {
704
- hexstring = "0" + hexstring;
705
- }
706
- bytesAsHexString += hexstring;
707
- }
708
- return bytesAsHexString;
709
- },
710
-
711
- // This function can be removed if record.type is changed to a String
712
- /**
713
- * Returns true if the record's TNF and type matches the supplied TNF and type.
714
- *
715
- * @record NDEF record
716
- * @tnf 3-bit TNF (Type Name Format) - use one of the TNF_* constants
717
- * @type byte array or String
718
- */
719
- isType: function(record, tnf, type) {
720
- if (record.tnf === tnf) { // TNF is 3-bit
721
- var recordType;
722
- if (typeof(type) === 'string') {
723
- recordType = type;
724
- } else {
725
- recordType = nfc.bytesToString(type);
726
- }
727
- return (nfc.bytesToString(record.type) === recordType);
728
- }
729
- return false;
730
- },
731
-
732
- /**
733
- * Convert an ArrayBuffer to a hex string
734
- *
735
- * @param {ArrayBuffer} buffer
736
- * @returns {srting} - hex representation of bytes e.g. 000407AF
737
- */
738
- arrayBufferToHexString: function(buffer) {
739
- function toHexString(byte) {
740
- return ('0' + (byte & 0xFF).toString(16)).slice(-2);
741
- }
742
- var typedArray = new Uint8Array(buffer);
743
- var array = Array.from(typedArray); // need to convert to [] so our map result is not typed
744
- var parts = array.map(function(i) { return toHexString(i) });
745
-
746
- return parts.join('');
747
- },
748
-
749
- /**
750
- * Convert a hex string to an ArrayBuffer.
751
- *
752
- * @param {string} hexString - hex representation of bytes
753
- * @return {ArrayBuffer} - The bytes in an ArrayBuffer.
754
- */
755
- hexStringToArrayBuffer: function(hexString) {
756
-
757
- // remove any delimiters - space, dash, or colon
758
- hexString = hexString.replace(/[\s-:]/g, '');
759
-
760
- // remove the leading 0x
761
- hexString = hexString.replace(/^0x/, '');
762
-
763
- // ensure even number of characters
764
- if (hexString.length % 2 != 0) {
765
- console.log('WARNING: expecting an even number of characters in the hexString');
766
- }
767
-
768
- // check for some non-hex characters
769
- var bad = hexString.match(/[G-Z\s]/i);
770
- if (bad) {
771
- console.log('WARNING: found non-hex characters', bad);
772
- }
773
-
774
- // split the string into pairs of octets
775
- var pairs = hexString.match(/[\dA-F]{2}/gi);
776
-
777
- // convert the octets to integers
778
- var ints = pairs.map(function(s) { return parseInt(s, 16) });
779
-
780
- var array = new Uint8Array(ints);
781
- return array.buffer;
782
- }
783
-
784
- };
785
-
786
- // this is a module in ndef-js
787
- var textHelper = {
788
-
789
- decodePayload: function (data) {
790
-
791
- var languageCodeLength = (data[0] & 0x3F), // 6 LSBs
792
- languageCode = data.slice(1, 1 + languageCodeLength),
793
- utf16 = (data[0] & 0x80) !== 0; // assuming UTF-16BE
794
-
795
- // TODO need to deal with UTF in the future
796
- if (utf16) {
797
- console.log('WARNING: utf-16 data may not be handled properly for', languageCode);
798
- }
799
- // Use TextDecoder when we have enough browser support
800
- // new TextDecoder('utf-8').decode(data.slice(languageCodeLength + 1));
801
- // new TextDecoder('utf-16').decode(data.slice(languageCodeLength + 1));
802
-
803
- return util.bytesToString(data.slice(languageCodeLength + 1));
804
- },
805
-
806
- // encode text payload
807
- // @returns an array of bytes
808
- encodePayload: function(text, lang, encoding) {
809
-
810
- // ISO/IANA language code, but we're not enforcing
811
- if (!lang) { lang = 'en'; }
812
-
813
- var encoded = util.stringToBytes(lang + text);
814
- encoded.unshift(lang.length);
815
-
816
- return encoded;
817
- }
818
-
819
- };
820
-
821
- // this is a module in ndef-js
822
- var uriHelper = {
823
- // URI identifier codes from URI Record Type Definition NFCForum-TS-RTD_URI_1.0 2006-07-24
824
- // index in array matches code in the spec
825
- protocols: [ "", "http://www.", "https://www.", "http://", "https://", "tel:", "mailto:", "ftp://anonymous:anonymous@", "ftp://ftp.", "ftps://", "sftp://", "smb://", "nfs://", "ftp://", "dav://", "news:", "telnet://", "imap:", "rtsp://", "urn:", "pop:", "sip:", "sips:", "tftp:", "btspp://", "btl2cap://", "btgoep://", "tcpobex://", "irdaobex://", "file://", "urn:epc:id:", "urn:epc:tag:", "urn:epc:pat:", "urn:epc:raw:", "urn:epc:", "urn:nfc:" ],
826
-
827
- // decode a URI payload bytes
828
- // @returns a string
829
- decodePayload: function (data) {
830
- var prefix = uriHelper.protocols[data[0]];
831
- if (!prefix) { // 36 to 255 should be ""
832
- prefix = "";
833
- }
834
- return prefix + util.bytesToString(data.slice(1));
835
- },
836
-
837
- // shorten a URI with standard prefix
838
- // @returns an array of bytes
839
- encodePayload: function (uri) {
840
-
841
- var prefix,
842
- protocolCode,
843
- encoded;
844
-
845
- // check each protocol, unless we've found a match
846
- // "urn:" is the one exception where we need to keep checking
847
- // slice so we don't check ""
848
- uriHelper.protocols.slice(1).forEach(function(protocol) {
849
- if ((!prefix || prefix === "urn:") && uri.indexOf(protocol) === 0) {
850
- prefix = protocol;
851
- }
852
- });
853
-
854
- if (!prefix) {
855
- prefix = "";
856
- }
857
-
858
- encoded = util.stringToBytes(uri.slice(prefix.length));
859
- protocolCode = uriHelper.protocols.indexOf(prefix);
860
- // prepend protocol code
861
- encoded.unshift(protocolCode);
862
-
863
- return encoded;
864
- }
865
- };
866
-
867
- // added since WP8 must call a named function, also used by iOS
868
- // TODO consider switching NFC events from JS events to using the PG callbacks
869
- function fireNfcTagEvent(eventType, tagAsJson) {
870
- setTimeout(function () {
871
- var e = document.createEvent('Events');
872
- e.initEvent(eventType, true, false);
873
- e.tag = JSON.parse(tagAsJson);
874
- console.log(e.tag);
875
- document.dispatchEvent(e);
876
- }, 10);
877
- }
878
-
879
- // textHelper and uriHelper aren't exported, add a property
880
- ndef.uriHelper = uriHelper;
881
- ndef.textHelper = textHelper;
882
-
883
- // create aliases
884
- nfc.bytesToString = util.bytesToString;
885
- nfc.stringToBytes = util.stringToBytes;
886
- nfc.bytesToHexString = util.bytesToHexString;
887
-
888
- // kludge some global variables for plugman js-module support
889
- // eventually these should be replaced and referenced via the module
890
- window.nfc = nfc;
891
- window.ndef = ndef;
892
- window.util = util;
893
- window.fireNfcTagEvent = fireNfcTagEvent;
894
-
895
- // This channel receives nfcEvent data from native code
896
- // and fires JavaScript events.
897
- require('cordova/channel').onCordovaReady.subscribe(function() {
898
- require('cordova/exec')(success, null, 'NfcPlugin', 'channel', []);
899
- function success(message) {
900
- if (!message.type) {
901
- console.log(message);
902
- } else {
903
- console.log("Received NFC data, firing '" + message.type + "' event");
904
- var e = document.createEvent('Events');
905
- e.initEvent(message.type);
906
- e.tap = message.tap;
907
- e.tag = message.tag;
908
- document.dispatchEvent(e);
909
- }
910
- }
911
- });
1
+ /*jshint bitwise: false, camelcase: false, quotmark: false, unused: vars, esversion: 6, browser: true*/
2
+ /*global cordova, console, require */
3
+
4
+ function handleNfcFromIntentFilter() {
5
+
6
+ // This was historically done in cordova.addConstructor but broke with PhoneGap-2.2.0.
7
+ // We need to handle NFC from an Intent that launched the application, but *after*
8
+ // the code in the application's deviceready has run. After upgrading to 2.2.0,
9
+ // addConstructor was finishing *before* deviceReady was complete and the
10
+ // ndef listeners had not been registered.
11
+ // It seems like there should be a better solution.
12
+ if (cordova.platformId === "android" || cordova.platformId === "windows") {
13
+ setTimeout(
14
+ function () {
15
+ cordova.exec(
16
+ function () {
17
+ console.log("Initialized the NfcPlugin");
18
+ },
19
+ function (reason) {
20
+ console.log("Failed to initialize the NfcPlugin " + reason);
21
+ },
22
+ "NfcPlugin", "init", []
23
+ );
24
+ }, 10
25
+ );
26
+ }
27
+ }
28
+
29
+ document.addEventListener('deviceready', handleNfcFromIntentFilter, false);
30
+
31
+ var ndef = {
32
+
33
+ // see android.nfc.NdefRecord for documentation about constants
34
+ // http://developer.android.com/reference/android/nfc/NdefRecord.html
35
+ TNF_EMPTY: 0x0,
36
+ TNF_WELL_KNOWN: 0x01,
37
+ TNF_MIME_MEDIA: 0x02,
38
+ TNF_ABSOLUTE_URI: 0x03,
39
+ TNF_EXTERNAL_TYPE: 0x04,
40
+ TNF_UNKNOWN: 0x05,
41
+ TNF_UNCHANGED: 0x06,
42
+ TNF_RESERVED: 0x07,
43
+
44
+ RTD_TEXT: [0x54], // "T"
45
+ RTD_URI: [0x55], // "U"
46
+ RTD_SMART_POSTER: [0x53, 0x70], // "Sp"
47
+ RTD_ALTERNATIVE_CARRIER: [0x61, 0x63], // "ac"
48
+ RTD_HANDOVER_CARRIER: [0x48, 0x63], // "Hc"
49
+ RTD_HANDOVER_REQUEST: [0x48, 0x72], // "Hr"
50
+ RTD_HANDOVER_SELECT: [0x48, 0x73], // "Hs"
51
+
52
+ /**
53
+ * Creates a JSON representation of a NDEF Record.
54
+ *
55
+ * @tnf 3-bit TNF (Type Name Format) - use one of the TNF_* constants
56
+ * @type byte array, containing zero to 255 bytes, must not be null
57
+ * @id byte array, containing zero to 255 bytes, must not be null
58
+ * @payload byte array, containing zero to (2 ** 32 - 1) bytes, must not be null
59
+ *
60
+ * @returns JSON representation of a NDEF record
61
+ *
62
+ * @see Ndef.textRecord, Ndef.uriRecord and Ndef.mimeMediaRecord for examples
63
+ */
64
+ record: function (tnf, type, id, payload) {
65
+
66
+ // handle null values
67
+ if (!tnf) { tnf = ndef.TNF_EMPTY; }
68
+ if (!type) { type = []; }
69
+ if (!id) { id = []; }
70
+ if (!payload) { payload = []; }
71
+
72
+ // convert strings to arrays
73
+ if (!(type instanceof Array)) {
74
+ type = nfc.stringToBytes(type);
75
+ }
76
+ if (!(id instanceof Array)) {
77
+ id = nfc.stringToBytes(id);
78
+ }
79
+ if (!(payload instanceof Array)) {
80
+ payload = nfc.stringToBytes(payload);
81
+ }
82
+
83
+ return {
84
+ tnf: tnf,
85
+ type: type,
86
+ id: id,
87
+ payload: payload
88
+ };
89
+ },
90
+
91
+ /**
92
+ * Helper that creates an NDEF record containing plain text.
93
+ *
94
+ * @text String of text to encode
95
+ * @languageCode ISO/IANA language code. Examples: “fi”, “en-US”, “fr- CA”, “jp”. (optional)
96
+ * @id byte[] (optional)
97
+ */
98
+ textRecord: function (text, languageCode, id) {
99
+ var payload = textHelper.encodePayload(text, languageCode);
100
+ if (!id) { id = []; }
101
+ return ndef.record(ndef.TNF_WELL_KNOWN, ndef.RTD_TEXT, id, payload);
102
+ },
103
+
104
+ /**
105
+ * Helper that creates a NDEF record containing a URI.
106
+ *
107
+ * @uri String
108
+ * @id byte[] (optional)
109
+ */
110
+ uriRecord: function (uri, id) {
111
+ var payload = uriHelper.encodePayload(uri);
112
+ if (!id) { id = []; }
113
+ return ndef.record(ndef.TNF_WELL_KNOWN, ndef.RTD_URI, id, payload);
114
+ },
115
+
116
+ /**
117
+ * Helper that creates a NDEF record containing an absolute URI.
118
+ *
119
+ * An Absolute URI record means the URI describes the payload of the record.
120
+ *
121
+ * For example a SOAP message could use "http://schemas.xmlsoap.org/soap/envelope/"
122
+ * as the type and XML content for the payload.
123
+ *
124
+ * Absolute URI can also be used to write LaunchApp records for Windows.
125
+ *
126
+ * See 2.4.2 Payload Type of the NDEF Specification
127
+ * http://www.nfc-forum.org/specs/spec_list#ndefts
128
+ *
129
+ * Note that by default, Android will open the URI defined in the type
130
+ * field of an Absolute URI record (TNF=3) and ignore the payload.
131
+ * BlackBerry and Windows do not open the browser for TNF=3.
132
+ *
133
+ * To write a URI as the payload use ndef.uriRecord(uri)
134
+ *
135
+ * @uri String
136
+ * @payload byte[] or String
137
+ * @id byte[] (optional)
138
+ */
139
+ absoluteUriRecord: function (uri, payload, id) {
140
+ if (!id) { id = []; }
141
+ if (!payload) { payload = []; }
142
+ return ndef.record(ndef.TNF_ABSOLUTE_URI, uri, id, payload);
143
+ },
144
+
145
+ /**
146
+ * Helper that creates a NDEF record containing an mimeMediaRecord.
147
+ *
148
+ * @mimeType String
149
+ * @payload byte[]
150
+ * @id byte[] (optional)
151
+ */
152
+ mimeMediaRecord: function (mimeType, payload, id) {
153
+ if (!id) { id = []; }
154
+ return ndef.record(ndef.TNF_MIME_MEDIA, nfc.stringToBytes(mimeType), id, payload);
155
+ },
156
+
157
+ /**
158
+ * Helper that creates an NDEF record containing an Smart Poster.
159
+ *
160
+ * @ndefRecords array of NDEF Records
161
+ * @id byte[] (optional)
162
+ */
163
+ smartPoster: function (ndefRecords, id) {
164
+ var payload = [];
165
+
166
+ if (!id) { id = []; }
167
+
168
+ if (ndefRecords)
169
+ {
170
+ // make sure we have an array of something like NDEF records before encoding
171
+ if (ndefRecords[0] instanceof Object && ndefRecords[0].hasOwnProperty('tnf')) {
172
+ payload = ndef.encodeMessage(ndefRecords);
173
+ } else {
174
+ // assume the caller has already encoded the NDEF records into a byte array
175
+ payload = ndefRecords;
176
+ }
177
+ } else {
178
+ console.log("WARNING: Expecting an array of NDEF records");
179
+ }
180
+
181
+ return ndef.record(ndef.TNF_WELL_KNOWN, ndef.RTD_SMART_POSTER, id, payload);
182
+ },
183
+
184
+ /**
185
+ * Helper that creates an empty NDEF record.
186
+ *
187
+ */
188
+ emptyRecord: function() {
189
+ return ndef.record(ndef.TNF_EMPTY, [], [], []);
190
+ },
191
+
192
+ /**
193
+ * Helper that creates an Android Application Record (AAR).
194
+ * http://developer.android.com/guide/topics/connectivity/nfc/nfc.html#aar
195
+ *
196
+ */
197
+ androidApplicationRecord: function(packageName) {
198
+ return ndef.record(ndef.TNF_EXTERNAL_TYPE, "android.com:pkg", [], packageName);
199
+ },
200
+
201
+ /**
202
+ * Encodes an NDEF Message into bytes that can be written to a NFC tag.
203
+ *
204
+ * @ndefRecords an Array of NDEF Records
205
+ *
206
+ * @returns byte array
207
+ *
208
+ * @see NFC Data Exchange Format (NDEF) http://www.nfc-forum.org/specs/spec_list/
209
+ */
210
+ encodeMessage: function (ndefRecords) {
211
+
212
+ var encoded = [],
213
+ tnf_byte,
214
+ type_length,
215
+ payload_length,
216
+ id_length,
217
+ i,
218
+ mb, me, // messageBegin, messageEnd
219
+ cf = false, // chunkFlag TODO implement
220
+ sr, // boolean shortRecord
221
+ il; // boolean idLengthFieldIsPresent
222
+
223
+ for(i = 0; i < ndefRecords.length; i++) {
224
+
225
+ mb = (i === 0);
226
+ me = (i === (ndefRecords.length - 1));
227
+ sr = (ndefRecords[i].payload.length < 0xFF);
228
+ il = (ndefRecords[i].id.length > 0);
229
+ tnf_byte = ndef.encodeTnf(mb, me, cf, sr, il, ndefRecords[i].tnf);
230
+ encoded.push(tnf_byte);
231
+
232
+ type_length = ndefRecords[i].type.length;
233
+ encoded.push(type_length);
234
+
235
+ if (sr) {
236
+ payload_length = ndefRecords[i].payload.length;
237
+ encoded.push(payload_length);
238
+ } else {
239
+ payload_length = ndefRecords[i].payload.length;
240
+ // 4 bytes
241
+ encoded.push((payload_length >> 24));
242
+ encoded.push((payload_length >> 16));
243
+ encoded.push((payload_length >> 8));
244
+ encoded.push((payload_length & 0xFF));
245
+ }
246
+
247
+ if (il) {
248
+ id_length = ndefRecords[i].id.length;
249
+ encoded.push(id_length);
250
+ }
251
+
252
+ encoded = encoded.concat(ndefRecords[i].type);
253
+
254
+ if (il) {
255
+ encoded = encoded.concat(ndefRecords[i].id);
256
+ }
257
+
258
+ encoded = encoded.concat(ndefRecords[i].payload);
259
+ }
260
+
261
+ return encoded;
262
+ },
263
+
264
+ /**
265
+ * Decodes an array bytes into an NDEF Message
266
+ *
267
+ * @bytes an array bytes read from a NFC tag
268
+ *
269
+ * @returns array of NDEF Records
270
+ *
271
+ * @see NFC Data Exchange Format (NDEF) http://www.nfc-forum.org/specs/spec_list/
272
+ */
273
+ decodeMessage: function (ndefBytes) {
274
+
275
+ var bytes = ndefBytes.slice(0), // clone since parsing is destructive
276
+ ndef_message = [],
277
+ tnf_byte,
278
+ header,
279
+ type_length = 0,
280
+ payload_length = 0,
281
+ id_length = 0,
282
+ record_type = [],
283
+ id = [],
284
+ payload = [];
285
+
286
+ while(bytes.length) {
287
+ tnf_byte = bytes.shift();
288
+ header = ndef.decodeTnf(tnf_byte);
289
+
290
+ type_length = bytes.shift();
291
+
292
+ if (header.sr) {
293
+ payload_length = bytes.shift();
294
+ } else {
295
+ // next 4 bytes are length
296
+ payload_length = ((0xFF & bytes.shift()) << 24) |
297
+ ((0xFF & bytes.shift()) << 26) |
298
+ ((0xFF & bytes.shift()) << 8) |
299
+ (0xFF & bytes.shift());
300
+ }
301
+
302
+ if (header.il) {
303
+ id_length = bytes.shift();
304
+ }
305
+
306
+ record_type = bytes.splice(0, type_length);
307
+ id = bytes.splice(0, id_length);
308
+ payload = bytes.splice(0, payload_length);
309
+
310
+ ndef_message.push(
311
+ ndef.record(header.tnf, record_type, id, payload)
312
+ );
313
+
314
+ if (header.me) { break; } // last message
315
+ }
316
+
317
+ return ndef_message;
318
+ },
319
+
320
+ /**
321
+ * Decode the bit flags from a TNF Byte.
322
+ *
323
+ * @returns object with decoded data
324
+ *
325
+ * See NFC Data Exchange Format (NDEF) Specification Section 3.2 RecordLayout
326
+ */
327
+ decodeTnf: function (tnf_byte) {
328
+ return {
329
+ mb: (tnf_byte & 0x80) !== 0,
330
+ me: (tnf_byte & 0x40) !== 0,
331
+ cf: (tnf_byte & 0x20) !== 0,
332
+ sr: (tnf_byte & 0x10) !== 0,
333
+ il: (tnf_byte & 0x8) !== 0,
334
+ tnf: (tnf_byte & 0x7)
335
+ };
336
+ },
337
+
338
+ /**
339
+ * Encode NDEF bit flags into a TNF Byte.
340
+ *
341
+ * @returns tnf byte
342
+ *
343
+ * See NFC Data Exchange Format (NDEF) Specification Section 3.2 RecordLayout
344
+ */
345
+ encodeTnf: function (mb, me, cf, sr, il, tnf) {
346
+
347
+ var value = tnf;
348
+
349
+ if (mb) {
350
+ value = value | 0x80;
351
+ }
352
+
353
+ if (me) {
354
+ value = value | 0x40;
355
+ }
356
+
357
+ // note if cf: me, mb, li must be false and tnf must be 0x6
358
+ if (cf) {
359
+ value = value | 0x20;
360
+ }
361
+
362
+ if (sr) {
363
+ value = value | 0x10;
364
+ }
365
+
366
+ if (il) {
367
+ value = value | 0x8;
368
+ }
369
+
370
+ return value;
371
+ },
372
+
373
+ /**
374
+ * Convert TNF to String for user friendly display
375
+ *
376
+ */
377
+ tnfToString: function (tnf) {
378
+ var value = tnf;
379
+
380
+ switch (tnf) {
381
+ case ndef.TNF_EMPTY:
382
+ value = "Empty";
383
+ break;
384
+ case ndef.TNF_WELL_KNOWN:
385
+ value = "Well Known";
386
+ break;
387
+ case ndef.TNF_MIME_MEDIA:
388
+ value = "Mime Media";
389
+ break;
390
+ case ndef.TNF_ABSOLUTE_URI:
391
+ value = "Absolute URI";
392
+ break;
393
+ case ndef.TNF_EXTERNAL_TYPE:
394
+ value = "External";
395
+ break;
396
+ case ndef.TNF_UNKNOWN:
397
+ value = "Unknown";
398
+ break;
399
+ case ndef.TNF_UNCHANGED:
400
+ value = "Unchanged";
401
+ break;
402
+ case ndef.TNF_RESERVED:
403
+ value = "Reserved";
404
+ break;
405
+ }
406
+ return value;
407
+ }
408
+
409
+ };
410
+
411
+ // nfc provides javascript wrappers to the native phonegap implementation
412
+ var nfc = {
413
+
414
+ addTagDiscoveredListener: function (callback, win, fail) {
415
+ document.addEventListener("tag", callback, false);
416
+ cordova.exec(win, fail, "NfcPlugin", "registerTag", []);
417
+ },
418
+
419
+ addMimeTypeListener: function (mimeType, callback, win, fail) {
420
+ document.addEventListener("ndef-mime", callback, false);
421
+ cordova.exec(win, fail, "NfcPlugin", "registerMimeType", [mimeType]);
422
+ },
423
+
424
+ addNdefListener: function (callback, win, fail) {
425
+ document.addEventListener("ndef", callback, false);
426
+ cordova.exec(win, fail, "NfcPlugin", "registerNdef", []);
427
+ },
428
+
429
+ addTapDeviceListener: function (callback, win, fail) {
430
+ document.addEventListener("nfc-tap-device", callback, false);
431
+ win();
432
+ // cordova.exec(win, fail, "NfcPlugin", "registerTapDevice", [
433
+ // JSON.stringify(options)
434
+ // ]);
435
+ },
436
+
437
+ addNdefFormatableListener: function (callback, win, fail) {
438
+ document.addEventListener("ndef-formatable", callback, false);
439
+ cordova.exec(win, fail, "NfcPlugin", "registerNdefFormatable", []);
440
+ },
441
+
442
+ write: function (ndefMessage, win, fail) {
443
+ cordova.exec(win, fail, "NfcPlugin", "writeTag", [ndefMessage]);
444
+ },
445
+
446
+ erase: function (win, fail) {
447
+ cordova.exec(win, fail, "NfcPlugin", "eraseTag", [[]]);
448
+ },
449
+
450
+ enabled: function (win, fail) {
451
+ cordova.exec(win, fail, "NfcPlugin", "enabled", [[]]);
452
+ },
453
+
454
+ removeTagDiscoveredListener: function (callback, win, fail) {
455
+ document.removeEventListener("tag", callback, false);
456
+ cordova.exec(win, fail, "NfcPlugin", "removeTag", []);
457
+ },
458
+
459
+ removeMimeTypeListener: function(mimeType, callback, win, fail) {
460
+ document.removeEventListener("ndef-mime", callback, false);
461
+ cordova.exec(win, fail, "NfcPlugin", "removeMimeType", [mimeType]);
462
+ },
463
+
464
+ removeNdefListener: function (callback, win, fail) {
465
+ document.removeEventListener("ndef", callback, false);
466
+ cordova.exec(win, fail, "NfcPlugin", "removeNdef", []);
467
+ },
468
+
469
+ showSettings: function (win, fail) {
470
+ cordova.exec(win, fail, "NfcPlugin", "showSettings", []);
471
+ },
472
+
473
+ // iOS only
474
+
475
+ beginNDEFSession: function (win, fail) {
476
+ cordova.exec(win, fail, "NfcPlugin", "beginNDEFSession", []);
477
+ },
478
+
479
+ // iOS only
480
+
481
+ invalidateNDEFSession: function (win, fail) {
482
+ cordova.exec(win, fail, 'NfcPlugin', 'invalidateNDEFSession', []);
483
+ },
484
+
485
+ connect: function(tech, timeout) {
486
+ return new Promise(function(resolve, reject) {
487
+ cordova.exec(resolve, reject, 'NfcPlugin', 'connect', [tech, timeout]);
488
+ });
489
+ },
490
+
491
+
492
+ connectRaw: function(tech, timeout) {
493
+ return new Promise(function(resolve, reject) {
494
+ cordova.exec(resolve, reject, 'NfcPlugin', 'connectRaw', [tech, timeout]);
495
+ });
496
+ },
497
+
498
+ close: function() {
499
+ return new Promise(function(resolve, reject) {
500
+ cordova.exec(resolve, reject, 'NfcPlugin', 'close', []);
501
+ });
502
+ },
503
+
504
+ // data - ArrayBuffer or string of hex data for transcieve
505
+ // the results of transcieve are returned in the promise success as an ArrayBuffer
506
+ transceiveTap: function(data) {
507
+ return new Promise(function(resolve, reject) {
508
+
509
+ var buffer;
510
+ if (typeof data === 'string') {
511
+ buffer = util.hexStringToArrayBuffer(data);
512
+ } else if (data instanceof ArrayBuffer) {
513
+ buffer = data;
514
+ } else if (data instanceof Uint8Array) {
515
+ buffer = data.buffer;
516
+ } else {
517
+ reject("Expecting an ArrayBuffer or String");
518
+ }
519
+
520
+ cordova.exec(resolve, reject, 'NfcPlugin', 'transceiveTap', [buffer]);
521
+ });
522
+ },
523
+
524
+ // data - ArrayBuffer or string of hex data for transcieve
525
+ // the results of transcieve are returned in the promise success as an ArrayBuffer
526
+ transceive: function(data) {
527
+ return new Promise(function(resolve, reject) {
528
+
529
+ var buffer;
530
+ if (typeof data === 'string') {
531
+ buffer = util.hexStringToArrayBuffer(data);
532
+ } else if (data instanceof ArrayBuffer) {
533
+ buffer = data;
534
+ } else if (data instanceof Uint8Array) {
535
+ buffer = data.buffer;
536
+ } else {
537
+ reject("Expecting an ArrayBuffer or String");
538
+ }
539
+
540
+ cordova.exec(resolve, reject, 'NfcPlugin', 'transceive', [buffer]);
541
+ });
542
+ },
543
+
544
+ // // Android NfcAdapter.enableReaderMode flags
545
+ // FLAG_READER_NFC_A: 0x1,
546
+ // FLAG_READER_NFC_B: 0x2,
547
+ // FLAG_READER_NFC_F: 0x4,
548
+ // FLAG_READER_NFC_V: 0x8,
549
+ // FLAG_READER_NFC_BARCODE: 0x10,
550
+ // FLAG_READER_SKIP_NDEF_CHECK: 0x80,
551
+ // FLAG_READER_NO_PLATFORM_SOUNDS: 0x100,
552
+
553
+ // // Android NfcAdapter.enabledReaderMode
554
+ readerMode: function(flags, readCallback, errorCallback) {
555
+ cordova.exec(readCallback, errorCallback, 'NfcPlugin', 'readerMode', [flags]);
556
+ },
557
+
558
+ disableReaderMode: function(successCallback, errorCallback) {
559
+ cordova.exec(successCallback, errorCallback, 'NfcPlugin', 'disableReaderMode', []);
560
+ },
561
+
562
+ setTapDeviceDiscoveryEnabled: function(enabled) {
563
+ return new Promise(function(resolve, reject) {
564
+ cordova.exec(resolve, reject, 'NfcPlugin', 'setTapDeviceDiscoveryEnabled', [!!enabled]);
565
+ });
566
+ },
567
+
568
+ beginSessionFromTech: function(tech, alertMessage = undefined) {
569
+ const args = [tech];
570
+ if (alertMessage) {
571
+ args.push(alertMessage);
572
+ }
573
+ return new Promise(function(resolve, reject) {
574
+ cordova.exec(resolve, reject, 'NfcPlugin', 'beginSessionFromTech', args);
575
+ });
576
+ },
577
+
578
+ endSession: function() {
579
+ return new Promise(function(resolve, reject) {
580
+ cordova.exec(resolve,reject, 'NfcPlugin', 'endSession', []);
581
+ })
582
+ }
583
+
584
+
585
+ };
586
+
587
+ var util = {
588
+ // i must be <= 256
589
+ toHex: function (i) {
590
+ var hex;
591
+
592
+ if (i < 0) {
593
+ i += 256;
594
+ }
595
+
596
+ hex = i.toString(16);
597
+
598
+ // zero padding
599
+ if (hex.length === 1) {
600
+ hex = "0" + hex;
601
+ }
602
+
603
+ return hex;
604
+ },
605
+
606
+ toPrintable: function(i) {
607
+
608
+ if (i >= 0x20 & i <= 0x7F) {
609
+ return String.fromCharCode(i);
610
+ } else {
611
+ return '.';
612
+ }
613
+ },
614
+
615
+ bytesToString: function(bytes) {
616
+ // based on http://ciaranj.blogspot.fr/2007/11/utf8-characters-encoding-in-javascript.html
617
+
618
+ var result = "";
619
+ var i, c, c1, c2, c3;
620
+ i = c = c1 = c2 = c3 = 0;
621
+
622
+ // Perform byte-order check.
623
+ if( bytes.length >= 3 ) {
624
+ if( (bytes[0] & 0xef) == 0xef && (bytes[1] & 0xbb) == 0xbb && (bytes[2] & 0xbf) == 0xbf ) {
625
+ // stream has a BOM at the start, skip over
626
+ i = 3;
627
+ }
628
+ }
629
+
630
+ while ( i < bytes.length ) {
631
+ c = bytes[i] & 0xff;
632
+
633
+ if ( c < 128 ) {
634
+
635
+ result += String.fromCharCode(c);
636
+ i++;
637
+
638
+ } else if ( (c > 191) && (c < 224) ) {
639
+
640
+ if ( i + 1 >= bytes.length ) {
641
+ throw "Un-expected encoding error, UTF-8 stream truncated, or incorrect";
642
+ }
643
+ c2 = bytes[i + 1] & 0xff;
644
+ result += String.fromCharCode( ((c & 31) << 6) | (c2 & 63) );
645
+ i += 2;
646
+
647
+ } else {
648
+
649
+ if ( i + 2 >= bytes.length || i + 1 >= bytes.length ) {
650
+ throw "Un-expected encoding error, UTF-8 stream truncated, or incorrect";
651
+ }
652
+ c2 = bytes[i + 1] & 0xff;
653
+ c3 = bytes[i + 2] & 0xff;
654
+ result += String.fromCharCode( ((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63) );
655
+ i += 3;
656
+
657
+ }
658
+ }
659
+ return result;
660
+ },
661
+
662
+ stringToBytes: function(string) {
663
+ // based on http://ciaranj.blogspot.fr/2007/11/utf8-characters-encoding-in-javascript.html
664
+
665
+ var bytes = [];
666
+
667
+ for (var n = 0; n < string.length; n++) {
668
+
669
+ var c = string.charCodeAt(n);
670
+
671
+ if (c < 128) {
672
+
673
+ bytes[bytes.length]= c;
674
+
675
+ } else if((c > 127) && (c < 2048)) {
676
+
677
+ bytes[bytes.length] = (c >> 6) | 192;
678
+ bytes[bytes.length] = (c & 63) | 128;
679
+
680
+ } else {
681
+
682
+ bytes[bytes.length] = (c >> 12) | 224;
683
+ bytes[bytes.length] = ((c >> 6) & 63) | 128;
684
+ bytes[bytes.length] = (c & 63) | 128;
685
+
686
+ }
687
+
688
+ }
689
+
690
+ return bytes;
691
+ },
692
+
693
+ bytesToHexString: function (bytes) {
694
+ var dec, hexstring, bytesAsHexString = "";
695
+ for (var i = 0; i < bytes.length; i++) {
696
+ if (bytes[i] >= 0) {
697
+ dec = bytes[i];
698
+ } else {
699
+ dec = 256 + bytes[i];
700
+ }
701
+ hexstring = dec.toString(16);
702
+ // zero padding
703
+ if (hexstring.length === 1) {
704
+ hexstring = "0" + hexstring;
705
+ }
706
+ bytesAsHexString += hexstring;
707
+ }
708
+ return bytesAsHexString;
709
+ },
710
+
711
+ // This function can be removed if record.type is changed to a String
712
+ /**
713
+ * Returns true if the record's TNF and type matches the supplied TNF and type.
714
+ *
715
+ * @record NDEF record
716
+ * @tnf 3-bit TNF (Type Name Format) - use one of the TNF_* constants
717
+ * @type byte array or String
718
+ */
719
+ isType: function(record, tnf, type) {
720
+ if (record.tnf === tnf) { // TNF is 3-bit
721
+ var recordType;
722
+ if (typeof(type) === 'string') {
723
+ recordType = type;
724
+ } else {
725
+ recordType = nfc.bytesToString(type);
726
+ }
727
+ return (nfc.bytesToString(record.type) === recordType);
728
+ }
729
+ return false;
730
+ },
731
+
732
+ /**
733
+ * Convert an ArrayBuffer to a hex string
734
+ *
735
+ * @param {ArrayBuffer} buffer
736
+ * @returns {srting} - hex representation of bytes e.g. 000407AF
737
+ */
738
+ arrayBufferToHexString: function(buffer) {
739
+ function toHexString(byte) {
740
+ return ('0' + (byte & 0xFF).toString(16)).slice(-2);
741
+ }
742
+ var typedArray = new Uint8Array(buffer);
743
+ var array = Array.from(typedArray); // need to convert to [] so our map result is not typed
744
+ var parts = array.map(function(i) { return toHexString(i) });
745
+
746
+ return parts.join('');
747
+ },
748
+
749
+ /**
750
+ * Convert a hex string to an ArrayBuffer.
751
+ *
752
+ * @param {string} hexString - hex representation of bytes
753
+ * @return {ArrayBuffer} - The bytes in an ArrayBuffer.
754
+ */
755
+ hexStringToArrayBuffer: function(hexString) {
756
+
757
+ // remove any delimiters - space, dash, or colon
758
+ hexString = hexString.replace(/[\s-:]/g, '');
759
+
760
+ // remove the leading 0x
761
+ hexString = hexString.replace(/^0x/, '');
762
+
763
+ // ensure even number of characters
764
+ if (hexString.length % 2 != 0) {
765
+ console.log('WARNING: expecting an even number of characters in the hexString');
766
+ }
767
+
768
+ // check for some non-hex characters
769
+ var bad = hexString.match(/[G-Z\s]/i);
770
+ if (bad) {
771
+ console.log('WARNING: found non-hex characters', bad);
772
+ }
773
+
774
+ // split the string into pairs of octets
775
+ var pairs = hexString.match(/[\dA-F]{2}/gi);
776
+
777
+ // convert the octets to integers
778
+ var ints = pairs.map(function(s) { return parseInt(s, 16) });
779
+
780
+ var array = new Uint8Array(ints);
781
+ return array.buffer;
782
+ }
783
+
784
+ };
785
+
786
+ // this is a module in ndef-js
787
+ var textHelper = {
788
+
789
+ decodePayload: function (data) {
790
+
791
+ var languageCodeLength = (data[0] & 0x3F), // 6 LSBs
792
+ languageCode = data.slice(1, 1 + languageCodeLength),
793
+ utf16 = (data[0] & 0x80) !== 0; // assuming UTF-16BE
794
+
795
+ // TODO need to deal with UTF in the future
796
+ if (utf16) {
797
+ console.log('WARNING: utf-16 data may not be handled properly for', languageCode);
798
+ }
799
+ // Use TextDecoder when we have enough browser support
800
+ // new TextDecoder('utf-8').decode(data.slice(languageCodeLength + 1));
801
+ // new TextDecoder('utf-16').decode(data.slice(languageCodeLength + 1));
802
+
803
+ return util.bytesToString(data.slice(languageCodeLength + 1));
804
+ },
805
+
806
+ // encode text payload
807
+ // @returns an array of bytes
808
+ encodePayload: function(text, lang, encoding) {
809
+
810
+ // ISO/IANA language code, but we're not enforcing
811
+ if (!lang) { lang = 'en'; }
812
+
813
+ var encoded = util.stringToBytes(lang + text);
814
+ encoded.unshift(lang.length);
815
+
816
+ return encoded;
817
+ }
818
+
819
+ };
820
+
821
+ // this is a module in ndef-js
822
+ var uriHelper = {
823
+ // URI identifier codes from URI Record Type Definition NFCForum-TS-RTD_URI_1.0 2006-07-24
824
+ // index in array matches code in the spec
825
+ protocols: [ "", "http://www.", "https://www.", "http://", "https://", "tel:", "mailto:", "ftp://anonymous:anonymous@", "ftp://ftp.", "ftps://", "sftp://", "smb://", "nfs://", "ftp://", "dav://", "news:", "telnet://", "imap:", "rtsp://", "urn:", "pop:", "sip:", "sips:", "tftp:", "btspp://", "btl2cap://", "btgoep://", "tcpobex://", "irdaobex://", "file://", "urn:epc:id:", "urn:epc:tag:", "urn:epc:pat:", "urn:epc:raw:", "urn:epc:", "urn:nfc:" ],
826
+
827
+ // decode a URI payload bytes
828
+ // @returns a string
829
+ decodePayload: function (data) {
830
+ var prefix = uriHelper.protocols[data[0]];
831
+ if (!prefix) { // 36 to 255 should be ""
832
+ prefix = "";
833
+ }
834
+ return prefix + util.bytesToString(data.slice(1));
835
+ },
836
+
837
+ // shorten a URI with standard prefix
838
+ // @returns an array of bytes
839
+ encodePayload: function (uri) {
840
+
841
+ var prefix,
842
+ protocolCode,
843
+ encoded;
844
+
845
+ // check each protocol, unless we've found a match
846
+ // "urn:" is the one exception where we need to keep checking
847
+ // slice so we don't check ""
848
+ uriHelper.protocols.slice(1).forEach(function(protocol) {
849
+ if ((!prefix || prefix === "urn:") && uri.indexOf(protocol) === 0) {
850
+ prefix = protocol;
851
+ }
852
+ });
853
+
854
+ if (!prefix) {
855
+ prefix = "";
856
+ }
857
+
858
+ encoded = util.stringToBytes(uri.slice(prefix.length));
859
+ protocolCode = uriHelper.protocols.indexOf(prefix);
860
+ // prepend protocol code
861
+ encoded.unshift(protocolCode);
862
+
863
+ return encoded;
864
+ }
865
+ };
866
+
867
+ // added since WP8 must call a named function, also used by iOS
868
+ // TODO consider switching NFC events from JS events to using the PG callbacks
869
+ function fireNfcTagEvent(eventType, tagAsJson) {
870
+ setTimeout(function () {
871
+ var e = document.createEvent('Events');
872
+ e.initEvent(eventType, true, false);
873
+ e.tag = JSON.parse(tagAsJson);
874
+ console.log(e.tag);
875
+ document.dispatchEvent(e);
876
+ }, 10);
877
+ }
878
+
879
+ // textHelper and uriHelper aren't exported, add a property
880
+ ndef.uriHelper = uriHelper;
881
+ ndef.textHelper = textHelper;
882
+
883
+ // create aliases
884
+ nfc.bytesToString = util.bytesToString;
885
+ nfc.stringToBytes = util.stringToBytes;
886
+ nfc.bytesToHexString = util.bytesToHexString;
887
+
888
+ // kludge some global variables for plugman js-module support
889
+ // eventually these should be replaced and referenced via the module
890
+ window.nfc = nfc;
891
+ window.ndef = ndef;
892
+ window.util = util;
893
+ window.fireNfcTagEvent = fireNfcTagEvent;
894
+
895
+ // This channel receives nfcEvent data from native code
896
+ // and fires JavaScript events.
897
+ require('cordova/channel').onCordovaReady.subscribe(function() {
898
+ require('cordova/exec')(success, null, 'NfcPlugin', 'channel', []);
899
+ function success(message) {
900
+ if (!message.type) {
901
+ console.log(message);
902
+ } else {
903
+ console.log("Received NFC data, firing '" + message.type + "' event");
904
+ var e = document.createEvent('Events');
905
+ e.initEvent(message.type);
906
+ e.tap = message.tap;
907
+ e.tag = message.tag;
908
+ document.dispatchEvent(e);
909
+ }
910
+ }
911
+ });