diff --git a/package.json b/package.json index 47ea5fa9..076d254b 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,9 @@ { - "name": "phonegap-nfc", - "version": "1.2.0", + "name": "ziath-phonegap-nfc", + "version": "1.2.5", "description": "Near Field Communication (NFC) Plugin. Read and write NDEF messages to NFC tags and share NDEF messages with peers.", "cordova": { - "id": "phonegap-nfc", + "id": "ziath-phonegap-nfc", "platforms": [ "android", "wp8", @@ -14,7 +14,7 @@ }, "repository": { "type": "git", - "url": "git+https://github.com/chariotsolutions/phonegap-nfc.git" + "url": "git+https://github.com/ZiathLtd/ziath-phonegap-nfc.git" }, "keywords": [ "nfc", @@ -30,7 +30,7 @@ "author": "Don Coleman ", "license": "MIT", "bugs": { - "url": "https://github.com/chariotsolutions/phonegap-nfc/issues" + "url": "https://github.com/ZiathLtd/ziath-phonegap-nfc/issues" }, - "homepage": "https://github.com/chariotsolutions/phonegap-nfc#readme" + "homepage": "https://github.com/ZiathLtd/ziath-phonegap-nfc#readme" } diff --git a/plugin.xml b/plugin.xml index d2dddbe4..9e6ca01f 100644 --- a/plugin.xml +++ b/plugin.xml @@ -2,8 +2,8 @@ + id="ziath-phonegap-nfc" + version="1.2.5"> NFC @@ -11,8 +11,8 @@ MIT nfc, NFC, NDEF - https://github.com/chariotsolutions/phonegap-nfc.git - https://github.com/chariotsolutions/phonegap-nfc/issues + https://github.com/ZiathLtd/ziath-phonegap-nfc.git + https://github.com/ZiathLtd/ziath-phonegap-nfc/issues diff --git a/src/android/src/com/chariotsolutions/nfc/plugin/NfcPlugin.java b/src/android/src/com/chariotsolutions/nfc/plugin/NfcPlugin.java index e8256d83..e5f2cba8 100644 --- a/src/android/src/com/chariotsolutions/nfc/plugin/NfcPlugin.java +++ b/src/android/src/com/chariotsolutions/nfc/plugin/NfcPlugin.java @@ -339,7 +339,7 @@ private void writeTag(JSONArray data, CallbackContext callbackContext) throws JS callbackContext.error("Failed to write tag, received null intent"); } - Tag tag = savedIntent.getParcelableExtra(NfcAdapter.EXTRA_TAG); + Tag tag = getIntent().getParcelableExtra(NfcAdapter.EXTRA_TAG); NdefRecord[] records = Util.jsonToNdefRecords(data.getString(0)); writeNdefMessage(new NdefMessage(records), tag, callbackContext); } @@ -347,6 +347,10 @@ private void writeTag(JSONArray data, CallbackContext callbackContext) throws JS private void writeNdefMessage(final NdefMessage message, final Tag tag, final CallbackContext callbackContext) { cordova.getThreadPool().execute(() -> { try { + if(tag == null) + { + throw new TagLostException("Tag is Null"); + } Ndef ndef = Ndef.get(tag); if (ndef != null) { ndef.connect(); @@ -483,7 +487,7 @@ private void createPendingIntent() { Activity activity = getActivity(); Intent intent = new Intent(activity, activity.getClass()); intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP); - pendingIntent = PendingIntent.getActivity(activity, 0, intent, 0); + pendingIntent = PendingIntent.getActivity(activity, 0, intent, PendingIntent.FLAG_IMMUTABLE); } } diff --git a/src/ios/NfcPlugin.h b/src/ios/NfcPlugin.h index 46391af1..9611e61a 100644 --- a/src/ios/NfcPlugin.h +++ b/src/ios/NfcPlugin.h @@ -34,6 +34,7 @@ // Internal implementation - (void)channel:(CDVInvokedUrlCommand *)command; +//- (void)transceive:(CDVInvokedUrlCommand *)command; @end diff --git a/src/ios/NfcPlugin.m b/src/ios/NfcPlugin.m index 9b40f251..c2e77a3c 100644 --- a/src/ios/NfcPlugin.m +++ b/src/ios/NfcPlugin.m @@ -12,6 +12,7 @@ @interface NfcPlugin() { id connectedTag API_AVAILABLE(ios(13.0)); NFCNDEFStatus connectedTagStatus API_AVAILABLE(ios(13.0)); } + @property (nonatomic, assign) BOOL writeMode; @property (nonatomic, assign) BOOL shouldUseTagReaderSession; @property (nonatomic, assign) BOOL sendCallbackOnSessionStart; @@ -98,7 +99,7 @@ - (void)writeTag:(CDVInvokedUrlCommand*)command API_AVAILABLE(ios(13.0)){ NSArray *ndefData = [command argumentAtIndex:0]; // Create the NDEF Message - NSMutableArray *payloads = [NSMutableArray new]; + NSMutableArray *payloads = [[NSMutableArray alloc] init]; @try { for (id recordData in ndefData) { @@ -125,13 +126,13 @@ - (void)writeTag:(CDVInvokedUrlCommand*)command API_AVAILABLE(ios(13.0)){ if (self.shouldUseTagReaderSession) { NSLog(@"Using NFCTagReaderSession"); - self.nfcSession = [[NFCTagReaderSession new] + self.nfcSession = [[NFCTagReaderSession alloc] initWithPollingOption:(NFCPollingISO14443 | NFCPollingISO15693) delegate:self queue:dispatch_get_main_queue()]; } else { NSLog(@"Using NFCTagReaderSession"); - self.nfcSession = [[NFCNDEFReaderSession new]initWithDelegate:self queue:nil invalidateAfterFirstRead:FALSE]; + self.nfcSession = [[NFCNDEFReaderSession alloc]initWithDelegate:self queue:nil invalidateAfterFirstRead:FALSE]; } } @@ -211,7 +212,8 @@ - (void) readerSession:(NFCNDEFReaderSession *)session didDetectNDEFs:(NSArray> *)tags API_AVAILABLE(ios(13.0)) { +- (void) readerSession:(NFCTagReaderSession *)session didDetectTags:(NSArray<__kindof id> *)tags API_AVAILABLE(ios(13.0)) { + NSLog(@"ReaderSession didDetectTags"); if (tags.count > 1) { session.alertMessage = @"More than 1 tag detected. Please remove all tags and try again."; @@ -222,27 +224,63 @@ - (void) readerSession:(NFCNDEFReaderSession *)session didDetectTags:(NSArray<__ return; } - id tag = [tags firstObject]; - + id tag = tags[0]; + NSLog(@"Got the Tag"); [session connectToTag:tag completionHandler:^(NSError * _Nullable error) { if (error) { NSLog(@"%@", error); [self closeSession:session withError:@"Error connecting to tag."]; return; } - - [self processNDEFTag:session tag:tag]; + NSLog(@"Tag Connected with session"); + if([tag conformsToProtocol:@protocol(NFCNDEFTag)]) + { + NSLog(@"Tag Confirms to NFCNDEFTag Protocol"); + id ndefTag = (id)tag; + [self processNDEFTag:session tag:ndefTag]; + } else if([tag conformsToProtocol:@protocol(NFCISO15693Tag)]) + { + NSLog(@"Tag Confirms to ISO15693 Protocol"); + id iso15693Tag = (id)tag; + + //read a single block + if (@available(iOS 14.0, *)) { + [iso15693Tag readSingleBlockWithRequestFlags:NFCISO15693RequestFlagDualSubCarriers blockNumber:0 completionHandler:^(NSData *dataBlock, NSError *error) { + NSLog(@"Read Single Block Invoked"); + if(error) + { + NSLog(@"Error Recieved in : Read Single Block"); + [self handleError:error]; + } else { + NSLog(@"Processing Result : Read Single Block"); + NSString *dataString = [dataBlock base64EncodedStringWithOptions:0]; + CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:dataString]; + [self.commandDelegate sendPluginResult:pluginResult callbackId:self->sessionCallbackId]; + } + [session invalidateSession]; + }]; + } else { + // Fallback on earlier versions + } + } }]; } -- (void) readerSession:(NFCNDEFReaderSession *)session didInvalidateWithError:(NSError *)error API_AVAILABLE(ios(11.0)) { +- (void) readerSession:(NFCReaderSession *)session didInvalidateWithError:(NSError *)error API_AVAILABLE(ios(11.0)) { NSLog(@"readerSession ended"); - if (error.code == NFCReaderSessionInvalidationErrorFirstNDEFTagRead) { // not an error - NSLog(@"Session ended after successful NDEF tag read"); - return; - } else { - [self sendError:error.localizedDescription]; + if([session isKindOfClass:[NFCISO15693ReaderSession class]]) + { + [self handleError:error]; + } + else if ([session isKindOfClass:[NFCNDEFReaderSession class]]) + { + if (error.code == NFCReaderSessionInvalidationErrorFirstNDEFTagRead) { // not an error + NSLog(@"Session ended after successful NDEF tag read"); + return; + } else { + [self sendError:error.localizedDescription]; + } } } @@ -258,9 +296,27 @@ - (void)tagReaderSessionDidBecomeActive:(NFCTagReaderSession *)session API_AVAIL [self sessionDidBecomeActive:session]; } +- (NSString *)createJSONStringWithMessage:(NSString *)message isProcessCompleted:(BOOL)isProcessCompleted{ + NSDictionary *responseDict = @{ + @"message": message, + @"isProcessCompleted": @(isProcessCompleted) + }; + + NSError *error; + NSData *jsonData = [NSJSONSerialization dataWithJSONObject:responseDict options:0 error:&error]; + if(!jsonData){ + NSLog(@"Failed to serialize JSON: %@",error); + return nil; + } else { + NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; + NSLog(@"Encoded JSON String: %@",jsonString); + return jsonString; + } +} + - (void)tagReaderSession:(NFCTagReaderSession *)session didDetectTags:(NSArray<__kindof id> *)tags API_AVAILABLE(ios(13.0)) { NSLog(@"tagReaderSession didDetectTags"); - + if (tags.count > 1) { session.alertMessage = @"More than 1 tag detected. Please remove all tags and try again."; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 500 * NSEC_PER_MSEC), dispatch_get_main_queue(), ^{ @@ -269,21 +325,120 @@ - (void)tagReaderSession:(NFCTagReaderSession *)session didDetectTags:(NSArray<_ }); return; } - - id tag = [tags firstObject]; + + id tag = tags[0]; NSMutableDictionary *tagMetaData = [self getTagInfo:tag]; - id ndefTag = (id)tag; - + + NSLog(@"Got the Tag"); [session connectToTag:tag completionHandler:^(NSError * _Nullable error) { if (error) { NSLog(@"%@", error); [self closeSession:session withError:@"Error connecting to tag."]; return; } + NSLog(@"Tag Connected with session"); + if([tag conformsToProtocol:@protocol(NFCISO15693Tag)]) + { + NSString *initialMessage = [self createJSONStringWithMessage:@"Connected" isProcessCompleted:NO]; + CDVPluginResult *initialResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_NO_RESULT messageAsString:initialMessage]; + [initialResult setKeepCallbackAsBool:YES]; + [self.commandDelegate sendPluginResult:initialResult callbackId:self->sessionCallbackId]; + dispatch_group_t readGroup = dispatch_group_create(); + NSMutableData *consolidatedData = [NSMutableData data]; + [self sendMessageToJavaScript:@"Connected"]; + NSLog(@"Tag Confirms to ISO15693 Protocol"); + id iso15693Tag = (id)tag; + __block NSInteger blockNumber = 0; + __block NSInteger errCount = 0; + NSInteger totalNumberOfBlocks = 247; + __block BOOL hasCompleted = NO; + __block NSInteger oldProgressUpdate = -1; + void (^readNextBlock)(void) = ^{ + if (blockNumber < totalNumberOfBlocks) { + dispatch_group_enter(readGroup); + [iso15693Tag readSingleBlockWithRequestFlags:NFCISO15693RequestFlagHighDataRate blockNumber:blockNumber completionHandler:^(NSData *dataBlock, NSError *error) { + NSLog(@"Read Single Block Invoked for block %ld", (long)blockNumber); + if (error) { + NSLog(@"Error Recieved in : Read Single Block"); + [self sendDisconnectMessage:@"Disconnected"]; + dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW, 1000 * NSEC_PER_MSEC); + dispatch_after(delay, dispatch_get_main_queue(), ^{ + NSLog(@"retrying after 1 sec"); + errCount++; + }); + if(errCount>=10) + { + blockNumber = 249; + [self handleError:error]; + // No data read + NSString *dataString = @"No Data Read"; + NSString *finalMessage = [self createJSONStringWithMessage:dataString isProcessCompleted:NO]; + CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:dataString]; + [self.commandDelegate sendPluginResult:pluginResult callbackId:self->sessionCallbackId]; + [session invalidateSession]; + } + } else { + //NSLog(@"Processing Result : Read Single Block"); + + [consolidatedData appendData:dataBlock]; + blockNumber++; + errCount = 0; + NSInteger progressUpdate = (blockNumber * 100) / totalNumberOfBlocks; + if(progressUpdate % 10 ==0 && (progressUpdate != oldProgressUpdate)) { + oldProgressUpdate = progressUpdate; + [self sendProgressUpdateToJavaScript:progressUpdate]; + } + } + dispatch_group_leave(readGroup); + }]; + } else if(!hasCompleted) { + hasCompleted = YES; + if ([consolidatedData length] > 0) { + NSData *data = [consolidatedData copy]; + NSString *dataString = [data base64EncodedStringWithOptions:0]; + NSString *finalMessage = [self createJSONStringWithMessage:dataString isProcessCompleted:YES]; + CDVPluginResult *finalResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:finalMessage]; + [self.commandDelegate sendPluginResult:finalResult callbackId:self->sessionCallbackId]; + } else { + // No data read + NSString *dataString = @"No Data Read"; + NSString *finalMessage = [self createJSONStringWithMessage:dataString isProcessCompleted:NO]; + CDVPluginResult *finalResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:finalMessage]; + [self.commandDelegate sendPluginResult:finalResult callbackId:self->sessionCallbackId]; + } + [session invalidateSession]; + } + }; + dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); + dispatch_async(queue, ^{ + while (blockNumber <= 247) { + if (dispatch_group_wait(readGroup, DISPATCH_TIME_NOW) == 0) { + readNextBlock(); + } + } + }); + + } - [self processNDEFTag:session tag:ndefTag metaData:tagMetaData]; }]; } +- (void)sendProgressUpdateToJavaScript:(NSInteger)progressUpdate { + NSLog(@"message progress update Invoked"); + NSString *jsString = [NSString stringWithFormat:@"document.dispatchEvent(new CustomEvent('nfcProgress', { 'detail': { 'progress' : %ld }}));", (long)progressUpdate]; + [self.commandDelegate evalJs:jsString]; +} + +- (void)sendMessageToJavaScript:(NSString *)message { + NSLog(@"message Connected Invoked"); + NSString *jsString = [NSString stringWithFormat:@"document.dispatchEvent(new CustomEvent('nfcConnect', { 'detail': {'message' : 'Connected'}}));"]; + [self.commandDelegate evalJs:jsString]; +} + +- (void)sendDisconnectMessage:(NSString *)message { + NSLog(@"message disconnected Invoked"); + NSString *jsString = [NSString stringWithFormat:@"document.dispatchEvent(new CustomEvent('nfcDisconnect', { 'detail': {'message' : 'Disconnected'}}));"]; + [self.commandDelegate evalJs:jsString]; +} - (void)tagReaderSession:(NFCTagReaderSession *)session didInvalidateWithError:(NSError *)error API_AVAILABLE(ios(13.0)) { NSLog(@"tagReaderSession ended"); @@ -305,21 +460,23 @@ - (void)startScanSession:(CDVInvokedUrlCommand*)command { if (@available(iOS 13.0, *)) { if (self.shouldUseTagReaderSession) { - NSLog(@"Using NFCTagReaderSession"); - self.nfcSession = [[NFCTagReaderSession new] + NSLog(@"Using NFCTagReaderSession and polling ISO15693"); + self.nfcSession = [[NFCTagReaderSession alloc] initWithPollingOption:(NFCPollingISO14443 | NFCPollingISO15693) delegate:self queue:dispatch_get_main_queue()]; + } else { NSLog(@"Using NFCNDEFReaderSession"); - self.nfcSession = [[NFCNDEFReaderSession new]initWithDelegate:self queue:nil invalidateAfterFirstRead:TRUE]; + self.nfcSession = [[NFCNDEFReaderSession alloc]initWithDelegate:self queue:nil invalidateAfterFirstRead:TRUE]; } sessionCallbackId = [command.callbackId copy]; - self.nfcSession.alertMessage = @"Hold near NFC tag to scan."; + self.nfcSession.alertMessage = @"Processing RITRack Tag."; + [self.nfcSession beginSession]; } else if (@available(iOS 11.0, *)) { NSLog(@"iOS < 13, using NFCNDEFReaderSession"); - self.nfcSession = [[NFCNDEFReaderSession new]initWithDelegate:self queue:nil invalidateAfterFirstRead:TRUE]; + self.nfcSession = [[NFCNDEFReaderSession alloc]initWithDelegate:self queue:nil invalidateAfterFirstRead:TRUE]; sessionCallbackId = [command.callbackId copy]; self.nfcSession.alertMessage = @"Hold near NFC tag to scan."; [self.nfcSession beginSession]; @@ -333,7 +490,7 @@ - (void)startScanSession:(CDVInvokedUrlCommand*)command { } - (void)processNDEFTag: (NFCReaderSession *)session tag:(__kindof id)tag API_AVAILABLE(ios(13.0)) { - [self processNDEFTag:session tag:tag metaData:[NSMutableDictionary new]]; + [self processNDEFTag:session tag:tag metaData:[[NSMutableDictionary alloc] init]]; } - (void)processNDEFTag: (NFCReaderSession *)session tag:(__kindof id)tag metaData: (NSMutableDictionary * _Nonnull)metaData API_AVAILABLE(ios(13.0)) { @@ -426,7 +583,7 @@ - (void)writeNDEFTag:(NFCReaderSession * _Nonnull)session status:(NFCNDEFStatus) // Gets the tag meta data - type and uid - (NSMutableDictionary *) getTagInfo:(id)tag API_AVAILABLE(ios(13.0)) { - NSMutableDictionary *tagInfo = [NSMutableDictionary new]; + NSMutableDictionary *tagInfo = [[NSMutableDictionary alloc] init]; NSData *uid; NSString *type; @@ -524,7 +681,7 @@ -(void) fireNdefEvent:(NFCNDEFMessage *) ndefMessage API_AVAILABLE(ios(11.0)) { -(void) fireNdefEvent:(NFCNDEFMessage *) ndefMessage metaData:(NSDictionary *)metaData API_AVAILABLE(ios(11.0)) { NSLog(@"fireNdefEvent"); - NSMutableDictionary *nfcEvent = [NSMutableDictionary new]; + NSMutableDictionary *nfcEvent = [[NSMutableDictionary alloc] init]; nfcEvent[@"type"] = @"ndef"; nfcEvent[@"tag"] = [self buildTagDictionary:ndefMessage metaData:metaData]; @@ -549,7 +706,7 @@ -(void) fireNdefEvent:(NFCNDEFMessage *) ndefMessage metaData:(NSDictionary *)me // NSData fields are converted to uint8_t arrays -(NSDictionary *) buildTagDictionary:(NFCNDEFMessage *) ndefMessage metaData: (NSDictionary *)metaData API_AVAILABLE(ios(11.0)) { - NSMutableDictionary *dictionary = [NSMutableDictionary new]; + NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init]; // start with tag meta data if (metaData) { @@ -563,7 +720,7 @@ -(NSDictionary *) buildTagDictionary:(NFCNDEFMessage *) ndefMessage metaData: (N } if (ndefMessage) { - NSMutableArray *array = [NSMutableArray new]; + NSMutableArray *array = [[NSMutableArray alloc] init]; for (NFCNDEFPayload *record in ndefMessage.records){ NSDictionary* recordDictionary = [self ndefRecordToNSDictionary:record]; [array addObject:recordDictionary]; @@ -575,7 +732,7 @@ -(NSDictionary *) buildTagDictionary:(NFCNDEFMessage *) ndefMessage metaData: (N } -(NSDictionary *) ndefRecordToNSDictionary:(NFCNDEFPayload *) ndefRecord API_AVAILABLE(ios(11.0)) { - NSMutableDictionary *dict = [NSMutableDictionary new]; + NSMutableDictionary *dict = [[NSMutableDictionary alloc] init]; dict[@"tnf"] = [NSNumber numberWithInt:(int)ndefRecord.typeNameFormat]; dict[@"type"] = [self uint8ArrayFromNSData: ndefRecord.type]; dict[@"id"] = [self uint8ArrayFromNSData: ndefRecord.identifier]; @@ -619,4 +776,26 @@ - (NSString*) dictionaryAsJSONString:(NSDictionary *)dict { return jsonString; } +//- (void)transceive:(CDVInvokedUrlCommand *)command { +// NSLog(@"Invoking Transcieve"); +// NFCTagReaderSession *session = [[NFCTagReaderSession alloc] initWithPollingOption:NFCPollingISO15693 delegate:self queue:nil]; +// session.alertMessage = @"Hold your phone near the Tag"; +// [session beginSession]; +//} + +- (void)handleError:(NSError *)error { + CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:error.localizedDescription]; + [self.commandDelegate sendPluginResult:pluginResult callbackId:self->sessionCallbackId]; +} + @end + + + + + + + + + +