community-cordova-plugin-nfc 1.3.0
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/.github/FUNDING.yml +2 -0
- package/CHANGES.txt +118 -0
- package/LICENSE.txt +21 -0
- package/README.md +1371 -0
- package/doc/GettingStartedBlackBerry10.md +64 -0
- package/doc/GettingStartedCLI.md +71 -0
- package/doc/GettingStartedPhoneGapBuild.md +77 -0
- package/doc/phonegap_build.png +0 -0
- package/doc/read_tag_1_basic_app.png +0 -0
- package/doc/read_tag_2_dump_tag.png +0 -0
- package/doc/read_tag_3_payload_as_string.png +0 -0
- package/package.json +33 -0
- package/plugin.xml +147 -0
- package/src/android/src/com/chariotsolutions/nfc/plugin/NfcPlugin.java +1020 -0
- package/src/android/src/com/chariotsolutions/nfc/plugin/Util.java +140 -0
- package/src/blackberry10/index.js +148 -0
- package/src/ios/NfcPlugin.h +40 -0
- package/src/ios/NfcPlugin.m +627 -0
- package/src/webworks/build.xml +24 -0
- package/src/webworks/src/com/chariotsolutions/nfc/plugin/NfcPlugin.java +341 -0
- package/src/webworks/src/com/chariotsolutions/nfc/plugin/Util.java +137 -0
- package/src/windows/nfc-plugin.js +285 -0
- package/src/windows-phone-8/Ndef.cs +191 -0
- package/src/windows-phone-8/NfcPlugin.cs +200 -0
- package/tests/package.json +14 -0
- package/tests/plugin.xml +11 -0
- package/tests/tests.js +135 -0
- package/www/phonegap-nfc-blackberry.js +76 -0
- package/www/phonegap-nfc.js +912 -0
|
@@ -0,0 +1,627 @@
|
|
|
1
|
+
//
|
|
2
|
+
// NfcPlugin.m
|
|
3
|
+
// PhoneGap NFC - Cordova Plugin
|
|
4
|
+
//
|
|
5
|
+
// (c) 2107-2020 Don Coleman
|
|
6
|
+
|
|
7
|
+
#import "NfcPlugin.h"
|
|
8
|
+
#import <CoreNFC/CoreNFC.h>
|
|
9
|
+
|
|
10
|
+
@interface NfcPlugin() {
|
|
11
|
+
NSString* sessionCallbackId;
|
|
12
|
+
NSString* channelCallbackId;
|
|
13
|
+
id<NFCNDEFTag> connectedTag API_AVAILABLE(ios(13.0));
|
|
14
|
+
NFCNDEFStatus connectedTagStatus API_AVAILABLE(ios(13.0));
|
|
15
|
+
}
|
|
16
|
+
@property (nonatomic, assign) BOOL writeMode;
|
|
17
|
+
@property (nonatomic, assign) BOOL shouldUseTagReaderSession;
|
|
18
|
+
@property (nonatomic, assign) BOOL sendCallbackOnSessionStart;
|
|
19
|
+
@property (nonatomic, assign) BOOL returnTagInCallback;
|
|
20
|
+
@property (nonatomic, assign) BOOL returnTagInEvent;
|
|
21
|
+
@property (nonatomic, assign) BOOL keepSessionOpen;
|
|
22
|
+
@property (strong, nonatomic) NFCReaderSession *nfcSession API_AVAILABLE(ios(11.0));
|
|
23
|
+
@property (strong, nonatomic) NFCNDEFMessage *messageToWrite API_AVAILABLE(ios(11.0));
|
|
24
|
+
@end
|
|
25
|
+
|
|
26
|
+
@implementation NfcPlugin
|
|
27
|
+
|
|
28
|
+
- (void)pluginInitialize {
|
|
29
|
+
|
|
30
|
+
NSLog(@"PhoneGap NFC - Cordova Plugin");
|
|
31
|
+
NSLog(@"(c) 2017-2020 Don Coleman");
|
|
32
|
+
|
|
33
|
+
[super pluginInitialize];
|
|
34
|
+
|
|
35
|
+
if (@available(iOS 11, *)) {
|
|
36
|
+
if (![NFCNDEFReaderSession readingAvailable]) {
|
|
37
|
+
NSLog(@"NFC Support is NOT available");
|
|
38
|
+
}
|
|
39
|
+
} else {
|
|
40
|
+
NSLog(@"NFC Support is NOT available before iOS 11");
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
#pragma mark - Cordova Plugin Methods
|
|
45
|
+
|
|
46
|
+
- (void)channel:(CDVInvokedUrlCommand *)command {
|
|
47
|
+
// the channel is used to send NFC tag data to the web view
|
|
48
|
+
channelCallbackId = [command.callbackId copy];
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
- (void)beginSession:(CDVInvokedUrlCommand*)command {
|
|
52
|
+
NSLog(@"beginSession");
|
|
53
|
+
NSLog(@"WARNING: beginSession is deprecated. Use scanNdef or scanTag.");
|
|
54
|
+
|
|
55
|
+
self.shouldUseTagReaderSession = NO;
|
|
56
|
+
self.sendCallbackOnSessionStart = YES; // Not sure why we were doing this
|
|
57
|
+
self.returnTagInCallback = NO;
|
|
58
|
+
self.returnTagInEvent = YES;
|
|
59
|
+
self.keepSessionOpen = NO;
|
|
60
|
+
|
|
61
|
+
[self startScanSession:command];
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
- (void)scanNdef:(CDVInvokedUrlCommand*)command {
|
|
65
|
+
NSLog(@"scanNdef");
|
|
66
|
+
|
|
67
|
+
self.shouldUseTagReaderSession = NO;
|
|
68
|
+
self.sendCallbackOnSessionStart = NO;
|
|
69
|
+
self.returnTagInCallback = YES;
|
|
70
|
+
self.returnTagInEvent = NO;
|
|
71
|
+
|
|
72
|
+
NSArray<NSDictionary *> *options = [command argumentAtIndex:0];
|
|
73
|
+
self.keepSessionOpen = [options valueForKey:@"keepSessionOpen"];
|
|
74
|
+
|
|
75
|
+
[self startScanSession:command];
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
- (void)scanTag:(CDVInvokedUrlCommand*)command {
|
|
79
|
+
NSLog(@"scanTag");
|
|
80
|
+
|
|
81
|
+
self.shouldUseTagReaderSession = YES;
|
|
82
|
+
self.sendCallbackOnSessionStart = NO;
|
|
83
|
+
self.returnTagInCallback = YES;
|
|
84
|
+
self.returnTagInEvent = NO;
|
|
85
|
+
|
|
86
|
+
NSArray<NSDictionary *> *options = [command argumentAtIndex:0];
|
|
87
|
+
self.keepSessionOpen = [options valueForKey:@"keepSessionOpen"];
|
|
88
|
+
|
|
89
|
+
[self startScanSession:command];
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
- (void)writeTag:(CDVInvokedUrlCommand*)command API_AVAILABLE(ios(13.0)){
|
|
93
|
+
NSLog(@"writeTag");
|
|
94
|
+
|
|
95
|
+
self.writeMode = YES;
|
|
96
|
+
self.shouldUseTagReaderSession = NO;
|
|
97
|
+
BOOL reusingSession = NO;
|
|
98
|
+
|
|
99
|
+
NSArray<NSDictionary *> *ndefData = [command argumentAtIndex:0];
|
|
100
|
+
|
|
101
|
+
// Create the NDEF Message
|
|
102
|
+
NSMutableArray<NFCNDEFPayload*> *payloads = [NSMutableArray new];
|
|
103
|
+
|
|
104
|
+
@try {
|
|
105
|
+
for (id recordData in ndefData) {
|
|
106
|
+
NSNumber *tnfNumber = [recordData objectForKey:@"tnf"];
|
|
107
|
+
NFCTypeNameFormat tnf = (uint8_t)[tnfNumber intValue];
|
|
108
|
+
NSData *type = [self uint8ArrayToNSData:[recordData objectForKey:@"type"]];
|
|
109
|
+
NSData *identifier = [self uint8ArrayToNSData:[recordData objectForKey:@"identifiers"]];
|
|
110
|
+
NSData *payload = [self uint8ArrayToNSData:[recordData objectForKey:@"payload"]];
|
|
111
|
+
NFCNDEFPayload *record = [[NFCNDEFPayload alloc] initWithFormat:tnf type:type identifier:identifier payload:payload];
|
|
112
|
+
[payloads addObject:record];
|
|
113
|
+
}
|
|
114
|
+
NSLog(@"%@", payloads);
|
|
115
|
+
NFCNDEFMessage *message = [[NFCNDEFMessage alloc] initWithNDEFRecords:payloads];
|
|
116
|
+
self.messageToWrite = message;
|
|
117
|
+
} @catch(NSException *e) {
|
|
118
|
+
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"Invalid NDEF Message"];
|
|
119
|
+
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (self.nfcSession && self.nfcSession.isReady) { // reuse existing session
|
|
124
|
+
reusingSession = YES;
|
|
125
|
+
} else { // create a new session
|
|
126
|
+
if (self.shouldUseTagReaderSession) {
|
|
127
|
+
NSLog(@"Using NFCTagReaderSession");
|
|
128
|
+
|
|
129
|
+
self.nfcSession = [[NFCTagReaderSession alloc]
|
|
130
|
+
initWithPollingOption:(NFCPollingISO14443 | NFCPollingISO15693)
|
|
131
|
+
delegate:self queue:dispatch_get_main_queue()];
|
|
132
|
+
|
|
133
|
+
} else {
|
|
134
|
+
NSLog(@"Using NFCTagReaderSession");
|
|
135
|
+
self.nfcSession = [[NFCNDEFReaderSession alloc]initWithDelegate:self queue:nil invalidateAfterFirstRead:FALSE];
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
self.nfcSession.alertMessage = [self localizeString:@"NFCHoldNearWritableTag" defaultValue:@"Hold near writable NFC tag to update."];
|
|
140
|
+
sessionCallbackId = [command.callbackId copy];
|
|
141
|
+
|
|
142
|
+
if (reusingSession) { // reusing a read session to write
|
|
143
|
+
self.keepSessionOpen = NO; // close session after writing
|
|
144
|
+
[self writeNDEFTag:self.nfcSession status:connectedTagStatus tag:connectedTag];
|
|
145
|
+
} else {
|
|
146
|
+
[self.nfcSession beginSession];
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
- (void)cancelScan:(CDVInvokedUrlCommand*)command API_AVAILABLE(ios(11.0)){
|
|
151
|
+
NSLog(@"cancelScan");
|
|
152
|
+
if (self.nfcSession) {
|
|
153
|
+
[self.nfcSession invalidateSession];
|
|
154
|
+
}
|
|
155
|
+
connectedTag = NULL;
|
|
156
|
+
connectedTagStatus = NFCNDEFStatusNotSupported;
|
|
157
|
+
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
|
|
158
|
+
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
- (void)invalidateSession:(CDVInvokedUrlCommand*)command {
|
|
162
|
+
NSLog(@"invalidateSession");
|
|
163
|
+
NSLog(@"WARNING: invalidateSession is deprecated. Use cancelScan.");
|
|
164
|
+
|
|
165
|
+
if (_nfcSession) {
|
|
166
|
+
[_nfcSession invalidateSession];
|
|
167
|
+
}
|
|
168
|
+
// Always return OK. Alternately could send status from the NFCNDEFReaderSessionDelegate
|
|
169
|
+
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
|
|
170
|
+
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Nothing happens here, the event listener is registered in JavaScript
|
|
174
|
+
- (void)registerNdef:(CDVInvokedUrlCommand *)command {
|
|
175
|
+
NSLog(@"registerNdef");
|
|
176
|
+
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
|
|
177
|
+
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Nothing happens here, the event listener is removed in JavaScript
|
|
181
|
+
- (void)removeNdef:(CDVInvokedUrlCommand *)command {
|
|
182
|
+
NSLog(@"removeNdef");
|
|
183
|
+
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
|
|
184
|
+
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
- (void)enabled:(CDVInvokedUrlCommand *)command {
|
|
188
|
+
NSLog(@"enabled");
|
|
189
|
+
CDVPluginResult *pluginResult;
|
|
190
|
+
if (@available(iOS 11.0, *)) {
|
|
191
|
+
if ([NFCNDEFReaderSession readingAvailable]) {
|
|
192
|
+
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
|
|
193
|
+
} else {
|
|
194
|
+
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"NO_NFC"];
|
|
195
|
+
}
|
|
196
|
+
} else {
|
|
197
|
+
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"NO_NFC"];
|
|
198
|
+
}
|
|
199
|
+
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
#pragma mark - NFCNDEFReaderSessionDelegate
|
|
203
|
+
|
|
204
|
+
// iOS 11 & 12
|
|
205
|
+
- (void) readerSession:(NFCNDEFReaderSession *)session didDetectNDEFs:(NSArray<NFCNDEFMessage *> *)messages API_AVAILABLE(ios(11.0)) {
|
|
206
|
+
NSLog(@"NFCNDEFReaderSession didDetectNDEFs");
|
|
207
|
+
|
|
208
|
+
session.alertMessage = [self localizeString:@"NFCTagRead" defaultValue:@"Tag successfully read."];
|
|
209
|
+
for (NFCNDEFMessage *message in messages) {
|
|
210
|
+
[self fireNdefEvent: message];
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// iOS 13
|
|
215
|
+
- (void) readerSession:(NFCNDEFReaderSession *)session didDetectTags:(NSArray<__kindof id<NFCNDEFTag>> *)tags API_AVAILABLE(ios(13.0)) {
|
|
216
|
+
|
|
217
|
+
if (tags.count > 1) {
|
|
218
|
+
session.alertMessage = [self localizeString:@"NFCMoreThanOneTag" defaultValue:@"More than 1 tag detected. Please remove all tags and try again."];
|
|
219
|
+
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 500 * NSEC_PER_MSEC), dispatch_get_main_queue(), ^{
|
|
220
|
+
NSLog(@"restaring polling");
|
|
221
|
+
[session restartPolling];
|
|
222
|
+
});
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
id<NFCNDEFTag> tag = [tags firstObject];
|
|
227
|
+
|
|
228
|
+
[session connectToTag:tag completionHandler:^(NSError * _Nullable error) {
|
|
229
|
+
if (error) {
|
|
230
|
+
NSLog(@"%@", error);
|
|
231
|
+
[self closeSession:session withError:[self localizeString:@"NFCErrorTagConnection" defaultValue:@"Error connecting to tag."]];
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
[self processNDEFTag:session tag:tag];
|
|
236
|
+
}];
|
|
237
|
+
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
- (void) readerSession:(NFCNDEFReaderSession *)session didInvalidateWithError:(NSError *)error API_AVAILABLE(ios(11.0)) {
|
|
241
|
+
NSLog(@"readerSession ended");
|
|
242
|
+
if (error.code == NFCReaderSessionInvalidationErrorFirstNDEFTagRead) { // not an error
|
|
243
|
+
NSLog(@"Session ended after successful NDEF tag read");
|
|
244
|
+
return;
|
|
245
|
+
} else {
|
|
246
|
+
[self sendError:error.localizedDescription];
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
- (void) readerSessionDidBecomeActive:(nonnull NFCReaderSession *)session API_AVAILABLE(ios(11.0)) {
|
|
251
|
+
NSLog(@"readerSessionDidBecomeActive");
|
|
252
|
+
[self sessionDidBecomeActive:session];
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
#pragma mark - NFCTagReaderSessionDelegate
|
|
256
|
+
|
|
257
|
+
- (void)tagReaderSessionDidBecomeActive:(NFCTagReaderSession *)session API_AVAILABLE(ios(13.0)) {
|
|
258
|
+
NSLog(@"tagReaderSessionDidBecomeActive");
|
|
259
|
+
[self sessionDidBecomeActive:session];
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
- (void)tagReaderSession:(NFCTagReaderSession *)session didDetectTags:(NSArray<__kindof id<NFCTag>> *)tags API_AVAILABLE(ios(13.0)) {
|
|
263
|
+
NSLog(@"tagReaderSession didDetectTags");
|
|
264
|
+
|
|
265
|
+
if (tags.count > 1) {
|
|
266
|
+
session.alertMessage = [self localizeString:@"NFCMoreThanOneTag" defaultValue:@"More than 1 tag detected. Please remove all tags and try again."];
|
|
267
|
+
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 500 * NSEC_PER_MSEC), dispatch_get_main_queue(), ^{
|
|
268
|
+
NSLog(@"restaring polling");
|
|
269
|
+
[session restartPolling];
|
|
270
|
+
});
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
id<NFCTag> tag = [tags firstObject];
|
|
275
|
+
NSMutableDictionary *tagMetaData = [self getTagInfo:tag];
|
|
276
|
+
id<NFCNDEFTag> ndefTag = (id<NFCNDEFTag>)tag;
|
|
277
|
+
|
|
278
|
+
[session connectToTag:tag completionHandler:^(NSError * _Nullable error) {
|
|
279
|
+
if (error) {
|
|
280
|
+
NSLog(@"%@", error);
|
|
281
|
+
[self closeSession:session withError:[self localizeString:@"NFCErrorTagConnection" defaultValue:@"Error connecting to tag."]];
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
[self processNDEFTag:session tag:ndefTag metaData:tagMetaData];
|
|
286
|
+
}];
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
- (void)tagReaderSession:(NFCTagReaderSession *)session didInvalidateWithError:(NSError *)error API_AVAILABLE(ios(13.0)) {
|
|
290
|
+
NSLog(@"tagReaderSession ended");
|
|
291
|
+
[self sendError:error.localizedDescription];
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
#pragma mark - Common NDEF Processing
|
|
295
|
+
|
|
296
|
+
// Handles scanNdef, scanTag, and beginSession
|
|
297
|
+
- (void)startScanSession:(CDVInvokedUrlCommand*)command {
|
|
298
|
+
|
|
299
|
+
self.writeMode = NO;
|
|
300
|
+
|
|
301
|
+
NSLog(@"shouldUseTagReaderSession %d", self.shouldUseTagReaderSession);
|
|
302
|
+
NSLog(@"callbackOnSessionStart %d", self.sendCallbackOnSessionStart);
|
|
303
|
+
NSLog(@"returnTagInCallback %d", self.returnTagInCallback);
|
|
304
|
+
NSLog(@"returnTagInEvent %d", self.returnTagInEvent);
|
|
305
|
+
|
|
306
|
+
if (@available(iOS 13.0, *)) {
|
|
307
|
+
|
|
308
|
+
if (self.shouldUseTagReaderSession) {
|
|
309
|
+
NSLog(@"Using NFCTagReaderSession");
|
|
310
|
+
self.nfcSession = [[NFCTagReaderSession alloc]
|
|
311
|
+
initWithPollingOption:(NFCPollingISO14443 | NFCPollingISO15693)
|
|
312
|
+
delegate:self queue:dispatch_get_main_queue()];
|
|
313
|
+
} else {
|
|
314
|
+
NSLog(@"Using NFCNDEFReaderSession");
|
|
315
|
+
self.nfcSession = [[NFCNDEFReaderSession alloc]initWithDelegate:self queue:nil invalidateAfterFirstRead:TRUE];
|
|
316
|
+
}
|
|
317
|
+
sessionCallbackId = [command.callbackId copy];
|
|
318
|
+
self.nfcSession.alertMessage = [self localizeString:@"NFCHoldNearTag" defaultValue:@"Hold near NFC tag to scan."];
|
|
319
|
+
[self.nfcSession beginSession];
|
|
320
|
+
|
|
321
|
+
} else if (@available(iOS 11.0, *)) {
|
|
322
|
+
NSLog(@"iOS < 13, using NFCNDEFReaderSession");
|
|
323
|
+
self.nfcSession = [[NFCNDEFReaderSession alloc]initWithDelegate:self queue:nil invalidateAfterFirstRead:TRUE];
|
|
324
|
+
sessionCallbackId = [command.callbackId copy];
|
|
325
|
+
self.nfcSession.alertMessage = [self localizeString:@"NFCHoldNearTag" defaultValue:@"Hold near NFC tag to scan."];
|
|
326
|
+
[self.nfcSession beginSession];
|
|
327
|
+
} else {
|
|
328
|
+
NSLog(@"iOS < 11, no NFC support");
|
|
329
|
+
CDVPluginResult *pluginResult;
|
|
330
|
+
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"NFC requires iOS 11"];
|
|
331
|
+
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
- (void)processNDEFTag: (NFCReaderSession *)session tag:(__kindof id<NFCNDEFTag>)tag API_AVAILABLE(ios(13.0)) {
|
|
337
|
+
[self processNDEFTag:session tag:tag metaData:[NSMutableDictionary new]];
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
- (void)processNDEFTag: (NFCReaderSession *)session tag:(__kindof id<NFCNDEFTag>)tag metaData: (NSMutableDictionary * _Nonnull)metaData API_AVAILABLE(ios(13.0)) {
|
|
341
|
+
|
|
342
|
+
[tag queryNDEFStatusWithCompletionHandler:^(NFCNDEFStatus status, NSUInteger capacity, NSError * _Nullable error) {
|
|
343
|
+
if (error) {
|
|
344
|
+
NSLog(@"%@", error);
|
|
345
|
+
[self closeSession:session withError:[self localizeString:@"NFCErrorTagStatus" defaultValue:@"Error getting tag status."]];
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
if (self.writeMode) {
|
|
350
|
+
[self writeNDEFTag:session status:status tag:tag];
|
|
351
|
+
} else {
|
|
352
|
+
// save tag & status so we can re-use in write
|
|
353
|
+
if (self.keepSessionOpen) {
|
|
354
|
+
self->connectedTagStatus = status;
|
|
355
|
+
self->connectedTag = tag;
|
|
356
|
+
}
|
|
357
|
+
[self readNDEFTag:session status:status tag:tag metaData:metaData];
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
}];
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
- (void)readNDEFTag:(NFCReaderSession * _Nonnull)session status:(NFCNDEFStatus)status tag:(id<NFCNDEFTag>)tag metaData:(NSMutableDictionary * _Nonnull)metaData API_AVAILABLE(ios(13.0)){
|
|
364
|
+
|
|
365
|
+
if (status == NFCNDEFStatusNotSupported) {
|
|
366
|
+
NSLog(@"Tag does not support NDEF");
|
|
367
|
+
[self fireTagEvent:metaData];
|
|
368
|
+
[self closeSession:session];
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
if (status == NFCNDEFStatusReadOnly) {
|
|
373
|
+
metaData[@"isWritable"] = @FALSE;
|
|
374
|
+
} else if (status == NFCNDEFStatusReadWrite) {
|
|
375
|
+
metaData[@"isWritable"] = @TRUE;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
[tag readNDEFWithCompletionHandler:^(NFCNDEFMessage * _Nullable message, NSError * _Nullable error) {
|
|
379
|
+
|
|
380
|
+
// Error Code=403 "NDEF tag does not contain any NDEF message" is not an error for this plugin
|
|
381
|
+
if (error && error.code != 403) {
|
|
382
|
+
NSLog(@"%@", error);
|
|
383
|
+
[self closeSession:session withError:[self localizeString:@"NFCDataReadFailed" defaultValue:@"Read Failed."]];
|
|
384
|
+
return;
|
|
385
|
+
} else {
|
|
386
|
+
NSLog(@"%@", message);
|
|
387
|
+
session.alertMessage = [self localizeString:@"NFCTagRead" defaultValue:@"Tag successfully read."];
|
|
388
|
+
[self fireNdefEvent:message metaData:metaData];
|
|
389
|
+
[self closeSession:session];
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
}];
|
|
393
|
+
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
- (void)writeNDEFTag:(NFCReaderSession * _Nonnull)session status:(NFCNDEFStatus)status tag:(id<NFCNDEFTag>)tag API_AVAILABLE(ios(13.0)){
|
|
397
|
+
switch (status) {
|
|
398
|
+
case NFCNDEFStatusNotSupported:
|
|
399
|
+
[self closeSession:session withError:[self localizeString:@"NFCNotNdefCompliant" defaultValue:@"Tag is not NDEF compliant."]]; // alternate message "Tag does not support NDEF."
|
|
400
|
+
break;
|
|
401
|
+
case NFCNDEFStatusReadOnly:
|
|
402
|
+
[self closeSession:session withError:[self localizeString:@"NFCReadOnlyTag" defaultValue:@"Tag is read only."]];
|
|
403
|
+
break;
|
|
404
|
+
case NFCNDEFStatusReadWrite: {
|
|
405
|
+
|
|
406
|
+
[tag writeNDEF: self.messageToWrite completionHandler:^(NSError * _Nullable error) {
|
|
407
|
+
if (error) {
|
|
408
|
+
NSLog(@"%@", error);
|
|
409
|
+
[self closeSession:session withError:[self localizeString:@"NFCDataWriteFailed" defaultValue:@"Write failed."]];
|
|
410
|
+
} else {
|
|
411
|
+
session.alertMessage = [self localizeString:@"NFCDataWrote" defaultValue:@"Wrote data to NFC tag."];
|
|
412
|
+
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
|
|
413
|
+
[self.commandDelegate sendPluginResult:pluginResult callbackId:self->sessionCallbackId];
|
|
414
|
+
[self closeSession:session];
|
|
415
|
+
}
|
|
416
|
+
}];
|
|
417
|
+
break;
|
|
418
|
+
|
|
419
|
+
}
|
|
420
|
+
default:
|
|
421
|
+
[self closeSession:session withError:[self localizeString:@"NFCUnknownNdefTag" defaultValue:@"Unknown NDEF tag status."]];
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
#pragma mark - Tag Reader Helper Functions
|
|
426
|
+
|
|
427
|
+
// Gets the tag meta data - type and uid
|
|
428
|
+
- (NSMutableDictionary *) getTagInfo:(id<NFCTag>)tag API_AVAILABLE(ios(13.0)) {
|
|
429
|
+
|
|
430
|
+
NSMutableDictionary *tagInfo = [NSMutableDictionary new];
|
|
431
|
+
|
|
432
|
+
NSData *uid;
|
|
433
|
+
NSString *type;
|
|
434
|
+
|
|
435
|
+
switch (tag.type) {
|
|
436
|
+
case NFCTagTypeFeliCa:
|
|
437
|
+
type = @"NFCTagTypeFeliCa";
|
|
438
|
+
uid = nil;
|
|
439
|
+
break;
|
|
440
|
+
case NFCTagTypeMiFare:
|
|
441
|
+
type = @"NFCTagTypeMiFare";
|
|
442
|
+
uid = [[tag asNFCMiFareTag] identifier];
|
|
443
|
+
break;
|
|
444
|
+
case NFCTagTypeISO15693:
|
|
445
|
+
type = @"NFCTagTypeISO15693";
|
|
446
|
+
uid = [[tag asNFCISO15693Tag] identifier];
|
|
447
|
+
break;
|
|
448
|
+
case NFCTagTypeISO7816Compatible:
|
|
449
|
+
type = @"NFCTagTypeISO7816Compatible";
|
|
450
|
+
uid = [[tag asNFCISO7816Tag] identifier];
|
|
451
|
+
break;
|
|
452
|
+
default:
|
|
453
|
+
type = @"Unknown";
|
|
454
|
+
uid = nil;
|
|
455
|
+
break;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
NSLog(@"getTagInfo: %@ with uid %@", type, uid);
|
|
459
|
+
|
|
460
|
+
[tagInfo setValue:type forKey:@"type"];
|
|
461
|
+
if (uid) {
|
|
462
|
+
[tagInfo setValue:uid forKey:@"id"];
|
|
463
|
+
}
|
|
464
|
+
return tagInfo;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
#pragma mark - internal implementation
|
|
468
|
+
|
|
469
|
+
- (void) sendError:(NSString *)message {
|
|
470
|
+
// only send the error if the callback id exists
|
|
471
|
+
if (sessionCallbackId) {
|
|
472
|
+
NSLog(@"sendError: %@", message);
|
|
473
|
+
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:message];
|
|
474
|
+
[self.commandDelegate sendPluginResult:pluginResult callbackId:sessionCallbackId];
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
- (void) sessionDidBecomeActive:(NFCReaderSession *) session API_AVAILABLE(ios(11.0)){
|
|
479
|
+
if (sessionCallbackId && self.sendCallbackOnSessionStart) {
|
|
480
|
+
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
|
|
481
|
+
[pluginResult setKeepCallback:@YES];
|
|
482
|
+
[self.commandDelegate sendPluginResult:pluginResult callbackId:sessionCallbackId];
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
- (void) closeSession:(NFCReaderSession *) session API_AVAILABLE(ios(11.0)){
|
|
487
|
+
|
|
488
|
+
// this is a hack to keep a read session open to allow writing
|
|
489
|
+
if (self.keepSessionOpen) {
|
|
490
|
+
return;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
// kill the callback so the Cordova doesn't get "Session invalidated by user"
|
|
494
|
+
sessionCallbackId = NULL;
|
|
495
|
+
connectedTag = NULL;
|
|
496
|
+
connectedTagStatus = NFCNDEFStatusNotSupported;
|
|
497
|
+
[session invalidateSession];
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
- (void) closeSession:(NFCReaderSession *) session withError:(NSString *) errorMessage API_AVAILABLE(ios(11.0)){
|
|
501
|
+
[self sendError:errorMessage];
|
|
502
|
+
|
|
503
|
+
// kill the callback so Cordova doesn't get "Session invalidated by user"
|
|
504
|
+
sessionCallbackId = NULL;
|
|
505
|
+
connectedTag = NULL;
|
|
506
|
+
connectedTagStatus = NFCNDEFStatusNotSupported;
|
|
507
|
+
|
|
508
|
+
if (@available(iOS 13.0, *)) {
|
|
509
|
+
[session invalidateSessionWithErrorMessage:errorMessage];
|
|
510
|
+
} else {
|
|
511
|
+
[session invalidateSession];
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
-(void) fireTagEvent:(NSDictionary *)metaData API_AVAILABLE(ios(11.0)) {
|
|
516
|
+
// Data is from a tag, but still ends up as an NDEF event in Javascript
|
|
517
|
+
[self fireNdefEvent:nil metaData:metaData];
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
-(void) fireNdefEvent:(NFCNDEFMessage *) ndefMessage API_AVAILABLE(ios(11.0)) {
|
|
521
|
+
[self fireNdefEvent:ndefMessage metaData:nil];
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
// TODO rename method since we're using the channel or callback instead of firing an event
|
|
525
|
+
-(void) fireNdefEvent:(NFCNDEFMessage *) ndefMessage metaData:(NSDictionary *)metaData API_AVAILABLE(ios(11.0)) {
|
|
526
|
+
NSLog(@"fireNdefEvent");
|
|
527
|
+
|
|
528
|
+
NSMutableDictionary *nfcEvent = [NSMutableDictionary new];
|
|
529
|
+
nfcEvent[@"type"] = @"ndef";
|
|
530
|
+
nfcEvent[@"tag"] = [self buildTagDictionary:ndefMessage metaData:metaData];
|
|
531
|
+
|
|
532
|
+
if (sessionCallbackId && self.returnTagInCallback) {
|
|
533
|
+
NSLog(@"Sending NFC data via sessionCallbackId");
|
|
534
|
+
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:nfcEvent[@"tag"]];
|
|
535
|
+
// [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]];
|
|
536
|
+
[self.commandDelegate sendPluginResult:pluginResult callbackId:sessionCallbackId];
|
|
537
|
+
sessionCallbackId = NULL;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
if (channelCallbackId && self.returnTagInEvent) {
|
|
541
|
+
NSLog(@"Sending NFC data via channelCallbackId so an NDEF event fires)");
|
|
542
|
+
|
|
543
|
+
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:nfcEvent];
|
|
544
|
+
[pluginResult setKeepCallback:[NSNumber numberWithBool:YES]];
|
|
545
|
+
[self.commandDelegate sendPluginResult:pluginResult callbackId:channelCallbackId];
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
// NSDictionary representing an NFC tag
|
|
550
|
+
// NSData fields are converted to uint8_t arrays
|
|
551
|
+
-(NSDictionary *) buildTagDictionary:(NFCNDEFMessage *) ndefMessage metaData: (NSDictionary *)metaData API_AVAILABLE(ios(11.0)) {
|
|
552
|
+
|
|
553
|
+
NSMutableDictionary *dictionary = [NSMutableDictionary new];
|
|
554
|
+
|
|
555
|
+
// start with tag meta data
|
|
556
|
+
if (metaData) {
|
|
557
|
+
[dictionary setDictionary:metaData];
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
// convert uid from NSData to a uint8_t array
|
|
561
|
+
NSData *uid = [dictionary objectForKey:@"id"];
|
|
562
|
+
if (uid) {
|
|
563
|
+
dictionary[@"id"] = [self uint8ArrayFromNSData: uid];
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
if (ndefMessage) {
|
|
567
|
+
NSMutableArray *array = [NSMutableArray new];
|
|
568
|
+
for (NFCNDEFPayload *record in ndefMessage.records){
|
|
569
|
+
NSDictionary* recordDictionary = [self ndefRecordToNSDictionary:record];
|
|
570
|
+
[array addObject:recordDictionary];
|
|
571
|
+
}
|
|
572
|
+
[dictionary setObject:array forKey:@"ndefMessage"];
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
return [dictionary copy];
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
-(NSDictionary *) ndefRecordToNSDictionary:(NFCNDEFPayload *) ndefRecord API_AVAILABLE(ios(11.0)) {
|
|
579
|
+
NSMutableDictionary *dict = [NSMutableDictionary new];
|
|
580
|
+
dict[@"tnf"] = [NSNumber numberWithInt:(int)ndefRecord.typeNameFormat];
|
|
581
|
+
dict[@"type"] = [self uint8ArrayFromNSData: ndefRecord.type];
|
|
582
|
+
dict[@"id"] = [self uint8ArrayFromNSData: ndefRecord.identifier];
|
|
583
|
+
dict[@"payload"] = [self uint8ArrayFromNSData: ndefRecord.payload];
|
|
584
|
+
NSDictionary *copy = [dict copy];
|
|
585
|
+
return copy;
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
- (NSArray *) uint8ArrayFromNSData:(NSData *) data {
|
|
589
|
+
const void *bytes = [data bytes];
|
|
590
|
+
NSMutableArray *array = [NSMutableArray array];
|
|
591
|
+
for (NSUInteger i = 0; i < [data length]; i += sizeof(uint8_t)) {
|
|
592
|
+
uint8_t elem = OSReadLittleInt(bytes, i);
|
|
593
|
+
[array addObject:[NSNumber numberWithInt:elem]];
|
|
594
|
+
}
|
|
595
|
+
return array;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
- (NSData *) uint8ArrayToNSData:(NSArray *) array {
|
|
599
|
+
// NSLog(@"nsDataFromUint8Array input %@", array);
|
|
600
|
+
|
|
601
|
+
NSMutableData *data = [[NSMutableData alloc] initWithCapacity: [array count]];
|
|
602
|
+
for (NSNumber *number in array) {
|
|
603
|
+
uint8_t b = (uint8_t)[number unsignedIntValue];
|
|
604
|
+
// NSLog(@"> %hhu", b);
|
|
605
|
+
[data appendBytes:&b length:1];
|
|
606
|
+
}
|
|
607
|
+
return data;
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
- (NSString*) dictionaryAsJSONString:(NSDictionary *)dict {
|
|
611
|
+
NSError *error;
|
|
612
|
+
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dict options:0 error:&error];
|
|
613
|
+
NSString *jsonString;
|
|
614
|
+
if (! jsonData) {
|
|
615
|
+
jsonString = [NSString stringWithFormat:@"Error creating JSON for NDEF Message: %@", error];
|
|
616
|
+
NSLog(@"%@", jsonString);
|
|
617
|
+
} else {
|
|
618
|
+
jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
|
|
619
|
+
}
|
|
620
|
+
return jsonString;
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
- (NSString*) localizeString:(NSString *)key defaultValue:(NSString*) defaultValue {
|
|
624
|
+
return NSLocalizedString(key, comment: "") != key ? NSLocalizedString(key, comment: "") : defaultValue;
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
@end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<?xml version="1.0"?>
|
|
2
|
+
<project name="PhoneGap NFC Plugin Webworks" default="dist" basedir=".">
|
|
3
|
+
|
|
4
|
+
<property name="platform" value="webworks"/>
|
|
5
|
+
<property name="src.dir" location="src"/>
|
|
6
|
+
<property name="dist.dir" location="../../dist"/>
|
|
7
|
+
<property name="www.dir" location="../../www"/>
|
|
8
|
+
|
|
9
|
+
<target name="jar" description="build a new version of phonegap-nfc.jar">
|
|
10
|
+
<jar destfile="${dist.dir}/phonegap-nfc-${platform}.jar" basedir="${src.dir}"/>
|
|
11
|
+
</target>
|
|
12
|
+
|
|
13
|
+
<target name="javascript" description="copy javascript to dist directory">
|
|
14
|
+
<copy file="${www.dir}/phonegap-nfc.js" todir="${dist.dir}"/>
|
|
15
|
+
</target>
|
|
16
|
+
|
|
17
|
+
<target name="dist" depends="jar,javascript" description="jar and js for distribution">
|
|
18
|
+
<echo>Built phonegap-nfc-${platform} for distribution</echo>
|
|
19
|
+
</target>
|
|
20
|
+
|
|
21
|
+
<target name="clean" description="clean up">
|
|
22
|
+
<delete dir="${dist.dir}"/>
|
|
23
|
+
</target>
|
|
24
|
+
</project>
|