WebAPI/WebNFC: Difference between revisions

From MozillaWiki
Jump to navigation Jump to search
Line 160: Line 160:
MozNdefRecord is a binary format, and the data is packed into Uint8Array fields. In the following examples, we'll just refer to this helper function to convert javascript strings to Uint8Array buffers.
MozNdefRecord is a binary format, and the data is packed into Uint8Array fields. In the following examples, we'll just refer to this helper function to convert javascript strings to Uint8Array buffers.


var NfcUtil = {
  var NfcUtil = {
  fromUTF8: function nu_fromUTF8(str) {
    fromUTF8: function nu_fromUTF8(str) {
    var buf = new Uint8Array(str.length);
      var buf = new Uint8Array(str.length);
    for (var i = 0; i < str.length; i++) {
      for (var i = 0; i < str.length; i++) {
      buf[i] = str.charCodeAt(i);
        buf[i] = str.charCodeAt(i);
      }
      return buf;
     }
     }
    return buf;
   }
   }
}


== NDEF Connect Example ==
== NDEF Connect Example ==

Revision as of 17:58, 11 December 2013

First iteration: NDEF

Scope

  • Technologies:
    • Focus on NDEF standard only for now
    • Others (e.g. proprietary MIFARE) to be investigated later.
  • Capabilities:
    • Read/write NDEF records on tags
    • P2P NDEF push/receive
  • Implementation:
    • NDEF-only API available on navigator.mozNfc object
    • Discovered NDEF tags are automatically parsed and dispatched to content in the "ndefdiscovered" event on navigator.mozNfc
    • navigator.mozNfc only available to a specific privileged content page (cf. WebTelephony, WebSMS).
    • For now, content is expected to do filtering and dispatching to handlers e.g. via WebIntents/WebActions/postMessage

Proposed API

navigator.mozNfc has one event related to NDEF discovery that arrives through a MozActivity. The "nfc-ndef-discovered" NFC event will be fired when a new NFC technology is discovered either via reading a tag or receiving it via P2P communication. The event will contain an array of technologies discovered, as well as the session token required to get the appropriate object to operate with the tag or device on the other end.

NFCTag

Calling getDetailsNDEF will retrieve information, such as the length of the NDEF record, and the maximum size of the NDEF. readNDEF will read the NDEF record, and return it to the caller. writeNDEF allows writing a NDEF message to a Tag, subject to storage limits.

 enum NFCTechType {
   "NFC_A",
   "NFC_B",
   "NFC_ISO_DEP",
   "NFC_F",
   "NFC_V",
   "NDEF",
   "NDEF_FORMATABLE",
   "MIFARE_CLASSIC",
   "MIFARE_ULTRALIGHT",
   "NFC_BARCODE",
   "P2P",
   "UNKNOWN_TECH"
 };
 
 interface MozNFCTag : EventTarget {
   DOMRequest getDetailsNDEF();
   DOMRequest readNDEF();
   DOMRequest writeNDEF(sequence<MozNdefRecord> records);
   DOMRequest makeReadOnlyNDEF();
 
   DOMRequest connect(NFCTechType techType);
   DOMRequest close();
 };

NFCPeer

sendNDEF does a P2P send of an NDEF formatted message to another NFC enabled device. NFCPeer will also handle send a generic blob in handover requests where a NDEF formatted "handover" message will conditionally trigger pairing with another device over an available Bluetooth or Wifi connection.

 interface MozNFCPeer : EventTarget {
   DOMRequest sendNDEF(sequence<MozNdefRecord> records);
   DOMRequest sendFile(Blob blob);
 };

Navigator NFC object

The session token for the getNFCTag and getNFCPeer calls is located in the MozActivity message data field. It is used to get the DOM object to operate on the tag (through NFCTag) or the paired NFC device (through NFCPeer).

 interface mozNfc {
 
   /**
    * NDEF Functions
    */
 
    /* Get the NFCTag */
    DOMRequest getNFCTag(DOMString sessionToken);
 
    /* Get the NFCPeer for Peer to Peer interactions */
    DOMRequest getNFCPeer(DOMString sessionToken);
 
   /**
    * API to update chrome about the top-most (visible)
    * application's manifest URL that is capable of
    * handling peer notifications.
    *
    * Users of this API should have valid permissions 'nfc-manager'
    * and 'nfc-write'
    */
   DOMRequest checkP2PRegistration(DOMString manifestUrl);
   /* Sets a callback to notifiy when NDEF Push message communication is available for use. */  
   attribute EventHandler onpeerready();
   attribute EventHandler onpeerlost();
 
   /* Foreground dispatch allows the app, if in the foreground, to get routed all
      NFC messages. Useful for applications that write NFC tags. Privilaged API. */
   attribute EventHandler onforegrounddispatch();
 
 };

NDEF records contain a bunch of metadata and a payload that is exposed as a Uint8Array.

 interface NdefRecord {
 
   /**
    * Type Name Field (3-bits) - Specifies the NDEF record type in general.
    * tnf_empty: 0x00
    * tnf_well_known: 0x01
    * tnf_mime_media: 0x02
    * tnf_absolute_uri: 0x03
    * tnf_external type: 0x04
    * tnf_unknown: 0x05
    * tnf_unchanged: 0x06
    * tnf_reserved: 0x07
    */
   readonly attribute octet tnf;
 
   /**
    * type - Describes the content of the payload. This can be a mime type.
    */
   readonly attribute Uint8Array type;
 
   /**
    * id - Identifer is application dependent.
    */
   readonly attribute Uint8Array id;
 
   /**
    * payload - Binary data blob. The meaning of this field is application dependent.
    */
   readonly attribute Uint8Array payload;
 };

Receiving NDEF messages, via MozActivity

Setup an Activity handler for incoming NDEF messages. The web activity chooser UI will route the messsage to the user selected application if there is more than one match. Currently, only NDEF is supported, although individual nfc tags can actually be compatible with multiple legacy and proprietary technology types.

Applications that do not have "nfc" read or write permissions can still get NDEF events via activities, and act on the data. The raw NDEF data is included with the activity, should the application wish to process any special properties of more complex NDEF data structures.

If the NFC NDEF tag type is well known, such as URIs, the activity will be delievered with some extra fields already parsed.

In the application manifest, declare the following in the activities block to get nfc ndef discovered events.

 "nfc-ndef-discovered": {
   "filters": {
     "type": "uri",
     "uri": { "required":true, "regexp":"/^https?:.{1,16384}$/i" }
   }
 },

Then implement an activity handler in the application:

 navigator.mozSetMessageHandler('activity', NfcActivityHandler);
 
 function NfcActivityHandler(activity) {
   var activityName = activity.source.name;
   var data = activity.source.data;
 
   switch (activityName) {
     case 'nfc-ndef-discovered':
       console.log('nfc ndef message records(s): ' + JSON.stringify(data.records));
       console.log('Session Token: ' + JSON.stringify(data.sessionToken));
       console.log('Technology Detected: ' + JSON.stringify(data.tech));
       handleNdefDiscovered(data);
       break;
 }

NDEF Utilitiy function

MozNdefRecord is a binary format, and the data is packed into Uint8Array fields. In the following examples, we'll just refer to this helper function to convert javascript strings to Uint8Array buffers.

 var NfcUtil = {
   fromUTF8: function nu_fromUTF8(str) {
     var buf = new Uint8Array(str.length);
     for (var i = 0; i < str.length; i++) {
       buf[i] = str.charCodeAt(i);
     }
     return buf;
   }
 }

NDEF Connect Example

To establish an NFC application session, all NFCTag operations require an initial connect. It also selects the technology to use for subsequent operations until disconnect.

 nfctag = window.navigator.mozNfc.getNFCTag(sessionToken);
 var connectreq = nfctag.connect("NDEF");
 connectreq.onsuccess = function() {
   console.log('Connect success!');
 };
 connectreq.onerror = function() {
   console.log('ERROR: Failed to connect.');
 };

NFC Close Example

Applications should disconnect when done to release resources.

 var closereq = nfctag.close();
 closereq.onsuccess = function() {
   console.log('NFC tag close success!');
 };
 closereq.onerror = function() {
   console.log('ERROR: Failed to close.');
 };

NDEF Details Example

 var detailreq = nfctag.getDetailsNDEF();
 detailreq.onsuccess = function() {
   console.log('Max NDEF Message Length: ' + detailreq.result.maxNdefMsgLen);
 };
 detailreq.onerror = function() {
   console.log('ERROR: Failed to get NDEF details.');
 };

NDEF Read Example

The array of ndef records should be passed along in the web activity already read, but applications can still directly read the tag. The session token arrives from a MozActiviy.

 var conn = nfctag.connect("NDEF");
 conn.onsuccess = function() {
   var req = nfctag.readNDEF();
   req.onsuccess = function() {
     var records = req.result.records;
     showRecords(records);
     nfctag.close(); // This is a DOMRequest call, truncated code here.
   };
   req.onerror = function() {
     nfctag.close(); // This is a DOMRequest call, truncated code here.
   };
 };
 
 function showRecords(records) {
   records.forEach(function (record) {
     console.log("Found a " + record.tnf + " record" +
                 " of type " + NfcUtil.fromUTF8(record.type) +
                 " with ID " + NfcUtil.fromUTF8(record.id) +
                 " and payload " + NfcUtil.fromUTF8(record.payload));
   });
 };

NDEF Write Tag Example

 var tnf     = 1;                                                            // NFC Forum Well Known type
 var type    = new Uint8Array(NfcUtil.fromUTF8("U"));                        // URL type
 var id      = new Uint8Array(NfcUtil.fromUTF8(""));                         // id
 var payload = new Uint8Array(NfcUtil.fromUTF8("\u0000http://mozilla.org")); // URL data
 
 var ndefRecords = new MozNdefRecord(tnf, type, id, payload);
 
 var writereq = nfctag.writeNDEF(ndefRecords);
 writereq.onsuccess = function(e) {
   console.log("Successfully wrote records to tag");
 };
 writereq.onerror = function(e) {
   console.log("Write failed!");
 };

NDEF P2P Push Example

Peer to Peer communications to another NFC enabled device does not need a connect, as it will automatically connect implicitly. It also only supports NDEF, which is a common standard data format across different NFC devices.

 var tnf     = 1;                                                            // NFC Forum Well Known type
 var type    = new Uint8Array(NfcUtil.fromUTF8("U"));                        // URL type
 var id      = new Uint8Array(NfcUtil.fromUTF8(""));                         // id
 var payload = new Uint8Array(NfcUtil.fromUTF8("\u0000http://mozilla.org")); // URL data
 
 var ndefRecords = new MozNdefRecord(tnf, type, id, payload);
 
 window.navigator.onpeerfound = function(nfcpeer) {
   var peerreq = nfcpeer.pushNDEF(ndefRecords); // push NDEF message to other NFC device.
   peerreq.onsuccess = function(e) {
     console.log("Successfully pushed P2P message");
   };
   peerreq.onerror = function(e) {
     console.log("P2P push failed!");
   };
 };

Application Permissions

To use NFC NDEF functions like NFCTag {detailsNDEF, readNDEF, writeNDEF, connect, close}, or those in NFCPeer {pushNDEF, sendNDEF}, nfc permissions are required. Declare them in the application manifest. Currently, only certified applications can use nfc functions. Here, the app declares read only permissions:

 "permissions": {
   "nfc":{ "access": "readonly" }
 }

System level apps declare an additional certified system message permissions, as it fires the nfc-ndef-discovered WebActivities to applications that declare NFC NDEF support:

 "permissions": {
   "nfc": { "access": "readonly" },
   "nfc-manager": {}
 }

Application Dispatch Order

TBD.

Priority (low is highest):

Declared support levels:

1) Foreground App with declared type support (NFC writing apps need to be able to hold the screen so it can write the message, privilaged nfc permisisons).
2) Handover Types (BT transfers, WiFi direct connection, etc.)
3) Specific declared Type support

Implementation

  • See bug 674741
  • Engineers: Markus Neubrand, Arno Puder, Garner Lee, Siddartha Pothapragada, Philipp von Weitershausen