Tag Archives: data push

Pushing Data to a PhoneGap Web View

UPDATE:

In PhoneGap 1.5, the naming conventions were changed to use the Apache Cordova naming conventions.   EX: PGPlugin is now CDVPlugin, phonegap.js is now cordova.js, etc…   If you are running into issues, please be sure to check the PhoneGap version and appropriate naming conventions.

ORIGINAL POST:

In my last post, which gave a crash course in PhoneGap Native Plugins, I discussed a scenario where you could use a native plugin and the writeJavascript function to “push” data into the UI/web view layer from the native code layer.   To elaborate on this scenario, I put together a sample application that demonstrates this concept in action.

I set up the sample application so that there is an extremely basic HTML user interface.   In that user interface, you can click a link which executes native code to start a timer (in the native code layer).   Once the timer is started, the user interface will be updated with a “started” message, and on every timer event, the user interface will be updated with the current time, as it is provided by the native code layer.   In this case, I am using a timer to simulate an external thread of execution, or stream of input from some other source (device or stream).   Take a look at the video below to see it in action:

Next, let’s examine how it works.

The HTML interface is very simple.   There is an <a> link, which calls the “doStart()” JavaScript function, an <h4> element to display status, and an <h2> element to display the content received from the native code layer. When the “doStart()” function is invoked, it calls the SamplePlugin JavaScript class’ “start()” function, passing a reference to the “successCallback()” function, which will get executed when a callback is received from the native layer.   The “updateContent()” function will just set the innerHTML value of the “output” element to the value passed as a parameter.

<!DOCTYPE html>
<html>
  <head>
  <title></title>

    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no;" />
	<meta charset="utf-8">

    <script type="text/javascript" charset="utf-8" src="phonegap-1.4.1.js"></script>
    <script type="text/javascript" charset="utf-8" src="SamplePlugin.js"></script>
    <script type="text/javascript">

    function doStart() {
        SamplePlugin.start( successCallback );
    }

    function successCallback() {
        document.getElementById( "status" ).innerHTML = "started";
    }

    function updateContent( data ) {

        document.getElementById( "output" ).innerHTML = data;
    }

    </script>
  </head>
  <body onload="onBodyLoad()">
	<h1>Hey, it's PhoneGap!</h1>
	<a href="javascript:doStart()">Start!</a>

    <h4 id="status"></h4>
    <h2 id="output"></h2>
  </body>
</html>

In the SamplePlugin.js file, which is the JavaScript component of the native plugin, you can see that there is a SamplePlugin class instance that has a “start()” function.   The “start()” function invokes the PhoneGap.exec() command to invoke native code.

var SamplePlugin = {
    start: function (success, fail) {
        return PhoneGap.exec(success, fail, "SamplePlugin", "start", []);
    }
};

In the native code, there is a basic class that extends the PGPlugin class.  When the user invokes the “start()” function in JavaScript, the native “start” function will be invoked.   In this function, output is appended to the console using NSLog, and a NSTimer instance is started.   Once the timer is started, a success callback will be sent back to the HTML/JavaScript layer.

Now, the timer is executing indefinitely in the native code.   You will notice that in the timer handler “onTick” function, a message is written to the console, and a JavaScript string is created and routed to the UI layer using writeJavascript.   In this case, the JavaScript string just contains the current date as a string, to maintain simplicity.

#import "SamplePlugin.h"

@implementation SamplePlugin

- (void) start:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options {

    NSString* callbackID = [arguments pop];
    NSLog(@"start invoked");

    [NSTimer scheduledTimerWithTimeInterval:1.0
                                     target:self
                                   selector:@selector(onTick:)
                                   userInfo:nil
                                    repeats:YES];

    PluginResult* pluginResult = [PluginResult resultWithStatus:PGCommandStatus_OK messageAsString: @"OK"];
    [self writeJavascript: [pluginResult toSuccessCallbackString:callbackID]];
}

-(void)onTick:(NSTimer *)timer {

    NSLog(@"timer tick!");

    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    [formatter setDateFormat:@"dd-MM-yyyy HH:mm:ss"];

    NSString *dateString = [formatter stringFromDate:[NSDate date]];
    NSString *js = [NSString stringWithFormat:@"updateContent( '%@' );", dateString];

    [self writeJavascript:js];
}

@end

When the native-generated JavaScript is executed, it will invoke the updateContent() JavaScript function, which will then update the HTML user interface.

While this example is extremely basic, you could use this exact same approach to push more complex data to the UI layer in real time.  This data could be coming from network activity, Bluetooth connections, or physical devices that are connected to the mobile device.

You can download the full source code for this sample project directly from: PhoneGapPluginDataPush.zip

Toying with Realtime Data & Web Sockets

Recently I was acting as a “second set of eyes” to help out fellow Adobe Evangelist Kevin Hoyt track down a quirk with a websockets example that he was putting together. Kevin has a great writeup to familiarize yourself with web sockets & streaming communication that I highly recommend checking out.

While working with Kevin’s code, I started tinkering… “what if I change this, what if I tweak that?” Next thing you know, I put together a sample scenario showing subscription-based realtime data streaming to multiple web clients using web sockets. Check out the video below to see it in action.

You are seeing 9 separate browser instances getting realtime push-based updates from a local server using web sockets. When the browser loads, the html-based client makes a web socket connection, then requests all symbols from the server. The server then sends the stock symbol definitions back to the client and displays them within the HTML user interface. From there, the user can click on a stock symbol to subscribe to updates for that particular symbol. DISCLAIMER: All that data is randomly generated!

I put together this example for experimentation, but also to highlight a few technical scenarios for HTML-based applications. Specifically:

  • Realtime/push data in HTML-based apps
  • Per-client subscriptions for realtime data
  • Multi-series realtime data visualization in HTML-based apps

The server is an AIR app started by Kevin, based on the web sockets draft protocol. It is written in JavaScript, and the client is a HTML page to be viewed in the browser.

If you don’t feel like reading the full web sockets protocol reference, you can get a great overview from websocket.org or Wikipedia.

One thing to keep in mind is that web sockets are not widely supported in all browsers yet. There is a great reference matrix for web socket support from caniuse.com:

If you still aren’t sure if your browser supports web sockets, you can also check simply by visiting websocketstest.com/. If you want to test for web socket support within your own applications, you can easily check for support using Modernizr. Note: I didn’t add the Modernizr test in this example… I only tested in Chrome on OSX.

OK, now back to the sample application. All of the source code for this example is available on github at: https://github.com/triceam/Websocket-Streaming-Example.  To run it yourself, you first have to launch the server. You can do this on the command line by invoking ADL (part of the AIR SDK):

cd "/Applications/Adobe Flash Builder 4.6/sdks/4.6.0/bin"
./adl ~/Documents/dev/Websocket-Streaming-Example/server/application.xml

You’ll know the server is started b/c an air window will popup (you can ignore this, just don’t close it), and you will start seeing feed updates in the console output.

Once the server is running, open “client/client.html” in your browser. It will connect to the local server, and then request the list of symbols. If you click on a symbol, it will subscribe to that feed. Just click on the symbol name again to unsubscribe. You’ll know the feed is subscribed b/c the symbol will show up in a color (matching the corresponding feed on the chart). Again, let me reiterate that I only tested this in Chrome.

You can open up numerous client instances, and all will receive the same updates in real time for each subscribed stock symbol.

The “meat” of code for the server starts in server/scripts/server/server.js. Basically, the server loads a configuration file for the socket server, then creates a ConnectionManager and DataFeed (both of these are custom JS classes). The ConnectionManager class encapsulates all logic around socket connections. This includes managing the ServerSocket as well as all client socket instances and events. The DataFeed class handles data within the app. First, it generates random data, then sets up an interval to generate random data updates. For every data update, the ConnectionManager instance’s dispatch() method is invoked to send updates to all subscribed clients. Rather than trying to put lots of code snippets inline in this post (which would just be more confusing), check out the full source at: https://github.com/triceam/Websocket-Streaming-Example/tree/master/server

The client code all starts in client.html, with the application logic inside of client/scripts/client.js. Once the client interface loads, it connects to the web socket and adds the appropriate event handlers. Once subscribed to a data feed, realtime data will be returned via the web socket instance, transformed slightly to fit the data visualization structure, then rendered in an HTML canvas using the RGraph data visualization library. RGraph is free to get started with, however if you want to deploy a production app with it, you’ll need a license. You’ll notice that each feed updates independently, based upon the client subscriptions. Note: The data visualization is not temporally aligned… if you want the updates in time-sequence, there is a litte bit more work involved in the client-side data transformation.

Again, rather than trying to put lots of confusing code snippets inline in this post, check out the full client side source at: https://github.com/triceam/Websocket-Streaming-Example/tree/master/client

This example is intended to get your minds rolling with the concepts; it is not *yet* an all-encompassing enterprise solution. You can expect to see a few more data push scenarios here in the near future, based on different enterprise server technologies.

Enjoy!