Cross-platform application development for desktop, mobile and embedded with modern web technology

The field of web technology is evolving at a rapid pace. Unlike Qt, which offers a complete, prepackaged solution, there is a multitude of tools and libraries which need to be combined into a functional stack. This article presents a stack proven in cross-platform projects and our experience gathered with it.

Introduction

Modern web technology provides a powerful foundation for cross-platform application development. By using responsive design techniques a browser based application can already cover desktop and mobile platforms. Using the right set of tools, such an application can be developed further into a real mobile app and/or an embedded touch interface.

The building blocks of a modern “cross-platform web application” are the web runtime environment, the single-page application and the back-end system. Let’s have a look at the definition of these three terms and their relation to each other.

platform_layers_cropped

Web runtime environment

The traditional runtime environment for web content is the browser which consists of the DOM and a JavaScript environment. Web runtimes exist for almost all platforms. Besides desktop and mobile browsers, embeddable web views like the QtWebEngine or cross-platform solutions like the Apache Cordova framework extend the reach of web technology to embedded systems and mobile devices.

Single-page application

A single-page application (SPA) is a web application that is contained in a single web page. The web page is loaded and the single-page application is executed by a web runtime. The objective of this approach is to achieve a user experience similar to a desktop application or native mobile app. In order to achieve this the application code and data is loaded as part of the initial page load or dynamically during runtime. Subsequent user actions trigger the update of the page structure. Navigation in the application does not cause a page reload but rather a change to the location hash of the current page URL.

Back-end system

The role of the back-end system is typically assumed by a web server which provides access to core business logic operations through some kind of web service. The single-page application communicates with a web service in an asynchronous way in order to store and retrieve data and trigger business logic operations. The implementation of the business logic is usually split between the back-end (server) and the single-page application (client). Only sensitive parts of the business logic and the central data persistence layer (e.g. access to a database) reside on the server while all other concerns can be offloaded to the client.

Web technology is very diverse

Unlike Qt the web technology field is very diverse. There is a multitude of libraries, frameworks, build tools and “compile to JavaScript” languages and new ones are churned out every day. As a software developer it is quite easy to get overwhelmed by this. Though it is possible to use this diversity to your advantage by mixing and matching the individual components of your technology stack depending on your requirements and personal liking. This of course requires a certain amount of research to come up with a suitable stack.

Exemplary mobile web app technology stack

The technology stack we are going to present here is used in a cross-platform app development project at basysKom. At present the app has been released to the Google Play store and the iOS Appstore. Within this project the Cordova cross-platform framework is used to facilitate the creation of builds for Android and iOS.

Application structure

The actual web application embedded in the web runtime is a single-page application based on React.js for the view layer and a customized application state management solution loosely based on the Flux architecture pattern. A small host of special purpose JavaScript libraries is employed to fit certain aspects of the requirements. For example the library react-intl is used to add localization primitives and d3 is used to add support for drawing graphs. The JavaScript module syntax introduced in ECMAScript 6 is used extensively to organize the application code into separate modules. This greatly improves the maintainability of the code compared to the various module-less structuring techniques.

Build process

The webpack module bundler is used to combine the application code and resources together into a self contained “app bundle” as part of the build process. During this process ECMAScript 2015 and 2016 features are translated transparently into backwards compatible ECMAScript 5 syntax. Webpack offers a plugin API that can be used to extend the support for arbitrary resource types. This feature is heavily used in the build process. The various different build related issues are implemented as gulp tasks. Gulp is a JavaScript task runner implemented on top of Node.js. You can think of it as a kind of Make or CMake for JavaScript. NPM is used for package management.

Cross-platform framework

The app was designed exclusively as a cross-platform mobile app, because it required access to certain system functions and hardware like the photo gallery or camera. Apache Cordova does not support these functions out of the box, but support for them was added by using additional Cordova plugins.

Lessons learned

Watch out for unsuitably licensed dependencies

The released version of the app depends on about two dozen different libraries directly. Including indirect dependencies (i.e. dependencies of dependencies) the app depends on about 100 different libraries. This might appear as a very big amount but can be attributed to the fact that most of these libraries are actually quite small, usually in the range of 25 to 250 lines of code. Keep in mind that the direct and indirect dependencies need to be compatible with the intended licensing scheme of your application.

Luckily, the majority of JavaScript libraries available through NPM are licensed under permissive licenses like the MIT, BSD or Apache license whose obligations can be met more easily. Copyleft licenses are the exception, not the rule.

If you want to generate a list of used dependencies including the license information for your project, have a look at tools like license-report or license-checker.

About Cordova plugin quality

The quality of the Cordova plugins can differ. This did not only affect “third party” plugins, which are not officially part of the Cordova framework distribution, but also official Cordova plugins. We advise to test out the needed functionality and to check the bug tracker of the project before relying on a specific plugin. When push comes to shove it is always an option to get your hands dirty and fix the cause of the problem with the respective plugin yourself. In order to minimize the effect of bad plugin quality, you should always continuously test your application during development on all targeted platforms and form factors.

Always freeze dependencies

By default, NPM does resolve the project’s dependencies every time you run “npm install”. That means, it is very likely that you will not get the exact same version configuration of dependent libraries. Most of the time this just works, but from time to time this mode of operation might introduce a “bad version” of a dependency that somehow breaks your application in a non-obvious way.

In order to prevent this from happening, you should at least define explicit versions of your direct dependencies (good) or freeze the current version configuration with the NPM command “shrinkwrap” (even better). The latter is the recommended method, because it also freezes the indirect dependencies. With this approach, you will not be caught off guard with inexplicable bugs popping up suddenly in your application.

Conclusion

Web technology is a good choice for developing cross-platform applications. Whether it is the right choice is highly dependent on the specific project. Some factors are the existing knowledge of the involved developers, the larger technological environment and of course the requirements of the application itself. A web-based approach can be especially interesting, if one starts out small, with just a browser based application. If done correctly, this application can be developed into a mobile app or an embedded HMI at a later point, while reusing the existing code base.