DEVELOPERS BLOG

Porting BlackBerry Java NFC Applications to BlackBerry 10 Part 3: Peer to Peer – SNEP (Simple NDEF Exchange Protocol)

NFC P2P

Guest post by John Murray

This is the third part of a six-part series by Martin Woolley and I on porting BlackBerry Java applications that use NFC to BlackBerry 10. So far we’ve looked at Tag Reading and Tag Writing. This time, we’ll review the porting of code that exploits NFC’s Peer to Peer (P2P) mode.

Here’s where we are in the series as a whole:

  1. Reading NFC Tags
  2. Writing NFC Tags
  3. Peer to Peer Mode
  4. Reading NFC Contactless Cards
  5. NFC Virtual Tag and Card Emulation
  6. NFC Card Emulation

Let’s dive in and take a look at the aspects that you have to deal with:

Key issues for the Java developer
Let’s separate the main task you’ll need to have an understanding of into two broad categories: sending data over a P2P connection, and receiving data over a P2P connection.

Receiving data over a P2P  connection
Receiving P2P data is identical to reading a tag. This process was described in the first post of this series, “Porting BlackBerry Java NFC Applications to BlackBerry 10 – Part 1: Reading NFC Tags.”

Sending data over a P2P connection
The general pattern to follow in your Java application will be to address the following tasks:

  1. Create a class that will build NDEF Message to send over SNEP: To send data using NFC P2P, the BlackBerry Java developer must first create a class that implements the NDEFMessageBuilder interface. NDEFMessageBuilder’s buildNDEFMessages() method will be called when a P2P device is presented; it’s at this point that you have to construct an NDEF Message to send to the peer device.
  2. Create a class that will be notified of a successful transfer over SNEP: Next, you must create a class that implements the NDEFPushStatusCallback interface. NDEFPushStatusCallback’s onNDEFPushStatusUpdate() method will be called indicating the success or failure of the P2P transfer.
  3. Register instances of these two classes: Finally, an instance of the NDEFPushManager is obtained, and by calling its pushNDEF() method instances of the NDEFMessageBuilder and NDEFPushStatusCallback, classes that were created in steps 1 and 2 are registered.

The BlackBerry 10 Native approach
As in the Java case, we’ll separate the main task you’ll need to have an understanding of into two broad categories: sending data over a P2P connection, and receiving data over a P2P connection.

Receiving data over a P2P connection
Receiving P2P data is once again identical to reading a tag. Take a look at our post on that topic to refresh your memory.

Sending data over a P2P connection
There are three approaches on BlackBerry 10. You may:

  1. Use the BPS (BlackBerry Platform Services) APIs to handle the sending of data over P2P.
  2. Use the Invoke Framework APIs to handle the sending of the data over the P2P connection.
  3. Use the NfcShareManager Cascades class and associated classes.

The choice of approach is very much dependent on the application being developed, but the Cascades NfcShareManager approach is usually the easiest and quickest to implement, assuming it meets your requirements.

Let’s look at these in more detail.

The BPS API Approach
It’s necessary to register with BPS using nfc_register_snep_client() that we want to receive NFC_SNEP_CONNECTION_EVENT BPS events. Then, once a peer to peer target is presented to the device and an NFC_SNEP_CONNECTION_EVENT BPS event is received, an NDEF Message should be constructed and passed back in a call to nfc_push_ndef_message(). Success or failure of the push is determined by the return code from this function. The code below shows an NDEF message representing a vCard being constructed:

...       int rc = nfc_register_snep_client(); ... void NfcWorker::handleSendVcardEvent(bps_event_t *event) {       int rc;       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_SNEP_CONNECTION_EVENT == code) {             QString mimeType = QString("text/x-vCard");             QString vCard = String("BEGIN:VCARDn")                                  .append("VERSION:3.0n").append("N:")                                  .append(_last_name).append(";")                                  .append(_first_name).append("n")                                  .append(FN:").append(_first_name)                                  .append(" ").append(_last_name)                                  .append("n").append("ADR;TYPE=WORK:")                                  .append(_address).append("n")                                  .append("TEL;TYPE=CELL:").append(_mobile)                                   .append("n")                                   .append("EMAIL;TYPE=INTERNET:")                                  .append(_email).append("n")                                   .append("END:VCARD");             rc = nfc_get_nfc_event(event, &nfcEvent);             rc = nfc_get_target(nfcEvent, &target);             myNdefRecord = makeMediaRecord(mimeType, vCard);             rc = nfc_create_ndef_message(&myNdefMessage);             rc = nfc_add_ndef_record(myNdefMessage, myNdefRecord);             rc = nfc_push_ndef_message(target, myNdefMessage);             rc = nfc_delete_ndef_message(myNdefMessage, true);             rc = nfc_destroy_target(target);             emit message(QString("vCard sent OK"));       } else {             qDebug() << "XXXX NfcWorker::handleSendVcardEvent”                         “ - NFC BPS event that we didn't register for: "                      << code;       }       qDebug() << "XXXX SendVcard done"; }   ...

The Invoke Framework Approach
This approach is very attractive since most of the processing can be handled within the context of a QML page. It involves having an InvokeActionItem component in a list of actions with a query attribute that has a MIME Type identifying an NFC NDEF message. This construct lets the Invocation Framework locate the NFC Share Adapter that will perform the NFC SNEP operation on our behalf. The code below shows how to do this.

When a P2P connection is established the onInvoking method, the InvokeHandler is driven and the data attribute of the InvokeActionItem is set to be a NDEF Message as a byte array that can be constructed in any way you want. In this case, we have a factory class that will build messages for us. The net result is that this message is transmitted as a P2P SNEP message to the peer device.

...         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.getNdefVcardMessage(                          sendVcard.ndefFirstName,                          sendVcard.ndefLastName,                          sendVcard.ndefAddress,                          sendVcard.ndefEmail,                          sendVcard.ndefMobile);                     shareHandler.confirm();                 }             }         }       ]  ...

The Cascades Approach (NfcShareManager)
Cascades includes a number of high-level classes centered around NfcShareManager that makes the sharing of files and data of various (MIME) types very easy. Here’s an example where we share (that is, send over an NFC P2P link) a string of text over NFC:

void NfcSharing::dataShareContentChanged(QString message, QString dataType) {       NfcShareDataContent request;      QByteArray data(message.toUtf8());      QUrl url;       request.setUri(url);      request.setMimeType(dataType);      request.setData(data);       NfcShareSetContentError::Type rc = _nfcShareManager->setShareContent(request);  }

As you can see, all we do is create an NfcShareDataContent object, populate it with our data and its MIME type, and hand it to the NfcShareManager for sharing. That’s it!

For larger files, it’s wise to use Bluetooth to transfer the data, but NFC makes the establishment of the Bluetooth connection very easy. This is collectively known as “Bluetooth Connection Handover.” The Cascades NFC P2P APIs make it extremely simple to indicate that you would like Bluetooth Connection Handover to take place. Simply use the NfcShareFilesContent class instead of the NfcShareDataContent class, and connection handover gets initiated as if by magic.

For more information, we provided a link to a full technical knowledge base article on the use of the Cascades NFC P2P APIs below.

Good luck porting your NFC P2P code to BlackBerry 10, and let us know if you have any questions in the comments section below!

Resources

Knowledge Base Articles:

Sample Code:

  • Sending P2P data using SNEP using the BPS APIs is demonstrated by the NfcTool application.
  • Sending P2P data using SNEP using the Invoke Framework is demonstrated by the NfcToolLite application.
  • See this example for a simple Tic Tac Toe game implemented between two handsets using SNEP as the Peer to Peer communication channel, as described in this blog post.
  • Use of the Cascades NFC P2P APIs including NfcShareManager is well illustrated by the NfcSharing application.

Contacts:

About alexkinsella1