The basics of developing an end-to-end mobile application using IBM Worklight and Dojo Mobile

This article describes things we learned through our experience using IBM® Worklight Studio and Dojo Mobile to develop an end-to-end mobile application for retail banking. Along with some fundamental information about these development tools and about developing mobile apps in general, sample source code is included to illustrate and help you apply these tips to your own mobile app development. This content is part of the IBM WebSphere Developer Technical Journal.

Denzil Menezes (dmeneze@us.ibm.com), IT Specialist Coop, IBM

Denzil Menezes has over 5 years of experience in J2EE systems development and integration. He is currently working on mobile application solutions at the IBM Global Solution Center, primarily using IBM Worklight and dojo mobile.



Karl Bishop (kfbishop@us.ibm.com), Senior Software Engineer, IBM

Karl Bishop is a Senior Software Engineer on the IBM Web Enablement and Support team. He works from the wilds of North Carolina. Karl works on various internal and external Web 2.0 and Mobile applications. He specializes in Dojo, Dojo Mobile, and Worklight based solutions.


developerWorks Contributing author
        level

Biao Hao (biaohao@us.ibm.com), Senior IT Architect, IBM

Biao Hao is a Certified Senior IT Architect in the IBM Global Solution Center in Dallas. Currently he is leading the development of mobile banking solutions and demonstrations, using IBM Mobile Foundation technology. He has over 15 years of experiences with integration middleware and tools using WebSphere products and solution architecture and development for banking and insurance industry.



12 September 2012

Also available in Chinese Portuguese Spanish

Introduction

Get Worklight now

Download IBM Worklight Developer Edition 5.0 now at no cost, and with no expiration date!

The IBM Global Solution Center team in Dallas developed a mobile application for retail banking. The app included many retail banking functions, such as branch and ATM location, contact, account balances and activities, funds transfer, and more. Designed for and deployed onto both iOS and Android smartphones, the app was built using IBM Worklight Studio with a hybrid approach. Dojo Mobile, a JavaScript framework for developing cross-platform mobile web applications, was used as the primary toolkit for implementing the mobile user interface, along with Worklight widgets.

The article describes key technical aspects in the design and development of the mobile application, including the design and implementation of the mobile user interface using Dojo Mobile, the Worklight project structure and environment optimization, the use of Dojo to reduce the effort of developing environment-specific artifacts, and the steps in developing a Worklight adapter — an essential component for integrating the application with enterprise systems. The integration with enterprise systems is illustrated in the included sample code using a REST service that simulates the account information in a banking system. The implementation of a security mechanism using Worklight authentication to protect resources (such as Worklight adapters) is also discussed. Sample code (developed and tested on Worklight Studio Developer Edition v5.0.0.0), as a subset of the overall mobile application, is included for illustration purposes.

Included here is information to help you get started:


Implementing a mobile user interface using Dojo Mobile

Figure 1 shows the home screen of the banking app on an iPhone. From here, the user can access account information and initiate transactions, locate an ATM or branch, and initiate contact for help.

There are two common UI design approaches you might consider for enabling a user to navigate between functions:

  • The tab bar approach uses a list of common functions, each shown as a button on the tab bar that is available on most screens. The user taps on a button to navigate to a specific function. This approach provides fast, one-click navigation to common functions. The drawback is the additional screen space used for the tab bar, reducing the screen space available for the functional area.
  • The list-of-functions approach lists most (if not all) functions as buttons on the screen. The advantage here is that each function gets more screen space to work with. The main drawback is that additional clicks are required for navigating, even to commonly used functions.

Both approaches are used in the sample mobile application described here. The list-of-functions approach is shown in Figure 1, in which three main functions (My Accounts, Locations and Contact) are listed as buttons. When the user navigates to My Accounts after authentication, common functions such as Accounts, Cash and Transfer are listed as buttons on the bottom tab bar, shown in Figure 2. Additional functions are displayed by clicking the More tab.

Figure 1. Home screen
Figure 1. Home screen
Figure 2. Accounts screen
Figure 2. Accounts screen

Dojo Mobile is an HTML5 mobile JavaScript™ framework that enables rapid development of mobile web applications with a native look and feel on modern mobile devices, such as iPhone, iPod Touch, iPad, and on Android and RIM smartphones and tablets. Using the hybrid approach, a Dojo Mobile app can make use of native device APIs, such as GPS location or barcode scanning, and can easily be packaged as a native app using IBM Worklight Studio.

Figure 3 shows the Accounts screen implemented using Dojo Mobile widgets (all the widgets noted in this section are a part of the dojox.mobile package):

  • The overall view (not shown) is a dojox.mobile.View, which contains a ScrollableView at the top and a TabBar at the bottom.
  • The top ScrollableView shows a scrollable list of accounts, with a Heading at the top and an EdgeToEdgeList at the bottom.
  • The Heading shows the title "Accounts" and contains a Back button and a ToolBarButton, "Logout."
  • The EdgeToEdgeList contains a list of ListItem, each showing an account summary.
  • The bottom TabBar contains a list of TabBarButton, each representing a common function such as Accounts, Cash, Transfer.
Figure 3. Account screen with Dojo Mobile widgets
Figure 3. Account screen with Dojo Mobile widgets

Listing 1 shows the code used to implement these widgets on this screen.

Listing 1. Code for Accounts screen in Figure 3
<div data-dojo-type="dojox.mobile.View" id="LoggedInView" class="mobileClass"  
 style="height: 100%;">
 <div id="AccountsView" data-dojo-type="dojox.mobile.ScrollableView"
  data-dojo-props="selected:true" class="mobileClass">
  <h2 data-dojo-type="dojox.mobile.Heading"
   data-dojo-props="fixed:'top', back:'Back', moveTo:'IndexView', fixed:'top'"
   style="font-size: 19px;" align="center">Accounts
    <div id="logoutBtn" data-dojo-type="dojox.mobile.ToolBarButton"
     data-dojo-props="label:'Logout', moveTo:'IndexView',  
     transition:'slide',transitionDir:'-1'"
     style="width: 45px; float: right;" class="mblColorBlue"></div>
  </h2>
  <ul id="accountContainer" style="margin-top: 40px;"
   data-dojo-type="dojox.mobile.EdgeToEdgeList" class="indexListStyle">
   <!-- List of Accounts will be populated at runtime using the custom widget template
    defined under folder 'custom/AccountWidget' -->
  </ul>
</div>
 <ul data-dojo-type="dojox.mobile.TabBar" data-dojo-props="fixed:'bottom'" style="height:
   11%; overflow-x: hidden;">
  <li data-dojo-type="dojox.mobile.TabBarButton" id="accountsTab" style="width: 20%"
   data-dojo-props="icon1:'./images/tabs/icon_128x128_accounts.png', 
   icon2:'./images/tabs/icon_128x128_accounts_blue.png', selected:'true'">Accounts</li>
  <li data-dojo-type="dojox.mobile.TabBarButton" style="width: 20%"
   data-dojo-props="icon1:'./images/tabs/icon_128x128_cash_gradient.png', 
   icon2:'./images/tabs/icon_128x128_cash_blue.png'">Cash</li>
  <li data-dojo-type="dojox.mobile.TabBarButton" style="width: 20%"
   data-dojo-props="icon1:'./images/tabs/icon_128x128_transfer_solid.png', 
   icon2:'./images/tabs/icon_128x128_transfer_solid_blue.png'">Transfer</li>
  <li data-dojo-type="dojox.mobile.TabBarButton" style="width: 20%"
   data-dojo-props=" icon1:'./images/tabs/icon_128x128_billPay.png', 
   icon2:'./images/tabs/icon_128x128_billPay_blue.png'">Bill Pay</li>
  <li data-dojo-type="dojox.mobile.TabBarButton" style="width: 20%"
   data-dojo-props="icon1:'./images/tabs/icon_128x128_more.png', 
   icon2:'./images/tabs/icon_128x128_more_blue.png'">More</li>
 </ul>
</div>

Worklight project structure using Dojo

Worklight Studio provides an integrated development environment for cross-platform mobile applications. The Worklight project structure contains an apps folder that can contain one or more applications. An application can have multiple Worklight environments, depending on the platforms to be supported by the application. OpenFNApp in Figure 4 contains a common folder and both android and iphone environments for creating applications to be deployed to Android and iPhone devices. The dojo folder is automatically included when you create a Dojo-enabled application in Worklight.

Figure 4. Worklight project structure
Figure 4. Worklight project structure

The common folder in Figure 5 contains artifacts that will be shared by all environments. It contains a main HTML file (OpenFNApp.html) that is loaded on application startup, and other typical web resource folders such as js, css, and images.

Figure 5. Common folder structure
Figure 5. Common folder structure

Environment-specific files should be included in the iphone or android folder, as appropriate. These folders have the same folder structure as the common folder. For example, if there are certain styles that need to be applied to a device-specific environment, then a CSS file can be created under the appropriate folder with the same name as the corresponding file in the common/css folder. When the native project is built, Worklight will append environment-specific css files to the common css files with the same names when generating the native code. The environment-specific styles will take precedence over the styles included in the common folder. Similarly, if the main HTML file is placed under the android or iphone folder, this HTML file will replace the main HTML file in the common folder and will be used by Worklight to build the native application. Environment-specific JavaScript files with the same names will be appended to each other. In the application described here, because of the cross-platform capability in Dojo, most of the code is in the common folder and shared in both iphone and android environments. Environment-specific code is added only when it is needed. For example, the OpenFN.css files in the android and iphone environments contain different height rules for AccountsView (Listing 1), whereas all the common application styles are defined in the common/css/OpenFN.css file.

Figure 6. Environment-specific file
Figure 6. Environment-specific file

A custom widget, AccountWidget, is used to display account information within the application. This widget is included in the common/custom folder (see Resources for details on implementing custom widgets). Listing 2 shows the JavaScript code to load the custom widget.

Listing 2. Code to load custom widget
<script>
 var base = location.href.split("/");
 base.pop();
 base = base.join("/");
 var dojoConfig = {
 isDebug : false,
 async : true,
 parseOnLoad : false,
 packages : [ {
  name : "custom",
  location : base + "/custom"
 } ]
};	
</script>

For cross-platform application development, the dojox/mobile/deviceTheme module (Listing 3) automatically detects the device and includes the necessary stylesheets for rendering on that device. This facilitates a native look and feel of the application regardless of platform while utilizing the same code base.

Listing 3. Loading Dojo modules
<script type="text/javascript">
 require(// module identifiers
  ["dojo/parser", "dojo/_base/connect", "dojox/mobile",
    "dojox/mobile/deviceTheme", "dojox/mobile/compat",
    "dojox/mobile/Button", "dojox/mobile/TabBar", "dojox/mobile/TabBarButton",
    "dojox/mobile/ScrollableView"],
     // Callback function invoked on dependencies evaluation results
     function(parser, connect) {
      dojo.ready(function() {
      parser.parse();
      dojo.style("content", "display", "");
      connect.connect(dijit.byId("myAccountsListItem"), "onClick", null, getAccounts);
      });
     });
</script>

Developing Worklight adapters

Worklight adapters provide a single interface for a client application to communicate with backend systems. There are several types of adapters, including HTTP connections, SOAP services, SQL database calls, and more. These adapters can be secured and monitored.

An AccountsAdapter is used here to invoke a REST service that retrieves the user’s account information. The adapter consists of these files (Figure 7):

  • A configuration XML file for specifying connectivity options and listing the procedures exposed to the client application or other adapters.
  • A JavaScript file for implementing procedures declared in the configuration XML file.
  • Optional XSL files for transforming the retrieved raw XML data.
Figure 7. Worklight adapter files
Figure 7. Worklight adapter files

The configuration XML file for AccountsAdapter (Listing 4) specifies the connection details (such as connection policy that includes protocol, domain, and port) the adapter needs for the connection to retrieve the account information. The adapter resource is protected by using the Realm defined in the authenticationRealm attribute, which ensures the user is authenticated before the adapter procedure is invoked. (Authentication protection is set up in the next section.)

Listing 4. Configuration XML for AccountsAdapter
<xml version="1.0" encoding="UTF-8"?>
<wl:adapter name="AccountsAdapter" authenticationRealm="AccountsAuthRealm"
. . . . . . . 
 <displayName>AccountsAdapter</displayName>
 <description>AccountsAdapter</description>
 <connectivity>
   <!--The configuration below assumes the REST service is deployed 
	on localhost with port 9080 --> 
   <connectionPolicy xsi:type="http:HTTPConnectionPolicyType">
    <protocol>http</protocol>
    <domain>localhost</domain>
    <port>9080</port>
   </connectionPolicy>
  <loadConstraints maxConcurrentConnectionsPerNode="2" />
 </connectivity>
<procedure name="getAccounts" requiresAuthentication="true"/>
</wl:adapter>

The adapter JavaScript file (Listing 5) contains the implementation code for the procedure defined in the configuration XML file. The procedure getAccounts invokes a REST service that retrieves account information for an authenticated user. There is no need for the client application to pass the user information to the adapter procedure since it can be obtained using WL.Server.getActiveUser() once the user is authenticated. The account information REST service is invoked using the WL.Server.invokeHttp call, which returns the data back to the client application in JSON format.

Listing 5. Adapter JavaScript code
function getAccounts() {
 . . . . 	
 var userObj = WL.Server.getActiveUser();
 var serviceURL = "/OFNWebServices/rest/account/getAccounts";
 . . . . .
 
 return WL.Server.invokeHttp({
	 method : 'get',
	 returnedContentType : 'json',
	 path : serviceURL,
	 parameters : {
	  username : userObj.userId
	 }
        });
 }

Implementing Worklight authentication

Entities like Worklight adapters can be protected by an authentication process that defines steps to be taken before an entity is accessed. AccountsAdapter is protected; the user needs to be authenticated before retrieving the account information using the back end REST service. Worklight authentication is used to implement this security measure:

  1. First, an authentication realm is defined in the authenticationConfig.xml file in the folder server/conf. The realm named AccountsAuthRealm (Listing 6) specifies the login-function and logout-function attributes. These attributes define the adapter methods to call when the login and logout functions are performed on the server end.
    Listing 6. Authentication realm in authenticationConfig.xml
    <realm name="AccountsAuthRealm" loginModule="AccountsAuthModule">
     <className>com.worklight.integration.auth.AdapterAuthenticator</className>
     <parameter name="login-function" value="AuthenticationAdapter.onAuthRequired" /> 
     <parameter name="logout-function" value="AuthenticationAdapter.onLogout" />
    </realm>
  2. A login module is then defined in the same authenticationConfig.xml file. In Listing 7, AccountsAuthModule uses com.worklight.core.auth.ext.NonValidatingLoginModule, indicating that the authentication will be performed by a developer-defined process within the adapter.
    Listing 7. Login module in authenticationConfig.xml
    <loginModule name="AccountsAuthModule" canBeResourceLogin="true"
     isIdentityAssociationKey="false">
     <className>com.worklight.core.auth.ext.NonValidatingLoginModule</className>
    </loginModule>

    The login and logout functions are defined in the adapter named AuthenticationAdapter (Listing 8).

    Listing 8. onAuthRequired and onLogout functions in AuthenticationAdapter-impl.js
    function onAuthRequired(headers, errorMessage){
     errorMessage = errorMessage ? errorMessage : null;
     return {
      authRequired: true,
      errorMessage: errorMessage
     };
    }
    function onLogout(){
     WL.Logger.debug("Logged out");
    }
  3. In Listing 9, procedure submitAuthentication is defined in the AuthenticationAdapter.xml file. This procedure will be invoked from the client application for validating user credentials.
    Listing 9. submitAuthentication in AuthenticationAdapter.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <wl:adapter name="AuthenticationAdapter"
     . . . . 
     <procedure name="submitAuthentication"/>	
    </wl:adapter>

    Procedure submitAuthentication (see Listing 10) takes in the username and password as parameters that can be validated against a user registry. If successful, the userIdentity object is created and placed in the pool of active users using the WL.Server.setActiveUser() method. A JSON object with parameter authRequired:false is also returned, indicating a successful authentication. If the user is not authenticated, a JSON object with parameter authRequired:true is returned indicating that authentication is still required.

    Listing 10. submitAuthentication in AuthenticationAdapter-impl.js
    function submitAuthentication(username, password) {
     if ((username=="wl" && password == "wl") || (username=="worklight" && password ==
      "worklight") ){
      WL.Logger.debug("Auth :: SUCCESS");
      var userIdentity = {
       userId: username,
       displayName: username, 
       attributes: {}
     };
     WL.Server.setActiveUser("AccountsAuthRealm",userIdentity);
     return {
      authRequired: false
      };
     }else{
      WL.Logger.debug("Auth :: FAILURE");
      return onAuthRequired(null, "Invalid login credentials");
     }
    }
  4. Completing the authentication on the server side, AccountsAdapter is protected by specifying the realm AccountsAuthRealm for the authenticationRealm attribute in AccountsAdapter XML (Listing 11).
    Listing 11. authenticationRealm in AccountsAdapter.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <wl:adapter name="AccountsAdapter" authenticationRealm="AccountsAuthRealm"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     xmlns:wl="http://www.worklight.com/integration"
     xmlns:http="http://www.worklight.com/integration/http">
    . . . . 
    <procedure name="getAccounts" requiresAuthentication="true"/>
    </wl:adapter>

Now, let’s look at authentication implemented on the client side.

  1. A JavaScript file auth.js is automatically generated to provide method skeletons to implement the Worklight authentication. The init function (Listing 12) is used for initialization. An event handler is defined for clicking the Sign On button (with ID submitAuthBtn). The event handling function invokes the authentication adapter procedure AuthenticationAdapter.submitAuthentication by passing the username and password from the input fields. Similarly, the event handler for clicking the Logout button (with ID logoutBtn) is also defined by invoking WL.Client.logout(‘AccountsAuthRealm’).
    Listing 12. init function in js/auth.js
    init : function() {
     // Authenticator initialization code
     require([ "dojo", "dojo/_base/connect" ],
      function(dojo, connect) {
       connect.connect(dojo.byId("submitAuthBtn"),"onclick",null,function() {
       var username = document.getElementById("usernameInputField").value;
       var password = document.getElementById("passwordInputField").value;
       var invocationData = {
       adapter : "AuthenticationAdapter",
         procedure : "submitAuthentication",
         parameters : [ username,password ]
       };
       WL.Client.invokeProcedure(
         invocationData,
         {onSuccess : signOnSuccess,
          onFailure : signOnFailure
       });
     });
      connect.connect(dojo.byId("logoutBtn"), "onclick", null, function() {
       WL.Client.logout('AccountsAuthRealm');
      });
     });
    }
  2. The isLoginFormResponse() function (Listing 13) is invoked once a response is received from the server side. The function returns a boolean indicating if the authentication is successful or not.
    Listing 13. isLoginFormResponse function in js/auth.js
    isLoginFormResponse : function(response) {
     if (!response || !response.responseJSON || response.responseText == null) {
      return false;
     }
     return response.responseJSON.authRequired;
     }
  3. The onBeforeLogin() function (Listing 14) is used to clear input fields and prepare for the display of an authentication view. The authentication view can be a login page with inputs for username and password.
    Listing 14. onBeforeLogin function in js/auth.js
    onBeforeLogin : function(response, username, onSubmit, onCancel) {
     // clean up the input login fields
     document.getElementById("usernameInputField").value = "";
     document.getElementById("passwordInputField").value = "";
     document.getElementById("AuthInfo").innerHTML = response.responseJSON.errorMessage;
     }
  4. Function onShowLogin() or onHideLogin() (Listing 15) displays or hides the login page. These are automatically invoked based on the boolean returned from isLoginFormResponse. If the authentication is successful, onHideLogin will be invoked. Otherwise, onShowLogin will be invoked. In this example, the onHideLogin function does not do anything. Instead, a callback function signOnSuccess() is specified for invoking the authentication adapter (Listing 12). Function signOnSuccess() calls another function getAccounts() to change the screen from the login view to the accounts view.
    Listing 15. onShowLogin / onHideLogin function in auth.js
    onShowLogin : function() {
     require([ "dijit" ], function(dijit) {
      var currentView = dijit.byId("LoginView").getShowingView();
      var currentViewId = currentView.get("id");
      if (currentViewId != "LoginView") {
       currentView.performTransition("LoginView", 1, "slide", null);
      }	
     });
    },
    onHideLogin : function() {
    }
    . . . . 
    function signOnSuccess(response) {
     getAccounts();
    }

Conclusion

This article described experiences using Worklight and Dojo Mobile to develop an end-to-end mobile application. Technical topics, such as mobile user interface implementation using Dojo Mobile, Worklight adapter development, and Worklight authentication, were described.


Acknowledgements

We thank our colleagues Rod Fleming and Catherine McCauley for their support that led to the success of this project.


Download

DescriptionNameSize
Code sampleOFNProjectSampleCode.zip30 MB

Resources

Learn

Get products and technologies

Discuss

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into WebSphere on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=WebSphere, Mobile development, Agile transformation
ArticleID=834444
ArticleTitle=The basics of developing an end-to-end mobile application using IBM Worklight and Dojo Mobile
publish-date=09122012