Introduction
“Interface Design for MoSync applications” … doesn’t sound very interesting! As a matter of fact, it isn’t. There is not much new to what I am going to discuss here. The same age old problem, the same old solution, what’s new is implementing the solution for MoSync. This blog post is based more on personal experience of working with MoSync. What’s MoSync? I’ll talk about MoSync more in the next section, for now you can think of a powerful-yet-not-much-popular cross platform mobile application development framework.
MoSync provides a number of ways for creating user interfaces, based on what your application requires and what you are most comfortable with, you can choose your pick. This blog post discusses some of these methods to create interfaces for your applications, their pros and cons and concludes with a class that I wrote to simplify my requirement for designing user interfaces for MoSync applications.
What is MoSync?
MoSync is an open-source cross-platform mobile application development environment that makes it easy to develop apps for all major mobile platforms from a single code base. There are a number of such frameworks out there in the market, you can see a comparison of most of the available options on this wikipedia page.
I’ll just give a quick highlight of MoSync features:
- Supports application development using C/C++, HTML5/JavaScript or a combination of both.
- Supports most of the major platforms: Android, Blackberry, iOS, Java ME MIDP, Moblin, Symbian, Windows Mobile, Windows Phone
- Supports OpenGL
- Supports most of the device features
- Compiles native apps for all supported platforms without any extra footprint which results in small sized smooth running applications.
- Well documented API and a number of example applications.
- MoSync Reload – Web based tool to quickly create native applications using HTML5/JavaScipt and simultaneously testing on multiple test devices/emulators.
You can explore more about MoSync here. I am sure you’ll find more interesting and useful stuff about MoSync on their website.
Designing Interfaces with MoSync
This post is about designing interfaces, so, I’ll skip everything else and directly jump to interface design with MoSync. MoSync provides multiple solutions for cross-platform user interface development. You can develop your MoSync applications with plain HTML/HTML5 UI or Native UI or Java based UI for older devices. Along with supporting multiple UI, MoSync also provides multiple libraries for implementing these UI. Following table gives a little more detailed view:
Library/API | Pros & Cons | |
Vanilla HTML/HTML5 |
|
|
Wormhole NativeUI JavaScript API |
|
|
MAUI C++ Library |
|
|
NativeUI C++ Library |
|
|
Widget C API |
|
That’s a lot of options for a single framework! You can check this page for more detailed description and example applications.
The Problem
When I started working with MoSync, I was working on a TMDB API based movie application. The target platforms were Android, iOS and Windows with native look and feel. You guessed it right! I had an option of using Native C++ library or Wormhole NativeUI JavaScript API or Widget C API.
The Native C++ library suffers the same problem as most of the UI libraries. It provides a number of useful classes, but you need to write C++ code create your interfaces. There is nothing wrong with writing code to create interfaces, except:
- it makes the task difficult and repetitive
- adds additional responsibility of managing widget objects
- anytime you want to tweak the user interface just a little bit, you need to recompile your application
- maintaining multiple interfaces for various device resolutions and orientations is tedious and error prone
The MoSync Wormhole library provides a bridge between the HTML5/JavaScript and C++ layers of your application. Using the wormhole library it is possible to use HTML5 markup to create NativeUI interfaces. The HTML5 in this case is used more as XML markup, you create div tags for everything with some special data attributes to specify widget properties. What MoSync does here is create a hidden WebView which parses the HTML5 markup and use JavaScript to navigate the DOM and create NativeUI widgets for each HTML5 element. I still couldn’t use this approach because:
- This approach is reported to be not efficient on some platforms e.g. Windows phone.
- The NativeUI widgets created this way are accessible via JavaScript just as a web page e.g. getElementById(<id of the widget>), I would have had to write code to be able to access them from C++ code.
- The JavaScript-C++ bridge is not very intuitive. it just provides way to expose functions and not objects. Also, JavaScript being inherently asynchronous and C++ being synchronous, it’s difficult to write neat code.
- The life-cycle of widgets is out of control.
The Solution
In my case, rest of the whole application was written in C++, all I wanted was to somehow use some code-free markup to create interfaces dynamically at run time. What we required was:
- To be able to write some markup to define UI.
- Ability to load UI definition from multiple JSON files.
- Easy access to UI widgets from code.
- Move the responsibility to create/destroy widgets to some low level class.
Similar methods are used by many frameworks and UI libraries e.g. MFC uses .rc resource files to define user interfaces, Qt uses .ui xml files. MoSync supports both XML and JSON parsing. Personally I am not a very big fan of XML (no offence, but those tags make me feel uneasy!), so I went with JSON to define UI.
Following is a sample UI JSON file:
{ "Properties": { "fillHorizontally": { "width": -1 }, "fillVertically": { "height": -1 }, "fillParent": { "inheritProperty": ["fillVertically", "fillHorizontally"] }, "redEditBox": { "fontColor": "0xee2233", "placeholderFontColor": "0x33eeff" } }, "MainLayout" : { "class": "VerticalLayout", "properties": { "childVerticalAlignment": "top", "backgroundColor": "0xeeeeee", "inheritProperty": ["fillParent"] }, "AnotherTextBox": { "class": "EditBox", "properties": { "placeholder": "Hey!!!", "inheritProperty": ["fillHorizontally", "redEditBox"] } } }, "MainScreen": { "class": "Screen", "MainScreenLayout": { "class": "R:MainLayout", "ATextBox": { "class": "R:MainLayout.AnotherTextBox", "properties": { "placeholder": "Hello World!!!" } } } } }
The above JSON file shows some of the main functionality that I wanted to be able to achieve by defining UI using a markup:
- Widget definition: Defining any widget is simple. For any widget, you specify the ‘class’ of widget, ‘properties’ if any, followed by any child widget definition using the same approach. Check out the “MainLayout” and “MainScreen” objects in the above JSON.
- Global Properties: This idea was inspired by CSS. The idea here is to be able to define some named properties and apply them to any widget. In the above example we have defined a “Properties” object (line 2). This object contains some more objects that define some widget properties. Now, any widget can ‘inherit’ these properties, so that they need not be defined again and again for multiple widgets. Also, it enables us to easily skin our application without any code change. If you check the JSON, you’ll see the use of “inheritProperty” to inherit any predefined property.
- References to widgets: Some UI elements repeat again and again e.g. the header and footer on several screens, or some section of UI that gets repeated on several screens. The idea is to be able to define a widget (which may have child widgets as well) and use it at several other places. e.g. check the “MainScreenLayout” child object of the “MainScreen”. The specified class starts with ‘R:’ (stands for Reference) followed by complete name of the widget we want to refer. In this case the “MainScreenLayout” refers to the “MainLayout” definition. You can override any of the properties or add more children by specifying them for the referencing widget.
- The “inheritProperties” and widget references may be nested i.e. a widget may inherit properties which in turn may be inheriting other properties and so on. Similarly a widget may reference another widget definition which may be referencing to another widget.
I wrote a class to dynamically create UI at run time from JSON files. The class handles above scenarios and supports loading multiple JSON files, so that it is possible to define global properties in a separate file and keeping UI for different screens in different files or any other way we want to organize the UI definition.
As for accessing the widgets easily, the class provides a getWidget() function, which takes the complete widget name as argument e.g. “MainScreen.MainScreenLayout” and returns the widget. Internally it maintains a map of name-widget pairs. If the widget already exists, it is returned otherwise the widget is created and returned. In case there are any child widgets, they are created as well and added to the widget map. As a developer, I need not worry about creating or styling my widgets I can just magically get a reference to them wherever I need.
You might be bothered with what if you try to get a widget without creating its parent. Well, the widget will be created without a parent, but as soon as the parent widget gets requested, it will be created and any already created child widgets will be added as children to it.
Regarding destroying any widget, the class provides a destroyWidget() function, which again takes complete name of a widget and destroys it. This function is used by another higher level class – ScreenManager. This class handles creating/displaying/hiding/destroying screens. When a screen gets lowered, it automatically gets destroyed to release any acquired resources.
For maintaining multiple UI for various devices, I can define multiple JSON files for same screen. The ScreenManager can take care of picking the right one based on screen resolution or orientation. All I need to take care of is using the same widget names and the rest of the code will keep working without any change!
Conclusion
MoSync is a very powerful framework to develop cross platform applications. Although it supports multiple UI solutions and libraries to implement them, there is still scope for making life easier for developers. The class I wrote works quite well for my requirements, but it can still be improved in both efficiency and functionality e.g. support for some sort of event binding in the JSON file itself would be great !!!