Creating a RemObjects SDK Client Widget for iBooks - Part 3

This is the 3rd article in a 4 part series

  1. Using DashCode to create an interactive widget
  2. Creating an interactive widget without Dashcode
  3. Creating a RemObjects SDK client widget (this article)
  4. Creating a Data Abstract client widget

If you are new to creating widgets, take a look at the previous articles where I outline creating them with Dashcode and without. This article discusses using RemObjects SDK in both Dashcode widgets and in iBooks 2 on the iPad via iBooks Author.

When I first heard that iBooks Author supported interactive widgets powered by JavaScript, I immediately wondered if it would work with a widget that was a JavaScript client for a RemObjects SDK server. I started using Dashcode to create the widget, so that is where we will start in this article.

MegaDemo JavaScript Client

We will build a client for the MegaDemo Server. A client demo ships with the Xcode version of RemObjects SDK & Data Abstract. We will create a simple client to show how creating a JavaScript client works.

For this demo we are making to work you will need a MegaDemo Server running from .NET or Delphi. If you have a different server you want to connect with, you can easily adapt the code we are writing to work with that server instead, but either way you need a server running you can connect too.

Create a Dashcode Project

Create a new Dashcode custom widget. Since our goal is to connect to a network server and deploy to the iPad, the very first thing we need to do is go to Widget Attributes and put a check mark in Allow Network Access, otherwise we will get an error when we try to call remote methods. To support deploying to the iPad we need to go to Run & Share and change the Minimum OS X version to 10.4.0 (backward-compatible).

Adding RO/JS to a Dashcode Project

To create an RemObjects SDK project we need to add the RemObjectsSDK.js library to this Dashcode project. If you have a .NET or Delphi install, you can copy it from the folder:

C:\Program Files (x86)\RemObjects Software\RemObjects SDK for JavaScript\Source

Otherwise, you can download a compressed version from our sample server on our website and save it locally.

http://www.remobjects.com:8099/js/RemObjectsSDK.js

Simply drag the RemObjectsSDK.js file from Finder to the Files pane in Dashcode. That will copy it into the project.

The Server Interface File

For our client to communicate with the server we need an interface file that provides the proxy objects. Luckily, the rodl2objc tool that comes with RemObjects SDK also has the ability to generate a JavaScript interface file from the server RODL file.

First, locate the MegaServer.RODL file that comes in the samples folder for RemObjects SDK. The default location is usually

/Developer/RemObjects Software/Samples/RemObjects SDK/Mac OS X/Mega Client

The .RODL file should open with rodl2objc, if not, open the rodl2objc tool in the tools folder and then open the .RODL file.

MegaServer.RODL in rodl2objc

Once the .RODL file is open in rodl2objc, you can click on the Intf.js tab and browse the JavaScript source it generates.

JavaScript interface from MegaServer.RODL in rodl2objc

When you are ready, use the Save JavaScript Intf Code button on the Summary tab. Save it with the default filename MegaDemoLibrary_Intf.js in a convenient location. Then add it to your Dashcode project just like you did with the library.

Referencing new JavaScript Files from the Main HTML File

Adding the JavaScript files to the project isn’t enough. We also need to reference them from the Main HTML file to make them accessible in the project. This is done by adding the following lines to the `` section of the main.html file.

<scripttype="text/javascript"src="RemObjectsSDK.js"charset="utf-8"></script><scripttype="text/javascript"src="MegaDemoLibrary_intf.js"charset="utf-8"></script>

You will see a lot of similar lines referencing other JavaScript libraries in there already. Just insert the ones above in the middle of those.

Adding a Log

Because this is a demo, it is really useful to have a log where we can log any necessary information. We will do this in two parts: A TextArea in the HTML document and some AddLog methods in the JavaScript file. Let’s start with the TextArea.

In the visual widget design area, drop a Text Area part from the library. In the inspector, change the ID to log.

In the main.js file, add the following JavaScript to make working with the log text area easier.

function AddToLog(message){var ta = document.getElementById("log"); ta.value+= message; ta.scrollTop= ta.scrollHeight;}   function AddLineToLog(message){ AddToLog(message); document.getElementById("log").value+="\n";}

Adding a Log in Dashcode

Setting Up the Service

All calls to the server go through a service object. Before we can create a service object, we need a way to specify the server’s address. Add a Text Field part from the library. Give it a name of serverUrl and give it a value of the server address and port you are testing with. For example 192.168.0.2:8099. Don’t use 127.0.0.1, even if it is on your local machine, because when you deploy it to your iPad, it won’t be local anymore.

Next, we need to add the JavaScript to main.js to create a service object that is able to connect to that server. You’ll notice this uses our AddToLog function from earlier to log what happens.

var Service;// Main service objectvar svcUrl;   function createService(){// This gives our script access to the libraries it needsfunction includeScript(scriptSrc, callback){var headID = document.getElementsByTagName("head")[0];var newScript = document.createElement('script'); newScript.type='text/javascript'; newScript.onload= callback; newScript.src= scriptSrc; headID.appendChild(newScript);}   function connectToService(){ AddLineToLog("------------------------"); svcUrl +='json' AddLineToLog("Service Url: "+ svcUrl); Service =new MegaDemoService(new RemObjects.SDK.HTTPClientChannel(svcUrl),// Safai doesn't support Binary, so stick with JSONMessage new RemObjects.SDK.JSONMessage()); AddLineToLog("Message: JSONMessage:");}// build the service URL svcUrl ="http://"+ document.getElementById("serverUrl").value+"/"; includeScript("RemObjectsSDK.js",function(){ includeScript("MegaDemoLibrary_intf.js",function(){ includeScript("main.js", connectToService())})});}

Notice we are using the JSONMessage format. RemObjects SDK for JavaScript also supports the more efficient BinMessage format, unfortunately Safari (both on the iPad and on Mac OS X) doesn’t support binary data because it sends data to the server via XMLHttpRequest as zero-terminated string, so cuts it at first zero occurrence. So we stick with JSONMessage.

Locate the function load() is in the Main.js file. This function is called when the widget is loaded and ready to go. Add a call to createService() here to attempt to automatically connect to the default service when the widget first loads.

Just in case we want to connect to a different server, we will add a Button part from the library. For the button’s onclick event, have it call the createService() function above.

Adding the CreateService function in Dashcode

Getting the Server Time

The easiest function to implemenet and to make sure everything is working is the GetServerTime function because it doesn’t have any inputs.

Here is the JavaScript to call the GetServerTime function on the server:

function BeginGetServerTimeMethod(){ AddLineToLog('----------------------'); AddLineToLog('Method: GetServerTime;'); AddToLog('Sending request...'); Service.GetServerTime(function(result){ AddLineToLog(' ok.'); AddLineToLog('Result is '+ result); AddLineToLog('Done.');},function(msg, ex){if(ex){ AddLineToLog(" Error: "+ ex);}else AddLineToLog(msg.getErrorMessage());});     AddToLog('Waiting for response... ');}

The heart of this is the call to Service.GetServerTime. This uses the Service object reference we created earlier and calls the GetServerTime method. This method on the service proxy object maps to the same method on the remote server.

We provide two parameters to this method. The first is a function that is called ‘on success’. It has a single parameter of result. In that function we simply log the result to our log via the AddToLog function.

The second parameter is another function that is called ‘in the case of an error’. It has two parameters: msg, ex. Ex is an exception, while msg is actually a JSONMessage (in this case), which gives us access to the error message, as well as client ID, data stream, etc.

With that JavaScript in place, we just need a button part from the library to call it. On the behaviors tab of the Inspector, select the BeginGetServerTimeMethod for the onclick event hander.

Now let’s run our widget and see if everything works.

If you see a line that just says “Response:” and no time is returned or you get some odd error, make sure the serverURL is correct and your server is running. Once you get this function working, you are ready to start implementing the other functions.

The Sum Method

The Sum method takes two numbers and returns their sum. Here is the code to call this method:

function BeginSumMethod(){ AddLineToLog('----------------------');   var A = document.getElementById("editA").value;var B = document.getElementById("editB").value;   AddLineToLog('Method: Sum; Params: A='+ A +'; B='+ B +';'); AddToLog('Sending request...'); Service.Sum(A, B, SuccessSumMethod, ErrorSumMethod);   AddToLog('Waiting for response... ');   function SuccessSumMethod(result){ AddLineToLog(' ok.'); AddLineToLog('Result is '+ result); AddLineToLog('Done.');}   function ErrorSumMethod(msg, ex){if(ex){ AddLineToLog(" Error: "+ ex);}else AddLineToLog(msg.getErrorMessage());}   }

This gets the numbers from the HTML elements editA & editB. Go ahead and add two Text Field parts to the widget with those IDs. I like to initialize the values with a valid integer value to make testing easier.

When the Sum method is called, it passes those two values along with two functions much like last time. In the SuccessSumMethod function, it displays the sum in the log.

Now add a button with an onclick event handler that calls BeginSumMethod(). When the function is called, the sum of the two numbers provided will be added to the log. It is important that, when you run it, the values of editA & editB are numeric or the call to BeginSumMethod will result in an error.

Other Methods

There are some other methods supported by the MegaDemo, like EchoPerson. You can discover those methods in the MegaDemoLibrary_intf.js file. The implementation of those is similar. Feel free to implement those on your own.

Deploying to iBooks Author

When you have implemented and tested all the methods you want, go to Save & Share (verify the version is 10.4.0) and click Save to Disk (lower right hand corner). Save your widget someplace convenient.

Fire up iBooks Author, add an HTML widget and then add the new widget you just created to that HTML widget.

Download a Sample

You can download my sample implementation.

Things to Remember

  1. No alert calls – this is a limitation on the iPad. It will hang your browser.
  2. Turn on Allow Network Access under Widget Attributes.
  3. Set the Minimum Mac OS X version to 10.4.0 (backward-compatible) under Run & Share, so it will work on the iPad.
  4. All JavaScript libraries must be referenced from the Main HTML file.
  5. The RemObjects SDK supports strong types, even though JavaScript is very flexible with its types. Make sure you are sending the expected data type.

Conclusion

Because RemObjects SDK for JavaScript is natively developed in JavaScript using best practices, it just works on any platform that JavaScript works on.

jim

0