community-cordova-plugin-nfc 1.4.0 → 1.5.3
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/CHANGELOG.md +37 -4
- package/README.md +184 -24
- package/package.json +32 -15
- package/plugin.xml +12 -10
- package/types/index.d.ts +429 -0
- package/www/phonegap-nfc.js +236 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,11 +3,44 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
## [1.5.0](https://github.com/EYALIN/community-cordova-plugin-nfc/compare/v1.4.0...v1.5.0) (2026-01-17)
|
|
7
7
|
|
|
8
8
|
### Features
|
|
9
9
|
|
|
10
|
-
*
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
* **Advanced Tag Analysis**: Add premium methods for deep NFC tag analysis
|
|
11
|
+
- `readMemoryPages(startPage, numPages)` - Read raw memory pages from NTAG/MIFARE Ultralight using READ command (0x30)
|
|
12
|
+
- `getNtagVersion()` - Get NTAG version info including IC type and memory size using GET_VERSION command (0x60)
|
|
13
|
+
- `readNtagCounter()` - Read NTAG 24-bit tap counter using READ_CNT command (0x39)
|
|
14
|
+
- `readNtagSignature()` - Read NTAG 32-byte ECC originality signature using READ_SIG command (0x3C)
|
|
15
|
+
- `getPasswordProtectionStatus(configPage)` - Check password protection configuration from config pages
|
|
16
|
+
- `fullMemoryDump()` - Perform complete memory dump with automatic tag type detection
|
|
13
17
|
|
|
18
|
+
* **TypeScript Support**: Add full TypeScript definitions
|
|
19
|
+
- Added `types/index.d.ts` with complete type definitions
|
|
20
|
+
- Interfaces for NDEF records, tags, and advanced analysis results
|
|
21
|
+
- Global declarations for `nfc`, `ndef`, and `util` objects
|
|
22
|
+
|
|
23
|
+
* **Package Improvements**:
|
|
24
|
+
- Updated `package.json` to match community plugin conventions
|
|
25
|
+
- Added `main` and `types` fields for TypeScript support
|
|
26
|
+
- Cleaned up platform list to focus on Android and iOS
|
|
27
|
+
|
|
28
|
+
### Breaking Changes
|
|
29
|
+
|
|
30
|
+
* Legacy platforms (Windows, BlackBerry) are no longer actively maintained
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## [1.4.0](https://github.com/EYALIN/community-cordova-plugin-nfc/releases/tag/v1.4.0) (2024-07-19)
|
|
35
|
+
|
|
36
|
+
### Features
|
|
37
|
+
|
|
38
|
+
* Change Android code to support SDK 34
|
|
39
|
+
* Deprecate `share`, `unshare`, `handover`, `stopHandover` functions
|
|
40
|
+
* Organize and clean up codebase
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Previous Versions
|
|
45
|
+
|
|
46
|
+
See the [original phonegap-nfc changelog](https://github.com/chariotsolutions/phonegap-nfc) for earlier version history.
|
package/README.md
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
[](https://www.npmjs.com/package/community-cordova-plugin-nfc)
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
# community-cordova-plugin-nfc
|
|
3
|
+
# Community Cordova NFC Plugin
|
|
6
4
|
|
|
5
|
+
A comprehensive Cordova plugin for NFC (Near Field Communication) on Android and iOS.
|
|
7
6
|
|
|
8
7
|
I dedicate a considerable amount of my free time to developing and maintaining many cordova plugins for the community ([See the list with all my maintained plugins][community_plugins]).
|
|
9
8
|
To help ensure this plugin is kept updated,
|
|
@@ -14,43 +13,50 @@ or if you're asking for new features or priority bug fixes. Thank you!
|
|
|
14
13
|
|
|
15
14
|
[](https://github.com/sponsors/eyalin)
|
|
16
15
|
|
|
16
|
+
## Features
|
|
17
|
+
|
|
18
|
+
- **Read/Write NDEF** - Read and write NDEF formatted NFC tags
|
|
19
|
+
- **Raw Commands** - Send raw commands via transceive (ISO 14443-3A, ISO 14443-4, ISO 15693)
|
|
20
|
+
- **Advanced Tag Analysis** (v1.5.0+) - Read raw memory, get NTAG version, counter, signature
|
|
21
|
+
- **TypeScript Support** - Full TypeScript definitions included
|
|
22
|
+
|
|
23
|
+
## What's New in v1.5.0
|
|
24
|
+
|
|
25
|
+
### Advanced Tag Analysis Methods
|
|
17
26
|
|
|
27
|
+
New methods for premium NFC tag analysis:
|
|
18
28
|
|
|
19
|
-
|
|
29
|
+
| Method | Description |
|
|
30
|
+
|--------|-------------|
|
|
31
|
+
| `readMemoryPages(startPage, numPages)` | Read raw memory pages from NTAG/MIFARE Ultralight |
|
|
32
|
+
| `getNtagVersion()` | Get NTAG version info (IC type, memory size) |
|
|
33
|
+
| `readNtagCounter()` | Read 24-bit NFC tap counter |
|
|
34
|
+
| `readNtagSignature()` | Read 32-byte ECC originality signature |
|
|
35
|
+
| `getPasswordProtectionStatus()` | Check password protection configuration |
|
|
36
|
+
| `fullMemoryDump()` | Complete memory dump with automatic tag detection |
|
|
20
37
|
|
|
21
|
-
|
|
22
|
-
* read data from NFC tags
|
|
23
|
-
* write data to NFC tags
|
|
24
|
-
* send data to other NFC enabled devices
|
|
25
|
-
* receive data from NFC devices
|
|
26
|
-
* send raw commands (ISO 14443-3A, ISO 14443-3A, ISO 14443-4, JIS 6319-4, ISO 15693) to NFC tags
|
|
38
|
+
## Supported Platforms
|
|
27
39
|
|
|
28
|
-
|
|
40
|
+
- ✅ Android (API 16+)
|
|
41
|
+
- ✅ iOS 11+ (CoreNFC)
|
|
29
42
|
|
|
30
|
-
|
|
31
|
-
-------------------
|
|
32
|
-
* Android
|
|
33
|
-
* [iOS 11](#ios-notes)
|
|
34
|
-
* Windows (includes Windows Phone 8.1, Windows 8.1, Windows 10)
|
|
35
|
-
* BlackBerry 10
|
|
36
|
-
* Windows Phone 8
|
|
37
|
-
* BlackBerry 7
|
|
43
|
+
> Note: Legacy platforms (Windows, BlackBerry) are no longer actively maintained but may still work.
|
|
38
44
|
|
|
39
45
|
## Contents
|
|
40
46
|
|
|
41
47
|
* [Installing](#installing)
|
|
48
|
+
* [TypeScript Usage](#typescript-usage)
|
|
49
|
+
* [Advanced Tag Analysis](#advanced-tag-analysis-v150)
|
|
42
50
|
* [NFC](#nfc)
|
|
43
51
|
* [NDEF](#ndef)
|
|
44
52
|
- [NdefMessage](#ndefmessage)
|
|
45
53
|
- [NdefRecord](#ndefrecord)
|
|
46
54
|
* [Events](#events)
|
|
47
55
|
* [Platform Differences](#platform-differences)
|
|
48
|
-
* [BlackBerry 10 Invoke Target](#blackberry-10-invoke-target)
|
|
49
56
|
* [Launching Application when Scanning a Tag](#launching-your-android-application-when-scanning-a-tag)
|
|
50
57
|
* [Testing](#testing)
|
|
51
58
|
* [Sample Projects](#sample-projects)
|
|
52
59
|
* [Host Card Emulation (HCE)](#hce)
|
|
53
|
-
* [Book](#book)
|
|
54
60
|
* [License](#license)
|
|
55
61
|
|
|
56
62
|
# Installing
|
|
@@ -71,11 +77,165 @@ Edit config.xml to install the plugin for [PhoneGap Build](http://build.phonegap
|
|
|
71
77
|
<plugin name="phonegap-nfc" source="npm" />
|
|
72
78
|
|
|
73
79
|
|
|
74
|
-
|
|
80
|
+
Or from local path:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
cordova plugin add /path/to/community-cordova-plugin-nfc
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
# TypeScript Usage
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
import { INdefTag, INtagVersionInfo, IFullMemoryDump } from 'community-cordova-plugin-nfc';
|
|
90
|
+
|
|
91
|
+
declare var nfc: any;
|
|
92
|
+
|
|
93
|
+
// Read NDEF tag (iOS)
|
|
94
|
+
const tag: INdefTag = await nfc.scanNdef();
|
|
95
|
+
console.log('Tag:', JSON.stringify(tag));
|
|
96
|
+
|
|
97
|
+
// Get NTAG version info (Android - requires connect first)
|
|
98
|
+
await nfc.connect('android.nfc.tech.NfcA');
|
|
99
|
+
const version: INtagVersionInfo = await nfc.getNtagVersion();
|
|
100
|
+
console.log('IC Type:', version.icType);
|
|
101
|
+
|
|
102
|
+
// Full memory dump
|
|
103
|
+
const dump: IFullMemoryDump = await nfc.fullMemoryDump();
|
|
104
|
+
console.log('Memory:', dump.hexDump);
|
|
105
|
+
await nfc.close();
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
# Advanced Tag Analysis (v1.5.0+)
|
|
109
|
+
|
|
110
|
+
These methods require connecting to the tag first using `nfc.connect()`.
|
|
111
|
+
|
|
112
|
+
## nfc.readMemoryPages
|
|
113
|
+
|
|
114
|
+
Read raw memory pages from NTAG/MIFARE Ultralight tags.
|
|
115
|
+
|
|
116
|
+
```javascript
|
|
117
|
+
await nfc.connect('android.nfc.tech.NfcA');
|
|
118
|
+
const memory = await nfc.readMemoryPages(0, 16);
|
|
119
|
+
console.log('Memory:', util.arrayBufferToHexString(memory));
|
|
120
|
+
await nfc.close();
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Parameters
|
|
124
|
+
|
|
125
|
+
- __startPage__: Starting page number (0-based)
|
|
126
|
+
- __numPages__: Number of pages to read
|
|
127
|
+
|
|
128
|
+
### Returns
|
|
129
|
+
|
|
130
|
+
- Promise with ArrayBuffer containing raw memory data
|
|
131
|
+
|
|
132
|
+
## nfc.getNtagVersion
|
|
133
|
+
|
|
134
|
+
Get NTAG version information using GET_VERSION command (0x60).
|
|
135
|
+
|
|
136
|
+
```javascript
|
|
137
|
+
await nfc.connect('android.nfc.tech.NfcA');
|
|
138
|
+
const version = await nfc.getNtagVersion();
|
|
139
|
+
console.log('IC Type:', version.icType);
|
|
140
|
+
console.log('Storage Size:', version.storageSize);
|
|
141
|
+
await nfc.close();
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Returns
|
|
145
|
+
|
|
146
|
+
- Promise with version info object:
|
|
147
|
+
- `vendorId`: Vendor ID (0x04 = NXP)
|
|
148
|
+
- `productType`: Product type (0x04 = NTAG, 0x03 = MIFARE Ultralight)
|
|
149
|
+
- `storageSize`: Storage size indicator
|
|
150
|
+
- `icType`: Human-readable IC type string (e.g., "NTAG215")
|
|
151
|
+
|
|
152
|
+
## nfc.readNtagCounter
|
|
153
|
+
|
|
154
|
+
Read the NTAG 24-bit NFC tap counter.
|
|
155
|
+
|
|
156
|
+
```javascript
|
|
157
|
+
await nfc.connect('android.nfc.tech.NfcA');
|
|
158
|
+
const counter = await nfc.readNtagCounter();
|
|
159
|
+
console.log('Tag has been tapped', counter, 'times');
|
|
160
|
+
await nfc.close();
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Returns
|
|
164
|
+
|
|
165
|
+
- Promise with counter value (0 to 16,777,215)
|
|
166
|
+
|
|
167
|
+
## nfc.readNtagSignature
|
|
168
|
+
|
|
169
|
+
Read the NTAG 32-byte ECC originality signature.
|
|
170
|
+
|
|
171
|
+
```javascript
|
|
172
|
+
await nfc.connect('android.nfc.tech.NfcA');
|
|
173
|
+
const signature = await nfc.readNtagSignature();
|
|
174
|
+
console.log('Signature:', util.arrayBufferToHexString(signature));
|
|
175
|
+
await nfc.close();
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Returns
|
|
179
|
+
|
|
180
|
+
- Promise with 32-byte signature as ArrayBuffer
|
|
181
|
+
|
|
182
|
+
## nfc.getPasswordProtectionStatus
|
|
183
|
+
|
|
184
|
+
Check password protection configuration.
|
|
185
|
+
|
|
186
|
+
```javascript
|
|
187
|
+
await nfc.connect('android.nfc.tech.NfcA');
|
|
188
|
+
const status = await nfc.getPasswordProtectionStatus();
|
|
189
|
+
console.log('Protected:', status.isProtected);
|
|
190
|
+
console.log('Protection starts at page:', status.protectionStartPage);
|
|
191
|
+
await nfc.close();
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Parameters
|
|
195
|
+
|
|
196
|
+
- __configPage__: (Optional) Config page number, defaults to NTAG216 config page
|
|
197
|
+
|
|
198
|
+
### Returns
|
|
199
|
+
|
|
200
|
+
- Promise with protection status object:
|
|
201
|
+
- `protectionStartPage`: Page where protection starts
|
|
202
|
+
- `isProtected`: Whether protection is enabled
|
|
203
|
+
- `readProtected`: Whether read is protected
|
|
204
|
+
- `writeProtected`: Whether write is protected
|
|
205
|
+
- `authLimitEnabled`: Whether auth limit is enabled
|
|
206
|
+
- `authLimitCounter`: Auth attempt counter (0-7)
|
|
207
|
+
|
|
208
|
+
## nfc.fullMemoryDump
|
|
209
|
+
|
|
210
|
+
Perform complete memory dump with automatic tag type detection.
|
|
211
|
+
|
|
212
|
+
```javascript
|
|
213
|
+
await nfc.connect('android.nfc.tech.NfcA');
|
|
214
|
+
const dump = await nfc.fullMemoryDump();
|
|
215
|
+
if (dump.success) {
|
|
216
|
+
console.log('Tag Type:', dump.tagType);
|
|
217
|
+
console.log('Total Pages:', dump.totalPages);
|
|
218
|
+
console.log('Hex Dump:', dump.hexDump);
|
|
219
|
+
}
|
|
220
|
+
await nfc.close();
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### Returns
|
|
224
|
+
|
|
225
|
+
- Promise with dump result object:
|
|
226
|
+
- `success`: Whether dump succeeded
|
|
227
|
+
- `tagType`: Detected tag type string
|
|
228
|
+
- `version`: NTAG version info (if available)
|
|
229
|
+
- `totalPages`: Total pages in tag
|
|
230
|
+
- `memoryDump`: Raw memory as ArrayBuffer
|
|
231
|
+
- `hexDump`: Memory as hex string
|
|
232
|
+
- `error`: Error message (if failed)
|
|
233
|
+
|
|
234
|
+
### Supported Platforms
|
|
75
235
|
|
|
76
|
-
|
|
236
|
+
- Android (requires `nfc.connect()` first)
|
|
77
237
|
|
|
78
|
-
|
|
238
|
+
---
|
|
79
239
|
|
|
80
240
|
## iOS Notes
|
|
81
241
|
|
package/package.json
CHANGED
|
@@ -1,33 +1,50 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "community-cordova-plugin-nfc",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.5.3",
|
|
4
|
+
"description": "Community Cordova NFC Plugin - Read and write NDEF messages, advanced tag analysis, raw memory access",
|
|
5
|
+
"main": "./types/index.d.ts",
|
|
6
|
+
"types": "./types/index.d.ts",
|
|
5
7
|
"cordova": {
|
|
6
|
-
"id": "
|
|
8
|
+
"id": "community-cordova-plugin-nfc",
|
|
7
9
|
"platforms": [
|
|
8
10
|
"android",
|
|
9
|
-
"wp8",
|
|
10
|
-
"windows",
|
|
11
|
-
"blackberry10",
|
|
12
11
|
"ios"
|
|
13
12
|
]
|
|
14
13
|
},
|
|
15
|
-
"
|
|
14
|
+
"readme": "README.md",
|
|
15
|
+
"repository": "EYALIN/community-cordova-plugin-nfc",
|
|
16
|
+
"homepage": "https://github.com/EYALIN/community-cordova-plugin-nfc",
|
|
17
|
+
"funding": "https://github.com/sponsors/EYALIN",
|
|
18
|
+
"bugs": "https://github.com/EYALIN/community-cordova-plugin-nfc/issues",
|
|
16
19
|
"keywords": [
|
|
20
|
+
"cordova",
|
|
17
21
|
"nfc",
|
|
18
22
|
"ndef",
|
|
23
|
+
"ntag",
|
|
24
|
+
"mifare",
|
|
25
|
+
"rfid",
|
|
26
|
+
"tag",
|
|
19
27
|
"ecosystem:cordova",
|
|
20
|
-
"cordova",
|
|
21
28
|
"cordova-android",
|
|
22
|
-
"cordova-wp8",
|
|
23
|
-
"cordova-windows",
|
|
24
|
-
"cordova-blackberry10",
|
|
25
29
|
"cordova-ios"
|
|
26
30
|
],
|
|
31
|
+
"scripts": {
|
|
32
|
+
"test": "npm run lint",
|
|
33
|
+
"lint": "eslint ."
|
|
34
|
+
},
|
|
27
35
|
"author": "Don Coleman <don.coleman@gmail.com>",
|
|
36
|
+
"contributors": [
|
|
37
|
+
"EYALIN"
|
|
38
|
+
],
|
|
28
39
|
"license": "MIT",
|
|
29
|
-
"
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
40
|
+
"engines": {
|
|
41
|
+
"cordovaDependencies": {
|
|
42
|
+
"1.0.0": {
|
|
43
|
+
"cordova": ">100"
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@cordova/eslint-config": "^3.0.0"
|
|
49
|
+
}
|
|
33
50
|
}
|
package/plugin.xml
CHANGED
|
@@ -1,18 +1,20 @@
|
|
|
1
|
-
<?xml version="1.
|
|
1
|
+
<?xml version="1.5.3" encoding="utf-8"?>
|
|
2
|
+
<!--
|
|
3
|
+
Community Cordova NFC Plugin
|
|
4
|
+
Licensed under MIT License
|
|
5
|
+
-->
|
|
2
6
|
<plugin
|
|
3
|
-
xmlns="http://
|
|
7
|
+
xmlns="http://apache.org/cordova/ns/plugins/1.0"
|
|
4
8
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
5
9
|
id="community-cordova-plugin-nfc"
|
|
6
|
-
version="1.
|
|
10
|
+
version="1.5.3">
|
|
7
11
|
|
|
8
12
|
<name>NFC</name>
|
|
9
|
-
|
|
10
|
-
<description>Near Field Communication (NFC) Plugin. Read and write NDEF messages to NFC tags and share NDEF messages with peers.</description>
|
|
11
|
-
|
|
13
|
+
<description>Community Cordova NFC Plugin - Read and write NDEF messages, advanced tag analysis, raw memory access</description>
|
|
12
14
|
<license>MIT</license>
|
|
13
|
-
<keywords>nfc,
|
|
14
|
-
<repo>https://github.com/EYALIN/community-cordova-plugin-nfc
|
|
15
|
-
<issue>https://github.com/EYALIN/community-cordova-plugin-nfc
|
|
15
|
+
<keywords>cordova,nfc,ndef,ntag,mifare,rfid</keywords>
|
|
16
|
+
<repo>https://github.com/EYALIN/community-cordova-plugin-nfc</repo>
|
|
17
|
+
<issue>https://github.com/EYALIN/community-cordova-plugin-nfc/issues</issue>
|
|
16
18
|
|
|
17
19
|
<platform name="android">
|
|
18
20
|
<js-module src="www/phonegap-nfc.js" name="NFC">
|
|
@@ -138,7 +140,7 @@
|
|
|
138
140
|
<framework src="CoreNFC.framework" weak="true" />
|
|
139
141
|
|
|
140
142
|
<preference name="NFC_USAGE_DESCRIPTION" default="Read NFC Tags" />
|
|
141
|
-
<config-file target="
|
|
143
|
+
<config-file target="App/App-Info.plist" parent="NFCReaderUsageDescription">
|
|
142
144
|
<string>$NFC_USAGE_DESCRIPTION</string>
|
|
143
145
|
</config-file>
|
|
144
146
|
</platform>
|
package/types/index.d.ts
ADDED
|
@@ -0,0 +1,429 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Community Cordova NFC Plugin - TypeScript Definitions
|
|
3
|
+
* Licensed under MIT License
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// ============================================
|
|
7
|
+
// NDEF Record Types
|
|
8
|
+
// ============================================
|
|
9
|
+
|
|
10
|
+
/** NDEF Record structure */
|
|
11
|
+
export interface INdefRecord {
|
|
12
|
+
/** Type Name Format (0-7) */
|
|
13
|
+
tnf: number;
|
|
14
|
+
/** Type as byte array */
|
|
15
|
+
type: number[];
|
|
16
|
+
/** Record ID as byte array */
|
|
17
|
+
id: number[];
|
|
18
|
+
/** Payload as byte array */
|
|
19
|
+
payload: number[];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** NDEF Tag/Event structure */
|
|
23
|
+
export interface INdefTag {
|
|
24
|
+
/** Tag type (e.g., "NFCTagTypeMiFare") */
|
|
25
|
+
type?: string;
|
|
26
|
+
/** Tag UID as byte array */
|
|
27
|
+
id?: number[];
|
|
28
|
+
/** Tech types available on the tag */
|
|
29
|
+
techTypes?: string[];
|
|
30
|
+
/** Maximum NDEF message size */
|
|
31
|
+
maxSize?: number;
|
|
32
|
+
/** Whether the tag is writable */
|
|
33
|
+
isWritable?: boolean;
|
|
34
|
+
/** Whether the tag can be made read-only */
|
|
35
|
+
canMakeReadOnly?: boolean;
|
|
36
|
+
/** NDEF message (array of records) */
|
|
37
|
+
ndefMessage?: INdefRecord[];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** NFC Event fired when tag is detected */
|
|
41
|
+
export interface INfcEvent extends Event {
|
|
42
|
+
tag: INdefTag;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// ============================================
|
|
46
|
+
// Advanced Tag Analysis Types (v1.5.0+)
|
|
47
|
+
// ============================================
|
|
48
|
+
|
|
49
|
+
/** NTAG/MIFARE Ultralight version information from GET_VERSION command */
|
|
50
|
+
export interface INtagVersionInfo {
|
|
51
|
+
/** Vendor ID (0x04 = NXP) */
|
|
52
|
+
vendorId: number;
|
|
53
|
+
/** Product type (0x04 = NTAG, 0x03 = MIFARE Ultralight) */
|
|
54
|
+
productType: number;
|
|
55
|
+
/** Product subtype */
|
|
56
|
+
productSubtype: number;
|
|
57
|
+
/** Major product version */
|
|
58
|
+
majorVersion: number;
|
|
59
|
+
/** Minor product version */
|
|
60
|
+
minorVersion: number;
|
|
61
|
+
/** Storage size indicator */
|
|
62
|
+
storageSize: number;
|
|
63
|
+
/** Protocol type */
|
|
64
|
+
protocolType: number;
|
|
65
|
+
/** Human-readable IC type (e.g., "NTAG215", "MIFARE Ultralight EV1") */
|
|
66
|
+
icType: string;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Password protection status for NTAG */
|
|
70
|
+
export interface INtagPasswordStatus {
|
|
71
|
+
/** Page number where protection starts */
|
|
72
|
+
protectionStartPage: number;
|
|
73
|
+
/** Whether any protection is enabled */
|
|
74
|
+
isProtected: boolean;
|
|
75
|
+
/** Whether read operations are protected */
|
|
76
|
+
readProtected: boolean;
|
|
77
|
+
/** Whether write operations are protected */
|
|
78
|
+
writeProtected: boolean;
|
|
79
|
+
/** Whether authentication attempt limiting is enabled */
|
|
80
|
+
authLimitEnabled: boolean;
|
|
81
|
+
/** Current authentication attempt counter (0-7) */
|
|
82
|
+
authLimitCounter: number;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** Complete memory dump result */
|
|
86
|
+
export interface IFullMemoryDump {
|
|
87
|
+
/** Whether the dump was successful */
|
|
88
|
+
success: boolean;
|
|
89
|
+
/** Detected tag type string */
|
|
90
|
+
tagType: string;
|
|
91
|
+
/** Version info if available */
|
|
92
|
+
version?: INtagVersionInfo;
|
|
93
|
+
/** Total number of pages in the tag */
|
|
94
|
+
totalPages: number;
|
|
95
|
+
/** Raw memory data as ArrayBuffer */
|
|
96
|
+
memoryDump: ArrayBuffer | null;
|
|
97
|
+
/** Hex string representation of all memory */
|
|
98
|
+
hexDump: string;
|
|
99
|
+
/** Error message if failed */
|
|
100
|
+
error?: string;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// ============================================
|
|
104
|
+
// Scan Options
|
|
105
|
+
// ============================================
|
|
106
|
+
|
|
107
|
+
/** Options for scanNdef and scanTag */
|
|
108
|
+
export interface IScanOptions {
|
|
109
|
+
/** Keep session open after reading (iOS only) */
|
|
110
|
+
keepSessionOpen?: boolean;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// ============================================
|
|
114
|
+
// NFC Plugin Interface
|
|
115
|
+
// ============================================
|
|
116
|
+
|
|
117
|
+
export interface INfcPlugin {
|
|
118
|
+
// ========== Core NDEF Operations ==========
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Scan for NDEF tags (iOS 13+)
|
|
122
|
+
* @param options - Scan options
|
|
123
|
+
* @returns Promise with tag data
|
|
124
|
+
*/
|
|
125
|
+
scanNdef(options?: IScanOptions): Promise<INdefTag>;
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Scan for any NFC tag with full tag info (iOS 13+)
|
|
129
|
+
* @param options - Scan options
|
|
130
|
+
* @returns Promise with tag data
|
|
131
|
+
*/
|
|
132
|
+
scanTag(options?: IScanOptions): Promise<INdefTag>;
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Write NDEF message to a tag
|
|
136
|
+
* @param ndefMessage - Array of NDEF records to write
|
|
137
|
+
* @returns Promise that resolves on success
|
|
138
|
+
*/
|
|
139
|
+
write(ndefMessage: INdefRecord[]): Promise<void>;
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Make a tag read-only (permanent!)
|
|
143
|
+
* @returns Promise that resolves on success
|
|
144
|
+
*/
|
|
145
|
+
makeReadOnly(): Promise<void>;
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Erase a tag (write empty NDEF message)
|
|
149
|
+
* @returns Promise that resolves on success
|
|
150
|
+
*/
|
|
151
|
+
erase(): Promise<void>;
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Cancel active NFC scan session
|
|
155
|
+
* @returns Promise that resolves on success
|
|
156
|
+
*/
|
|
157
|
+
cancelScan(): Promise<void>;
|
|
158
|
+
|
|
159
|
+
// ========== Event Registration (Android) ==========
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Register for NDEF tag events
|
|
163
|
+
* @param callback - Called when tag is detected
|
|
164
|
+
* @param onSuccess - Called on successful registration
|
|
165
|
+
* @param onError - Called on error
|
|
166
|
+
*/
|
|
167
|
+
addNdefListener(
|
|
168
|
+
callback: (event: INfcEvent) => void,
|
|
169
|
+
onSuccess?: () => void,
|
|
170
|
+
onError?: (error: string) => void
|
|
171
|
+
): void;
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Register for NDEF formatted tag events
|
|
175
|
+
* @param callback - Called when NDEF formatted tag is detected
|
|
176
|
+
* @param onSuccess - Called on successful registration
|
|
177
|
+
* @param onError - Called on error
|
|
178
|
+
*/
|
|
179
|
+
addNdefFormatableListener(
|
|
180
|
+
callback: (event: INfcEvent) => void,
|
|
181
|
+
onSuccess?: () => void,
|
|
182
|
+
onError?: (error: string) => void
|
|
183
|
+
): void;
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Register for MIME type events
|
|
187
|
+
* @param mimeType - MIME type to filter (e.g., "text/plain")
|
|
188
|
+
* @param callback - Called when matching tag is detected
|
|
189
|
+
* @param onSuccess - Called on successful registration
|
|
190
|
+
* @param onError - Called on error
|
|
191
|
+
*/
|
|
192
|
+
addMimeTypeListener(
|
|
193
|
+
mimeType: string,
|
|
194
|
+
callback: (event: INfcEvent) => void,
|
|
195
|
+
onSuccess?: () => void,
|
|
196
|
+
onError?: (error: string) => void
|
|
197
|
+
): void;
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Remove all NDEF listeners
|
|
201
|
+
* @param onSuccess - Called on success
|
|
202
|
+
* @param onError - Called on error
|
|
203
|
+
*/
|
|
204
|
+
removeNdefListener(
|
|
205
|
+
onSuccess?: () => void,
|
|
206
|
+
onError?: (error: string) => void
|
|
207
|
+
): void;
|
|
208
|
+
|
|
209
|
+
// ========== NFC Status ==========
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Check if NFC is enabled
|
|
213
|
+
* @returns Promise that resolves if enabled, rejects if disabled
|
|
214
|
+
*/
|
|
215
|
+
enabled(): Promise<void>;
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Open device NFC settings
|
|
219
|
+
*/
|
|
220
|
+
showSettings(): void;
|
|
221
|
+
|
|
222
|
+
// ========== Low-level Transceive (Android) ==========
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Connect to a tag for transceive operations
|
|
226
|
+
* @param tech - Tech type (e.g., "android.nfc.tech.NfcA")
|
|
227
|
+
* @param timeout - Connection timeout in ms
|
|
228
|
+
* @returns Promise that resolves on connection
|
|
229
|
+
*/
|
|
230
|
+
connect(tech: string, timeout?: number): Promise<void>;
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Close connection to tag
|
|
234
|
+
* @returns Promise that resolves on close
|
|
235
|
+
*/
|
|
236
|
+
close(): Promise<void>;
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Send raw command to tag and receive response
|
|
240
|
+
* @param command - Command bytes as ArrayBuffer
|
|
241
|
+
* @returns Promise with response as ArrayBuffer
|
|
242
|
+
*/
|
|
243
|
+
transceive(command: ArrayBuffer): Promise<ArrayBuffer>;
|
|
244
|
+
|
|
245
|
+
// ========== Advanced Tag Analysis (v1.5.0+) ==========
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Read raw memory pages from NTAG/MIFARE Ultralight
|
|
249
|
+
* Uses READ command (0x30) which reads 4 pages at a time
|
|
250
|
+
* @param startPage - Starting page number (0-based)
|
|
251
|
+
* @param numPages - Number of pages to read
|
|
252
|
+
* @returns Promise with raw memory data
|
|
253
|
+
*/
|
|
254
|
+
readMemoryPages(startPage: number, numPages: number): Promise<ArrayBuffer>;
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Get NTAG version information using GET_VERSION command (0x60)
|
|
258
|
+
* @returns Promise with version info
|
|
259
|
+
*/
|
|
260
|
+
getNtagVersion(): Promise<INtagVersionInfo>;
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Read NTAG counter value (24-bit tap counter)
|
|
264
|
+
* Uses READ_CNT command (0x39)
|
|
265
|
+
* @returns Promise with counter value
|
|
266
|
+
*/
|
|
267
|
+
readNtagCounter(): Promise<number>;
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Read NTAG originality signature (32-byte ECC)
|
|
271
|
+
* Uses READ_SIG command (0x3C)
|
|
272
|
+
* @returns Promise with signature as ArrayBuffer
|
|
273
|
+
*/
|
|
274
|
+
readNtagSignature(): Promise<ArrayBuffer>;
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Get password protection status from configuration pages
|
|
278
|
+
* @param configPage - Config page number (varies by tag type)
|
|
279
|
+
* @returns Promise with protection status
|
|
280
|
+
*/
|
|
281
|
+
getPasswordProtectionStatus(configPage?: number): Promise<INtagPasswordStatus>;
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Perform complete memory dump with automatic tag detection
|
|
285
|
+
* @returns Promise with full memory dump
|
|
286
|
+
*/
|
|
287
|
+
fullMemoryDump(): Promise<IFullMemoryDump>;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// ============================================
|
|
291
|
+
// NDEF Helper Utilities
|
|
292
|
+
// ============================================
|
|
293
|
+
|
|
294
|
+
export interface INdefUtil {
|
|
295
|
+
/**
|
|
296
|
+
* Create a text record
|
|
297
|
+
* @param text - Text content
|
|
298
|
+
* @param languageCode - Language code (default: "en")
|
|
299
|
+
* @param id - Optional record ID
|
|
300
|
+
* @returns NDEF record
|
|
301
|
+
*/
|
|
302
|
+
textRecord(text: string, languageCode?: string, id?: number[]): INdefRecord;
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Create a URI record
|
|
306
|
+
* @param uri - Full URI string
|
|
307
|
+
* @param id - Optional record ID
|
|
308
|
+
* @returns NDEF record
|
|
309
|
+
*/
|
|
310
|
+
uriRecord(uri: string, id?: number[]): INdefRecord;
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Create an Android Application Record (AAR)
|
|
314
|
+
* @param packageName - Android package name
|
|
315
|
+
* @returns NDEF record
|
|
316
|
+
*/
|
|
317
|
+
androidApplicationRecord(packageName: string): INdefRecord;
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Create a MIME type record
|
|
321
|
+
* @param mimeType - MIME type string
|
|
322
|
+
* @param payload - Payload as string or byte array
|
|
323
|
+
* @param id - Optional record ID
|
|
324
|
+
* @returns NDEF record
|
|
325
|
+
*/
|
|
326
|
+
mimeMediaRecord(mimeType: string, payload: string | number[], id?: number[]): INdefRecord;
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Create an empty record
|
|
330
|
+
* @returns Empty NDEF record
|
|
331
|
+
*/
|
|
332
|
+
emptyRecord(): INdefRecord;
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* Decode text payload from NDEF record
|
|
336
|
+
* @param record - NDEF record
|
|
337
|
+
* @returns Decoded text string
|
|
338
|
+
*/
|
|
339
|
+
decodeTextRecord(record: INdefRecord): string;
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Decode URI from NDEF record
|
|
343
|
+
* @param record - NDEF record
|
|
344
|
+
* @returns Decoded URI string
|
|
345
|
+
*/
|
|
346
|
+
decodeUriRecord(record: INdefRecord): string;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
export interface IUtil {
|
|
350
|
+
/**
|
|
351
|
+
* Convert byte array to string
|
|
352
|
+
* @param bytes - Byte array
|
|
353
|
+
* @returns String
|
|
354
|
+
*/
|
|
355
|
+
bytesToString(bytes: number[]): string;
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Convert string to byte array
|
|
359
|
+
* @param str - String
|
|
360
|
+
* @returns Byte array
|
|
361
|
+
*/
|
|
362
|
+
stringToBytes(str: string): number[];
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Convert byte array to hex string
|
|
366
|
+
* @param bytes - Byte array
|
|
367
|
+
* @returns Hex string
|
|
368
|
+
*/
|
|
369
|
+
bytesToHexString(bytes: number[]): string;
|
|
370
|
+
|
|
371
|
+
/**
|
|
372
|
+
* Convert ArrayBuffer to hex string
|
|
373
|
+
* @param buffer - ArrayBuffer
|
|
374
|
+
* @returns Hex string
|
|
375
|
+
*/
|
|
376
|
+
arrayBufferToHexString(buffer: ArrayBuffer): string;
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* Check if two byte arrays are equal
|
|
380
|
+
* @param a - First byte array
|
|
381
|
+
* @param b - Second byte array
|
|
382
|
+
* @returns True if equal
|
|
383
|
+
*/
|
|
384
|
+
isType(a: number[], b: number[]): boolean;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// ============================================
|
|
388
|
+
// Type Name Format Constants
|
|
389
|
+
// ============================================
|
|
390
|
+
|
|
391
|
+
export interface ITnf {
|
|
392
|
+
/** Record is empty */
|
|
393
|
+
TNF_EMPTY: 0;
|
|
394
|
+
/** NFC Forum well-known type */
|
|
395
|
+
TNF_WELL_KNOWN: 1;
|
|
396
|
+
/** Media type (RFC 2046) */
|
|
397
|
+
TNF_MIME_MEDIA: 2;
|
|
398
|
+
/** Absolute URI (RFC 3986) */
|
|
399
|
+
TNF_ABSOLUTE_URI: 3;
|
|
400
|
+
/** NFC Forum external type */
|
|
401
|
+
TNF_EXTERNAL_TYPE: 4;
|
|
402
|
+
/** Unknown type */
|
|
403
|
+
TNF_UNKNOWN: 5;
|
|
404
|
+
/** Unchanged (for chunked records) */
|
|
405
|
+
TNF_UNCHANGED: 6;
|
|
406
|
+
/** Reserved */
|
|
407
|
+
TNF_RESERVED: 7;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// ============================================
|
|
411
|
+
// Global Declarations
|
|
412
|
+
// ============================================
|
|
413
|
+
|
|
414
|
+
declare global {
|
|
415
|
+
interface Window {
|
|
416
|
+
nfc: INfcPlugin;
|
|
417
|
+
ndef: INdefUtil;
|
|
418
|
+
util: IUtil;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
/** NFC Plugin instance */
|
|
422
|
+
var nfc: INfcPlugin;
|
|
423
|
+
/** NDEF helper utilities */
|
|
424
|
+
var ndef: INdefUtil;
|
|
425
|
+
/** General utilities */
|
|
426
|
+
var util: IUtil;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
export default INfcPlugin;
|
package/www/phonegap-nfc.js
CHANGED
|
@@ -582,6 +582,242 @@ var nfc = {
|
|
|
582
582
|
|
|
583
583
|
disableReaderMode: function(successCallback, errorCallback) {
|
|
584
584
|
cordova.exec(successCallback, errorCallback, 'NfcPlugin', 'disableReaderMode', []);
|
|
585
|
+
},
|
|
586
|
+
|
|
587
|
+
// ============================================================
|
|
588
|
+
// Advanced Tag Analysis Methods (for premium features)
|
|
589
|
+
// ============================================================
|
|
590
|
+
|
|
591
|
+
/**
|
|
592
|
+
* Read raw memory pages from an NTAG/MIFARE Ultralight tag
|
|
593
|
+
* Uses the READ command (0x30) which reads 4 pages (16 bytes) at a time
|
|
594
|
+
*
|
|
595
|
+
* @param startPage - The starting page number (0-based)
|
|
596
|
+
* @param numPages - Number of pages to read (will read in blocks of 4)
|
|
597
|
+
* @returns Promise<ArrayBuffer> - Raw memory data
|
|
598
|
+
*/
|
|
599
|
+
readMemoryPages: function(startPage, numPages) {
|
|
600
|
+
return new Promise(function(resolve, reject) {
|
|
601
|
+
var pages = [];
|
|
602
|
+
var currentPage = startPage;
|
|
603
|
+
var endPage = startPage + numPages;
|
|
604
|
+
|
|
605
|
+
function readNextBlock() {
|
|
606
|
+
if (currentPage >= endPage) {
|
|
607
|
+
// Combine all page data
|
|
608
|
+
var totalLength = pages.reduce(function(sum, p) { return sum + p.length; }, 0);
|
|
609
|
+
var result = new Uint8Array(totalLength);
|
|
610
|
+
var offset = 0;
|
|
611
|
+
pages.forEach(function(p) {
|
|
612
|
+
result.set(new Uint8Array(p), offset);
|
|
613
|
+
offset += p.length;
|
|
614
|
+
});
|
|
615
|
+
resolve(result.buffer);
|
|
616
|
+
return;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
// NTAG READ command: 0x30 followed by page number
|
|
620
|
+
var cmd = new Uint8Array([0x30, currentPage]);
|
|
621
|
+
nfc.transceive(cmd.buffer).then(function(response) {
|
|
622
|
+
// READ returns 16 bytes (4 pages)
|
|
623
|
+
pages.push(response);
|
|
624
|
+
currentPage += 4;
|
|
625
|
+
readNextBlock();
|
|
626
|
+
}).catch(function(error) {
|
|
627
|
+
reject(error);
|
|
628
|
+
});
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
readNextBlock();
|
|
632
|
+
});
|
|
633
|
+
},
|
|
634
|
+
|
|
635
|
+
/**
|
|
636
|
+
* Get NTAG version information
|
|
637
|
+
* Sends GET_VERSION command (0x60) to identify tag type
|
|
638
|
+
*
|
|
639
|
+
* @returns Promise<Object> - Tag version info including IC type, memory size
|
|
640
|
+
*/
|
|
641
|
+
getNtagVersion: function() {
|
|
642
|
+
return new Promise(function(resolve, reject) {
|
|
643
|
+
// GET_VERSION command
|
|
644
|
+
var cmd = new Uint8Array([0x60]);
|
|
645
|
+
nfc.transceive(cmd.buffer).then(function(response) {
|
|
646
|
+
var data = new Uint8Array(response);
|
|
647
|
+
if (data.length >= 8) {
|
|
648
|
+
resolve({
|
|
649
|
+
vendorId: data[1],
|
|
650
|
+
productType: data[2],
|
|
651
|
+
productSubtype: data[3],
|
|
652
|
+
majorVersion: data[4],
|
|
653
|
+
minorVersion: data[5],
|
|
654
|
+
storageSize: data[6],
|
|
655
|
+
protocolType: data[7],
|
|
656
|
+
icType: nfc._parseIcType(data[2], data[6])
|
|
657
|
+
});
|
|
658
|
+
} else {
|
|
659
|
+
reject('Invalid GET_VERSION response');
|
|
660
|
+
}
|
|
661
|
+
}).catch(reject);
|
|
662
|
+
});
|
|
663
|
+
},
|
|
664
|
+
|
|
665
|
+
/**
|
|
666
|
+
* Read NTAG counter value (if supported)
|
|
667
|
+
* Sends READ_CNT command (0x39) with counter address 0x02
|
|
668
|
+
*
|
|
669
|
+
* @returns Promise<number> - Counter value (24-bit)
|
|
670
|
+
*/
|
|
671
|
+
readNtagCounter: function() {
|
|
672
|
+
return new Promise(function(resolve, reject) {
|
|
673
|
+
// READ_CNT command with counter address
|
|
674
|
+
var cmd = new Uint8Array([0x39, 0x02]);
|
|
675
|
+
nfc.transceive(cmd.buffer).then(function(response) {
|
|
676
|
+
var data = new Uint8Array(response);
|
|
677
|
+
if (data.length >= 3) {
|
|
678
|
+
// Counter is 3 bytes, LSB first
|
|
679
|
+
var counter = data[0] | (data[1] << 8) | (data[2] << 16);
|
|
680
|
+
resolve(counter);
|
|
681
|
+
} else {
|
|
682
|
+
reject('Invalid READ_CNT response');
|
|
683
|
+
}
|
|
684
|
+
}).catch(reject);
|
|
685
|
+
});
|
|
686
|
+
},
|
|
687
|
+
|
|
688
|
+
/**
|
|
689
|
+
* Read NTAG signature (originality check)
|
|
690
|
+
* Sends READ_SIG command (0x3C)
|
|
691
|
+
*
|
|
692
|
+
* @returns Promise<ArrayBuffer> - 32-byte ECC signature
|
|
693
|
+
*/
|
|
694
|
+
readNtagSignature: function() {
|
|
695
|
+
return new Promise(function(resolve, reject) {
|
|
696
|
+
// READ_SIG command
|
|
697
|
+
var cmd = new Uint8Array([0x3C, 0x00]);
|
|
698
|
+
nfc.transceive(cmd.buffer).then(function(response) {
|
|
699
|
+
var data = new Uint8Array(response);
|
|
700
|
+
if (data.length >= 32) {
|
|
701
|
+
resolve(response);
|
|
702
|
+
} else {
|
|
703
|
+
reject('Invalid READ_SIG response');
|
|
704
|
+
}
|
|
705
|
+
}).catch(reject);
|
|
706
|
+
});
|
|
707
|
+
},
|
|
708
|
+
|
|
709
|
+
/**
|
|
710
|
+
* Check if tag password protection is enabled
|
|
711
|
+
* Reads the configuration pages to determine auth status
|
|
712
|
+
*
|
|
713
|
+
* @param configPage - The config page number (varies by tag type)
|
|
714
|
+
* @returns Promise<Object> - Password protection status
|
|
715
|
+
*/
|
|
716
|
+
getPasswordProtectionStatus: function(configPage) {
|
|
717
|
+
return new Promise(function(resolve, reject) {
|
|
718
|
+
// Default config page for NTAG213/215/216 is different
|
|
719
|
+
var page = configPage || 41; // NTAG216 default
|
|
720
|
+
var cmd = new Uint8Array([0x30, page]);
|
|
721
|
+
nfc.transceive(cmd.buffer).then(function(response) {
|
|
722
|
+
var data = new Uint8Array(response);
|
|
723
|
+
// Parse AUTH0 and ACCESS config
|
|
724
|
+
var auth0 = data[3]; // Page address for password protection
|
|
725
|
+
var access = data[4]; // Access configuration byte
|
|
726
|
+
resolve({
|
|
727
|
+
protectionStartPage: auth0,
|
|
728
|
+
isProtected: auth0 < 255,
|
|
729
|
+
readProtected: (access & 0x80) !== 0,
|
|
730
|
+
writeProtected: true, // Write is always protected if auth0 < max
|
|
731
|
+
authLimitEnabled: (access & 0x07) !== 0,
|
|
732
|
+
authLimitCounter: access & 0x07
|
|
733
|
+
});
|
|
734
|
+
}).catch(reject);
|
|
735
|
+
});
|
|
736
|
+
},
|
|
737
|
+
|
|
738
|
+
/**
|
|
739
|
+
* Perform a full memory dump of the tag
|
|
740
|
+
* Automatically detects tag type and reads all user memory
|
|
741
|
+
*
|
|
742
|
+
* @returns Promise<Object> - Complete memory dump with metadata
|
|
743
|
+
*/
|
|
744
|
+
fullMemoryDump: function() {
|
|
745
|
+
return new Promise(function(resolve, reject) {
|
|
746
|
+
var result = {
|
|
747
|
+
success: false,
|
|
748
|
+
tagType: 'unknown',
|
|
749
|
+
totalPages: 0,
|
|
750
|
+
memoryDump: null,
|
|
751
|
+
hexDump: '',
|
|
752
|
+
error: null
|
|
753
|
+
};
|
|
754
|
+
|
|
755
|
+
// First try to get version to identify tag
|
|
756
|
+
nfc.getNtagVersion().then(function(version) {
|
|
757
|
+
result.tagType = version.icType;
|
|
758
|
+
result.version = version;
|
|
759
|
+
|
|
760
|
+
// Determine number of pages based on tag type
|
|
761
|
+
var pages = 45; // Default for NTAG213
|
|
762
|
+
if (version.icType.indexOf('215') !== -1) {
|
|
763
|
+
pages = 135;
|
|
764
|
+
} else if (version.icType.indexOf('216') !== -1) {
|
|
765
|
+
pages = 231;
|
|
766
|
+
} else if (version.icType.indexOf('210') !== -1) {
|
|
767
|
+
pages = 20;
|
|
768
|
+
} else if (version.icType.indexOf('212') !== -1) {
|
|
769
|
+
pages = 41;
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
result.totalPages = pages;
|
|
773
|
+
return nfc.readMemoryPages(0, pages);
|
|
774
|
+
}).then(function(memoryData) {
|
|
775
|
+
result.memoryDump = memoryData;
|
|
776
|
+
result.hexDump = util.arrayBufferToHexString(memoryData);
|
|
777
|
+
result.success = true;
|
|
778
|
+
resolve(result);
|
|
779
|
+
}).catch(function(error) {
|
|
780
|
+
// If GET_VERSION fails, try reading as MIFARE Ultralight
|
|
781
|
+
result.tagType = 'MIFARE Ultralight (Classic)';
|
|
782
|
+
result.totalPages = 16;
|
|
783
|
+
|
|
784
|
+
nfc.readMemoryPages(0, 16).then(function(memoryData) {
|
|
785
|
+
result.memoryDump = memoryData;
|
|
786
|
+
result.hexDump = util.arrayBufferToHexString(memoryData);
|
|
787
|
+
result.success = true;
|
|
788
|
+
resolve(result);
|
|
789
|
+
}).catch(function(error2) {
|
|
790
|
+
result.error = error2;
|
|
791
|
+
reject(result);
|
|
792
|
+
});
|
|
793
|
+
});
|
|
794
|
+
});
|
|
795
|
+
},
|
|
796
|
+
|
|
797
|
+
/**
|
|
798
|
+
* Parse IC type from GET_VERSION response
|
|
799
|
+
* @private
|
|
800
|
+
*/
|
|
801
|
+
_parseIcType: function(productType, storageSize) {
|
|
802
|
+
if (productType === 0x04) {
|
|
803
|
+
// NTAG family
|
|
804
|
+
switch(storageSize) {
|
|
805
|
+
case 0x0F: return 'NTAG213';
|
|
806
|
+
case 0x11: return 'NTAG215';
|
|
807
|
+
case 0x13: return 'NTAG216';
|
|
808
|
+
case 0x0B: return 'NTAG210';
|
|
809
|
+
case 0x0E: return 'NTAG212';
|
|
810
|
+
default: return 'NTAG (unknown variant)';
|
|
811
|
+
}
|
|
812
|
+
} else if (productType === 0x03) {
|
|
813
|
+
// MIFARE Ultralight family
|
|
814
|
+
switch(storageSize) {
|
|
815
|
+
case 0x0B: return 'MIFARE Ultralight EV1 (48 bytes)';
|
|
816
|
+
case 0x0E: return 'MIFARE Ultralight EV1 (128 bytes)';
|
|
817
|
+
default: return 'MIFARE Ultralight (unknown variant)';
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
return 'Unknown NFC tag';
|
|
585
821
|
}
|
|
586
822
|
|
|
587
823
|
};
|