Skip to content

Commit

Permalink
Allow iOS to read tag before writing (#420)
Browse files Browse the repository at this point in the history
* write can reuse session from read see #419

* Update README.md

* cleanup connectedTag
  • Loading branch information
don authored Jul 10, 2020
1 parent 232f631 commit d13a287
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 16 deletions.
64 changes: 63 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -307,12 +307,74 @@ Function `nfc.write` writes an NdefMessage to a NFC tag.

On **Android** this method *must* be called from within an NDEF Event Handler.

On **iOS** this method should be called outside the NDEF Event Handler, it will start a new scanning session.
On **iOS** this method can be called outside the NDEF Event Handler, it will start a new scanning session. Optionally you can reuse the read session to write data. See example below.

On **Windows** this method *may* be called from within the NDEF Event Handler.

On **Windows Phone 8.1** this method should be called outside the NDEF Event Handler, otherwise Windows tries to read the tag contents as you are writing to the tag.

### Examples

#### Android

On Android, write must be called inside an event handler

function onNfc(nfcEvent) {

console.log(nfcEvent.tag);
var message = [
ndef.textRecord(new String(new Date()))
];
nfc.write(
message,
success => console.log('wrote data to tag'),
error => console.log(error)
);

nfc.addNdefListener(onNfc);


#### iOS - Simple

Calling `nfc.write` on iOS will create a new session and write data when the user taps a NFC tag

var message = [
ndef.textRecord("Hello, world")
];

nfc.write(
message,
success => console.log('wrote data to tag'),
error => console.log(error)
);

#### iOS - Read and Write

On iOS you can optionally write to NFC tag using the read session

try {
let tag = await nfc.scanNdef({ keepSessionOpen: true});

// you can read tag data here
console.log(tag);
// this example writes a new message with a timestamp
var message = [
ndef.textRecord(new String(new Date()))
];

nfc.write(
message,
success => console.log('wrote data to tag'),
error => console.log(error)
);

} catch (err) {
console.log(err);
}

### Supported Platforms

- Android
Expand Down
61 changes: 49 additions & 12 deletions src/ios/NfcPlugin.m
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,15 @@
@interface NfcPlugin() {
NSString* sessionCallbackId;
NSString* channelCallbackId;
id<NFCNDEFTag> 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;
@property (nonatomic, assign) BOOL returnTagInCallback;
@property (nonatomic, assign) BOOL returnTagInEvent;
@property (nonatomic, assign) BOOL keepSessionOpen;
@property (strong, nonatomic) NFCReaderSession *nfcSession API_AVAILABLE(ios(11.0));
@property (strong, nonatomic) NFCNDEFMessage *messageToWrite API_AVAILABLE(ios(11.0));
@end
Expand Down Expand Up @@ -52,7 +55,8 @@ - (void)beginSession:(CDVInvokedUrlCommand*)command {
self.sendCallbackOnSessionStart = YES; // Not sure why we were doing this
self.returnTagInCallback = NO;
self.returnTagInEvent = YES;

self.keepSessionOpen = NO;

[self startScanSession:command];
}

Expand All @@ -64,6 +68,9 @@ - (void)scanNdef:(CDVInvokedUrlCommand*)command {
self.returnTagInCallback = YES;
self.returnTagInEvent = NO;

NSArray<NSDictionary *> *options = [command argumentAtIndex:0];
self.keepSessionOpen = [options valueForKey:@"keepSessionOpen"];

[self startScanSession:command];
}

Expand All @@ -75,6 +82,9 @@ - (void)scanTag:(CDVInvokedUrlCommand*)command {
self.returnTagInCallback = YES;
self.returnTagInEvent = NO;

NSArray<NSDictionary *> *options = [command argumentAtIndex:0];
self.keepSessionOpen = [options valueForKey:@"keepSessionOpen"];

[self startScanSession:command];
}

Expand All @@ -83,6 +93,7 @@ - (void)writeTag:(CDVInvokedUrlCommand*)command API_AVAILABLE(ios(13.0)){

self.writeMode = YES;
self.shouldUseTagReaderSession = NO;
BOOL reusingSession = NO;

NSArray<NSDictionary *> *ndefData = [command argumentAtIndex:0];

Expand All @@ -107,30 +118,41 @@ - (void)writeTag:(CDVInvokedUrlCommand*)command API_AVAILABLE(ios(13.0)){
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
return;
}

// Start the NFC Session
if (self.shouldUseTagReaderSession) {
NSLog(@"Using NFCTagReaderSession");

self.nfcSession = [[NFCTagReaderSession new]
initWithPollingOption:(NFCPollingISO14443 | NFCPollingISO15693)
delegate:self queue:dispatch_get_main_queue()];
if (self.nfcSession && self.nfcSession.isReady) { // reuse existing session
reusingSession = YES;
} else { // create a new session
if (self.shouldUseTagReaderSession) {
NSLog(@"Using NFCTagReaderSession");

} else {
NSLog(@"Using NFCTagReaderSession");
self.nfcSession = [[NFCNDEFReaderSession new]initWithDelegate:self queue:nil invalidateAfterFirstRead:FALSE];
self.nfcSession = [[NFCTagReaderSession new]
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.alertMessage = @"Hold near writable NFC tag to update.";
sessionCallbackId = [command.callbackId copy];
[self.nfcSession beginSession];

if (reusingSession) { // reusing a read session to write
self.keepSessionOpen = NO; // close session after writing
[self writeNDEFTag:self.nfcSession status:connectedTagStatus tag:connectedTag];
} else {
[self.nfcSession beginSession];
}
}

- (void)cancelScan:(CDVInvokedUrlCommand*)command API_AVAILABLE(ios(11.0)){
NSLog(@"cancelScan");
if (self.nfcSession) {
[self.nfcSession invalidateSession];
}
connectedTag = NULL;
connectedTagStatus = NFCNDEFStatusNotSupported;
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
}
Expand Down Expand Up @@ -326,6 +348,11 @@ - (void)processNDEFTag: (NFCReaderSession *)session tag:(__kindof id<NFCNDEFTag>
if (self.writeMode) {
[self writeNDEFTag:session status:status tag:tag];
} else {
// save tag & status so we can re-use in write
if (self.keepSessionOpen) {
self->connectedTagStatus = status;
self->connectedTag = tag;
}
[self readNDEFTag:session status:status tag:tag metaData:metaData];
}

Expand Down Expand Up @@ -456,8 +483,16 @@ - (void) sessionDidBecomeActive:(NFCReaderSession *) session API_AVAILABLE(ios(
}

- (void) closeSession:(NFCReaderSession *) session API_AVAILABLE(ios(11.0)){

// this is a hack to keep a read session open to allow writing
if (self.keepSessionOpen) {
return;
}

// kill the callback so the Cordova doesn't get "Session invalidated by user"
sessionCallbackId = NULL;
connectedTag = NULL;
connectedTagStatus = NFCNDEFStatusNotSupported;
[session invalidateSession];
}

Expand All @@ -466,6 +501,8 @@ - (void) closeSession:(NFCReaderSession *) session withError:(NSString *) errorM

// kill the callback so Cordova doesn't get "Session invalidated by user"
sessionCallbackId = NULL;
connectedTag = NULL;
connectedTagStatus = NFCNDEFStatusNotSupported;

if (@available(iOS 13.0, *)) {
[session invalidateSessionWithErrorMessage:errorMessage];
Expand Down
6 changes: 3 additions & 3 deletions www/phonegap-nfc.js
Original file line number Diff line number Diff line change
Expand Up @@ -501,16 +501,16 @@ var nfc = {
},

// iOS only - scan for NFC NDEF tag using NFCNDEFReaderSession
scanNdef: function () {
scanNdef: function (options) {
return new Promise(function(resolve, reject) {
cordova.exec(resolve, reject, "NfcPlugin", "scanNdef", []);
cordova.exec(resolve, reject, "NfcPlugin", "scanNdef", [options]);
});
},

// iOS only - scan for NFC Tag using NFCTagReaderSession
scanTag: function (options) {
return new Promise(function(resolve, reject) {
cordova.exec(resolve, reject, "NfcPlugin", "scanTag", []);
cordova.exec(resolve, reject, "NfcPlugin", "scanTag", [options]);
});
},

Expand Down

0 comments on commit d13a287

Please sign in to comment.