Extending HTML5 Mobile Apps with C++ in MoSync

Invoke C++ Code from JavaScript

The following example code is based on the HTML5/JS/C++ Hybrid Project Template. This template illustrates how to invoke custom C++ code from JavaScript. The UI has buttons for making the device vibrate and beep.
To create a project based on this template, launch MoSync SDK, and create an app in the Eclipse-based IDE, using the HTML5/JS/C++ Hybrid Project template. Then you will get the source code discussed below.
The template app uses the Wormhole C++ library (classes HybridMoblet and MessageStream) and the JavaScript libraries included in the file wormhole.js (all included with the application template).

Sending String Messages

It is good to know that two message formats are supported by Wormhole: JSON messages and String stream messages. The example we discuss here uses String streams.
String streams are a performant way of sending messages from JavaScript to C++. This method is generally faster than JSON messages (on some platforms 20x faster). Parsing on the C++ side is very efficient, and streams of string messages are concatenated before passed to C++. This makes sending a large number of small messages efficient.
The JavaScript function mosync.bridge.send() is used to send string messages to C++:

mosync.bridge.send(messageArray, callbackFunction)
This function takes two parameters. The first parameter "messageArray" is an array of strings.These values will be sent to C++. By convention, the protocol for sending custom messages is based on the first element in the array being the string "Custom", and the second element being the name ("action") of the message, like "Beep". Then follows any parameters. (See example below.)
The second parameter "callbackFunction" is an optional function that you can use to send back a result value from C++ to JavaScript. The communication mechanism is asynchronous, which is why a callback function is used to pass the result back from C++ to JavaScript.
Here is an example of a JavaScript call that sends a custom message C++ to make the device vibrate (here we do not need to use any callback function):

mosync.bridge.send(["Custom", "Vibrate", "500"]);
This JavaScript code is found in file index.html in the generated template application.
In the corresponding implementation in C++, the message "Vibrate" is first registered in the constructor of the the application's Moblet, in class MyMoblet. A Moblet is the main object in a MoSync application, and the constructor is a good place to declare message to method bindings.
The addMessage method binds the message name to a C++ method:

addMessageFun(

    "Vibrate",

    (FunTable::MessageHandlerFun)&MyMoblet::vibrate);
This C++ code is found in file main.cpp in the generated template application.
Here is the C++ code for the vibrate method:

void vibrate(Wormhole::MessageStream& message)

{

    int duration = MAUtil::stringToInteger(message.getNext());

    maVibrate(duration);

}
The call to message.getNext() retrives a char pointer (char*) to the next parameter in the message stream, in this case the duration time ("500"). If there are no more messages, NULL is returned.
Note that when a message handling method is called, the first two elements of the original string array sent from JavaScript have been "consumed" by the message handling framework, and the first call to message.getNext() will therefore return a pointer to the first parameter in our message, the value "500".
You can also have messages with no parameters. The "Beep" message is an example of this. Here is the call made from JavaScript:

mosync.bridge.send(["Custom", "Beep"]);
The message handler is registered like this in C++:

addMessageFun(

    "Beep",

    (FunTable::MessageHandlerFun)&MyMoblet::beep);
And here is the C++ code for the beep method:

void beep(Wormhole::MessageStream& message)

{

    maSoundPlay(BEEP_WAV, 0, maGetDataSize(BEEP_WAV));

}
Next, we will take alook at how to return values from C++ to JavaScript.

How to Call JavaScript Code from C++

Note that the code below is not part of the code you get with the template application. You can however type it in yourself, to further explore how the code works.
To evaluate JavaScript code in the WebView from C++, you can use the HybridMoblet::callJS() method. Here is an example:

callJS("alert('Hello World')");
The following snippets illustrate how to invoke C++ from JavaScript and call a JavaScript callback function.
Here is the JavaScript part:

mosync.bridge.send(

    ["Custom", "GetScreenSize"],

    function(width, height) {

        alert("Screen size: " + width + ", " + height);

    });
And here is the C++ part. First register the message handler in the MyMoblet constructor:

addMessageFun(

    "GetScreenSize",

    (FunTable::MessageHandlerFun)&MyMoblet::getScreenSize);
Then define the getScreenSize method. Here we create a script that invokes the JavaScript function mosync.bridge.reply() with the callbackId of the message and the result parameters (this will call the function specified above, in the call to mosync.bridge.send):

void getScreenSize()

{

    const char* callbackId = message.getNext();

    char script[512];

    sprintf(

        script,

        "mosync.bridge.reply(%d, %d, %d)",

        callbackId,

        EXTENT_X(maGetScrSize()),

        EXTENT_Y(maGetScrSize()));

    callJS(script);

}
The JavaScript function mosync.bridge.reply() always takes the callbackId as the first argument. You can then supply a variable number of arguments (zero to many) that will be passed to the callback function in JavaScript.

Comments

Popular posts from this blog

How to draw an overlay on a SurfaceView used by Camera on Android?

Create EditText with dropdown in android

Android TCP Connection Chat application