Guest post by John Murray
This is the second part of a six-part series by Martin Woolley and me on porting BlackBerry Java applications that use NFC to BlackBerry 10. In our last post, we looked at Tag Reading. This time, we’ll review the way in which you’d port code that writes to NFC tags.
Here’s where we are in the series as a whole:
- Reading NFC Tags
- Writing NFC Tags
- Peer to Peer Mode
- Reading NFC Contactless Cards
- NFC Virtual Tag and Card Emulation
- NFC Card Emulation
So without further ado, let’s take a look at the aspects you need to deal with:
Key issues for the Java developer
The general pattern you’ll have followed in your Java application will have been to address the following tasks:
- Detecting the tag: The application must implement the DetectionListener interface and register it with ReaderWriterManager.addDetectionListener(…). When a tag comes into proximity with the device, there will be a call-back to the DetectionListener.
- Creating tag content: To create tag content, we create an NDEFMessage object using methods in NDEFMessageUtils such as createUriNdefMessage (available from BlackBerry 7 device software version 7.1), or by manually create the byte[] payload and building NDEFRecord and NDEFMessage objects.
- Writing to the tag: When a tag is found to be in proximity of the BlackBerry device, as indicated by a call-back to the DetectionListener interface, we create an NDEFTagConnection to the Target object indicated in the call-back and then write the tag content to it that we’ve already prepared.
The BlackBerry 10 Native approach
To perform the corresponding tasks in BlackBerry 10, you can take one of two approaches. You may either:
a) Use the Invocation Framework. That is, find another application that can provide a “tag writing service” that your application can use, or:
b) Use BPS (BlackBerry Platform Services) to detect and then write data to the tag.
Writing tags using the Invocation Framework
The easiest way to do this is directly from QML using the QML InvokeActionItem component. The code fragment below shows how to do this. Note that the tag content itself must still be constructed, as an array of bytes, from C++ and, in this example we’re calling our own application code via _ndefFactory.getNdefTextMessage() to accomplish this. We’ll explain this in more detail below.
actions: [ InvokeActionItem { id: sharedNdefData ActionBar.placement: ActionBarPlacement.OnBar query { mimeType: "application/vnd.rim.nfc.ndef" invokeActionId: "bb.action.SHARE" } handler: InvokeHandler { id: shareHandler onInvoking: { sharedNdefData.data = _ndefFactory.getNdefTextMessage( "en", writeText.ndefText ); shareHandler.confirm(); } } } ]
In our example, we construct an invocation framework query whereby we express our need for an application that can “SHARE” data of MIME type “application/vnd.rim.nfc.ndef”. This means we’re looking for an application that can write tags on our behalf. When the action is invoked, we call our _ndefFactory C++ method to create the payload and assign the result to the data attribute of the InvokeActionItem component. Our C++ code is shown below and you can see that the QtMobilitySubset API was used to help create the tag content in the NDEF format.
QByteArray NdefFactory::getNdefTextMessage( const QVariant &lang, const QVariant &text) { QString ndefLang = lang.toString(); QString ndefText = text.toString(); QtMobilitySubset::QNdefRecord ndefRecord = QtMobilitySubset::QNdefRecord(); int langLength = (ndefLang.length() <= 63) ? ndefLang.length() : 63; QByteArray ndefPayload; ndefPayload[0] = langLength; ndefPayload.append(ndefLang.left(langLength)) .append(ndefText.toUtf8()); ndefRecord.setTypeNameFormat(QtMobilitySubset::QNdefRecord::NfcRtd); ndefRecord.setType(Settings::NfcRtdText); ndefRecord.setPayload(ndefPayload); QtMobilitySubset::QNdefMessage ndefMessage = QtMobilitySubset::QNdefMessage(ndefRecord); return ndefMessage.toByteArray(); }
Writing tags using BPS
BPS processing takes place inside an event loop. Detection of a tag is indicated by delivery to the event loop of a particular type of event object. To receive such events, we must first register our interest by calling:
nfc_register_tag_readerwriter(TAG_TYPE_NDEF);
On receiving an event with the event code NFC_TAG_READWRITE_EVENT we proceed to construct our tag content in NDEF format and then write it to the tag via a Target object. The following code fragment illustrates this.
void NfcWorker::handleNfcWriteTextTagEvent(bps_event_t *event) { uint16_t code = bps_event_get_code(event); nfc_event_t *nfcEvent; nfc_target_t* target; nfc_ndef_record_t* myNdefRecord; nfc_ndef_message_t* myNdefMessage; if (NFC_TAG_READWRITE_EVENT == code) { int rc; // check return codes from NFC calls below rc = nfc_get_nfc_event(event, &nfcEvent); rc = nfc_get_target(nfcEvent, &target); displayTagInformation(target); myNdefRecord = makeTextRecord(Settings::LANG_EN, _ndefText); rc = nfc_create_ndef_message(&myNdefMessage); rc = nfc_add_ndef_record(myNdefMessage, myNdefRecord); rc = nfc_write_ndef_message_to_tag(target, myNdefMessage, false); rc = nfc_delete_ndef_message(myNdefMessage, true); rc = nfc_destroy_target(target); rc = nfc_unregister_tag_readerwriter(); emit message(QString("Tag Type Written Text: %1").arg(_ndefText)); } else { qDebug() << "XXXX NfcWorker::handleNfcWriteTextTagEvent” “ - NFC BPS event that we didn't register for: " << code; } }
So there you have it. Hopefully our exploration of this topic will make it nice and easy for you to port your BlackBerry Java application over to the world of BlackBerry 10 native apps. Good luck!
Resources
Knowledge Base Articles:
- NFC on BlackBerry 10 – Reading and Writing Tags using native APIs
- BlackBerry 10 – Leveraging Invocation Framework and QML for NFC
Sample Code:
- Tag writing using the BPS APIs is demonstrated by the NfcTool application
- Tag writing via Invocation Framework is demonstrated by the NfcToolLite application
Contacts: