Example: Using the PPS interface

In the example, called com.qnx.demo, a plugin is built that provides methods and events for creating, updating, and watching a simple Persistent Publish/Subscribe (PPS) object. The source code for this project is available in the demo folder where you installed the HTML5 SDK.

In the example, called com.qnx.demo, a plugin is created that provide methods and events for creating, updating, and watching a simple PPS object. The example links to the PPS utilities file, ppsUtils.js, which is included as part of the webplatform.js file that's linked in by the Cordova packager (build command). The namespace for ppsUtils.js is qnx.webplatform.pps. The files in the demo follow the structure described in the "Structure of a plugin" section.

Files in the example

This example includes the following files:
  • plugin.xml in the com.qnx.demo directory. This file declares the namespace of the plugin, and describes the file structure.
  • demo.js and index.js in the com.qnx.demo/src/blacberry10 directory. The demo.js file initializes the extension and defines functions for handling events and returning PPS data. The index.js file sets up the events that are triggered.
  • client.js in the com.qnx.demo/www directory. This file defines the externally visible methods that apps can use.

Here's more information about these files.

demo.js

The demo.js file provides the core functionality of the plugin. First, you link to the qnx.webplatform.pps namespace to access PPS functionality and then declare some variables that are used later:

var _pps = qnx.webplatform.pps,
    _readerPPS,
    _writerPPS,
    _triggerUpdate; 

Now, you can create the demo PPS object. The PPS object specified by /pps/qnx/demo is the location of the file where the PPS objects are stored on the target. There's more code that handles errors and so on, but for simplification, just create the PPS object:

_readerPPS = _pps.create("/pps/qnx/demo", _pps.PPSMode.DELTA);
_readerPPS.onNewData = function(event) {
    if (_triggerUpdate && event && event.data) {
        _triggerUpdate(event.data);            
...

_writerPPS = _pps.create("/pps/qnx/demo", _pps.PPSMode.DELTA);
...

The preceding code creates a PPS object (/pps/qnx/demo) with two handles: one for reading (_readerPPS) and one for writing (_writerPPS). These handles provide access to the JavaScript APIs in qnx.webplatform.pps used for manipulating the PPS data. The _triggerUpdate method is used for handling events. Here, the method defines the action to take when new data is available in the PPS object.

The demo.js file also defines the functions for handling the event trigger (setTriggerUpdate()) and for getting (get()) and setting (set()) the PPS data. These functions are exported so that they can be called from the index.js file:

/**
 * Sets the trigger function to call when an event is triggered
 * @param trigger {Function} The trigger function to call when an event is fired
 */
setTriggerUpdate: function(trigger) {
    _triggerUpdate = trigger;
},
    
/**
 * Returns the demo object
 * @returns {Object} The demo object
 */
get: function(settings) {
     return _readerPPS.data.demo;
},
    
/**
 * Set a demo object field
 * @param {String} key The data key
 * @param {Mixed} value The data value
 */
set: function(key, value) {
     var data = {};
     data[key] = value;
     _writerPPS.write(data);
}

index.js

In the index.js file, the functions that are defined are made available to the clients through the client.js file:

/**
* Starts triggering events
* @param {Function} success Function to call if the operation is a success
* @param {Function} fail Function to call if the operation fails
* @param {Object} args The arguments supplied
* @param {Object} env Environment variables
*/
startEvents: function(success, fail, args, env) {
    _eventResult = new PluginResult(args, env)
    try {
        _demo.setTriggerUpdate(function (data) {
            _eventResult.callbackOk(data, true);
        });
        _eventResult.noResult(true);
    } catch (e) {
        _eventResult.error("error in startEvents: " + JSON.stringify(e), false);
    }
},

/**
 * Stops triggering events
 * @param {Function} success Function to call if the operation is a success
 * @param {Function} fail Function to call if the operation fails
 * @param {Object} args The arguments supplied
 * @param {Object} env Environment variables
 */
stopEvents: function(success, fail, args, env) {
   var result = new PluginResult(args, env);
   try {
       //disable the event trigger
        _demo.setTriggerUpdate(null);
        result.ok(undefined, false);

        //cleanup
        _eventResult.noResult(false);
        delete _eventResult;
    } catch (e) {
        result.error("error in stopEvents: " + JSON.stringify(e), false);
    }
},

/**
 * Returns system settings
 * @param success {Function} Function to call if the operation is a success
 * @param fail {Function} Function to call if the operation fails
 * @param args {Object} The arguments supplied
 * @param env {Object} Environment variables
 */
get: function(success, fail, args, env) {
    var result = new PluginResult(args, env)
    try {
        var fixedArgs = _wwfix.parseArgs(args);
        var data = _demo.get();
        result.ok(data, false);
    } catch (e) {
        result.error(JSON.stringify(e), false);
    }
},
    
/**
 * Sets one or more system settings
 * @param success {Function} Function to call if the operation is a success
 * @param fail {Function} Function to call if the operation fails
 * @param args {Object} The arguments supplied
 * @param env {Object} Environment variables
 */
set: function(success, fail, args, env) {
    var result = new PluginResult(args, env)
    try {
        var fixedArgs = _wwfix.parseArgs(args);
        _demo.set(fixedArgs.key, fixedArgs.value);
        result.ok(undefined, false);
    } catch (e) {
        result.error(JSON.stringify(e), false);
    }
}    
In the preceding code, these functions are defined:
  • startEvents() and stopEvents(), which use the setTriggerUpdate() function that was defined in index.js. This function is referenced as _demo.setTriggerUpdate().
  • get(), which uses the get() function that was defined in index.js (referenced here as _demo.get()).
  • set(), which uses the set() function that was defined in index.js (referenced here as _demo.set()).

client.js

The client.js file defines the public-facing interface, or client side, for the plugin. This file specifies where the cordova.exec() function is used to call the PPS functions that were previously defined in server-side files.

First, variables are declared. The variable _ID is used for calls to cordova.exec():

var _self = {},
    _ID = "com.qnx.demo",
    _utils = cordova.require('cordova/utils'),
    _watches = {};    

Next, a function is created to handle PPS update events. This function is also passed to cordova.exec(), but isn't accessible to other applications:

/**
 * Handles update events for this plugin
 * @param data {Array} The updated data provided by the event 
 * @private
 */
function onUpdate(data) {
    var keys = Object.keys(_watches);
    for (var i=0; i<keys.length; i++) {
        setTimeout(_watches[keys[i]](data), 0);
    }
}    

Finally, public-facing functions are declared and then and exported. For each function, cordova.exec() is called. The cordova.exec() function is passed the name of the function to call from index.js:

/**
 * Watch for PPS object changes
 * @param {Function} callback The function to call when a change is detected.
 * @return {String} An ID for the added watch.
 * @example
 * 
 * //define a callback function
 * function myCallback(myData) {
 *        //just send data to log
 *        console.log("Changed data: " , myData);
 *        }
 * }
 * 
 * var watchId = car.demo.watchDemo(myCallback);
 */
_self.watchDemo = function (callback) {
    var watchId = _utils.createUUID();
    
    _watches[watchId] = callback;
    if (Object.keys(_watches).length === 1) {
        window.cordova.exec(onUpdate, null, _ID, 'startEvents', null, false);
    }

    return watchId;
}

/**
 * Stop watching for PPS changes
 * @param {Number} watchId The watch ID as returned by car.demo.watchDemo().
 * @example
 * 
 * car.sensors.cancelWatch(watchId);
 */
_self.cancelWatch = function (watchId) {
    if (_watches[watchId]) {
        delete _watches[watchId];
        if (Object.keys(_watches).length === 0) {
            window.cordova.exec(null, null, _ID, 'stopEvents', null, false);
        }
    }
}

/**
 * Get the value of the demo PPS object
 * @returns {Object} The demo object contents.
 */
_self.get = function () {
        var value = null,
        success = function (data, response) {
            value = data;
        },
        fail = function (data, response) {
            throw data;
        };

    try {
        window.cordova.exec(success, fail, _ID, 'get', null);
    } catch (e) {
        console.error(e);
    }
    return value;
}
    
/**
 * Set a demo object field
 * @param {String} key The data key
 * @param {Mixed} value The data value
 */
_self.set = function (key, value) {
    window.cordova.exec(null, null, _ID, 'set', { key: key, value: value });
}
    
module.exports = _self;  

Applications that use this plugin must define a callback function for Cordova to call when watchDemo() is successful.