Chapter 4. Developing Client Apps
4.1. Developing An Ionic App Using RHMAP
Overview
This guide will introduce you to using the RHMAP Javascript SDK within a HTML5 Ionic Cordova App.
This guide includes the steps necessary to create a new Ionic Hello World Project and highlights the code necessary to interact with a Cloud Code App.
Requirements
The Ionic Documentation contains all of the information needed to start developing Ionic Apps.
4.1.1. Sample Project Overview
The example project is a simple project containing one Client App and one Cloud App.
4.1.1.1. Client App
The Client App is a simple Ionic App that includes the RHMAP Javascript SDK. The Client App asks the user to enter their name into a text box and click a Say Hello From The Cloud button. The Client App then uses the $fh.cloud function to send the text entered to the Cloud Code App.
4.1.1.2. Cloud Code App
The Cloud Code App exposes a hello endpoint to recieve a request from the Client App, change the text sent to add Hello and return the response to the client.
4.1.2. Create A New Ionic Hello World Project
Use the following steps to create a new Ionic Hello World Project.
- Log into the Studio.
-
Select the
Projectstab located at top-left of the screen. -
Select the
+ New Projectbutton located at the top of the screen. You will then see a list of Project Templates. -
Select the
Hello World ProjectTemplate and give the new project a name. -
Click the
Createbutton. The new project will now be created. -
When the project has been created, select the
Finishbutton.
You now have a new Project containing an Ionic Client App and a Cloud Code App that it will communicate with.
To Preview the app:
-
Select the
Apps, Cloud Apps & Servicestab. -
Select the
Client Appunder theAppssection. This will take you to the Details Screen. -
The
App Previewcontains a working version of the Ionic Client App that will communicate with the Cloud Code App.
4.1.3. Development Overview
This section will highlight the code necessary for the example solution to work correctly.
4.1.3.1. Cloud Code App
First, let’s consider the Cloud Code App. In this example, we want the Cloud Code App to recieve a request from the Client App, change the hello parameter and respond to the Client App using a JSON object containing the following parameters:
{
msg: "Hello <<hello parameter sent by the client app>>"
}To implement this functionality in the Cloud Code App:
-
In the application.js file, a new
/helloroute is added which requires ahello.jsfile located in thelibdirectory. The hello.js file creates two routes. Both routes perform the same operation of changing the
helloparameter.-
A
GETrequest where thehelloparameter is appended as a query string. -
A
POSTrequest where thehelloparameter is sent in the body of a POST request.
-
A
This Cloud Code App is completely independent of the Ionic Client App. The Cloud Code App can be shared between any number of Client Apps within a project.
4.1.3.2. Ionic Client App
Having created the /hello endpoint in the Cloud Code App, we now proceed to examine the functionality added to the Ionic Client App to allow it to send requests to the /hello endpoint exposed in the Cloud Code App.
The Client App is a simple Ionic App with a single input that accepts some text and a single button that sends the input to the cloud and displays the result to the user.
4.1.3.2.1. fhconfig.json
The Client App contains a fhconfig.json file. This file contains the information needed for the RHMAP Javascript SDK to communicate with the Cloud App.
All HTML5 Client Apps must contain a fhconfig.json file to use the $fh Client API functions. This file is automatically populated with the required information when the app is created in the Studio.
4.1.3.2.2. $fh.cloud
In this example, the $fh.cloud Client API function is used to send requests to the hello endpoint in the Cloud Code App.
The $fh.cloud function is located in the fhcloud.js file. Here, the $fh.cloud function is exposed as a reusable service for the MainCtrl Controller to use.
There is a single controller in the Ionic App called MainCtrl. This controller is responsible for
- Accepting the input from the user from the example.html view.
-
Using the
fhcloudservice to call thehelloendpoint in the Cloud Code App. -
Processing the response from the Cloud Code App using the
successorerrorfunctions, depending on whether the $fh.cloud call was successful.
In this case, the Client App is using a GET request type. As the Cloud Code App exposes both a GET and POST version of the hello endpoint, a POST request type will also work. This is especially useful when dealing with RESTful applications.
4.2. Using Cordova Plug-ins
Cordova plug-ins provide a platform-independent JavaScript interface to mobile device capabilities in hybrid mobile apps. There are several official Apache plug-ins for basic device functions such as storage, camera, or geolocation, and other third-party plug-ins.
The official registry and distribution channel for Cordova plug-ins is npm and the plug-in ID corresponds to the npm package ID. The Cordova Plugins page contains the official plug-in list and acts as a filter for npm packages with the keyword ecosystem:cordova.
4.2.1. Supported Platforms
You can use Cordova plug-ins with all platforms supported by RHMAP. However, not all Cordova plug-ins support all platforms. Platforms supported by a plug-in are specified in a plug-in’s package.json file in the cordova.platforms object, or on the Cordova Plug-ins search page.
4.2.2. Adding Plug-ins to Apps
When developing Cordova applications, plug-ins are added using cordova plugin add, which downloads the plug-in from the repository, creates the necessary folder structure, and adds an entry in the config.xml file. See Platforms and Plugins Version Management in the official Cordova documentation for more information.
In RHMAP, however, plug-ins can also be declared in an RHMAP-specific JSON file config.json and makes the apps future-proof in case the plug-in specification format changes.
{
"plugins": [
{
"id": "cordova-plugin-device",
"version": "latest"
},
{
"id": "cordova-plugin-geolocation",
"version": "1.0.1"
},
{
"id": "cordova-labs-local-webserver",
"url": "https://github.com/apache/cordova-plugins#master:local-webserver",
"version": "2.3.1",
"preferences": {
"CordovaLocalWebServerStartOnSimulator": "false"
}
}
]
}Three plug-ins are specified in the above example: the Device plug-in and Geolocation plug-in, which are available through npm, and the Local WebServer plug-in which is available only from the indicated Github repository.
4.2.2.1. Specification
The config.json file must be located in the www folder of a Cordova app.
The file must contain a key called plugins, the value of which is an array of JSON objects, which can define the following properties:
id (Required)
This is the globally unique ID of the Cordova plug-in, which corresponds to its npm package ID. It can also be found in the plug-in’s
plugin.xmlfile, as described in the Cordova Plugin Specification.version (Required)
The version of the plug-in to use. Corresponds to the npm package version. For plug-ins distributed through Git only, you can find the version of a plug-in in its
plugin.xml.For plug-ins distributed through npm, you can also use the
latestvalue to always use the latest available version. We strongly advise you to use a specific version that is proved to work with your app, since a plug-in upgrade could break backward compatibility.url
The URL of a public Git repository, containing a valid Cordova plugin (contains a
plugin.xmlfile).The provided value for this field is used to download the plug-in, regardless of the values of the
idandversionfields. If this field is not provided, the plug-in will be downloaded from npm with the values ofidandversionfields.You can also specify a particular Git ref and a path to the plug-in within the repository, as described in official Cordova CLI documentation.
-
A Git ref object can be specified by appending
#<git-ref>in the URL. We strongly recommend using a tag or other stable ref that is tested as working with your app. Usingmasteras the ref could result in the plug-in code changing on every build and potentially breaking your application. -
Path to the directory containing the plug-in can be specified with
:<path>in the URL.
For example, if we want to get a plug-in that resides in the
pluginsubdirectory in thereleasebranch of the repository, the URL should have the following format:https://example.com/example.git#release:plugin
After the plug-in is downloaded, its
plugin.xmlfile will be parsed to make sure the plug-in ID matches theidfield specified in theconfig.json.-
A Git ref object can be specified by appending
preferences
To provide plug-in configuration, use key-value pairs in the
preferencesobject, likeCordovaLocalWebServerStartOnSimulatorin the example above.variables
Some plug-ins use variables in
plugin.xmlto parameterize string values. You can provide values for variables as key-value pairs in this field. See official documentation for more information on variables.
4.2.2.2. Default Plugins
Official plug-ins
- cordova-plugin-device (1.1.2)
- cordova-plugin-network-information (1.2.1)
- cordova-plugin-battery-status (1.1.2)
- cordova-plugin-device-motion (1.2.1)
- cordova-plugin-device-orientation (1.0.3)
- cordova-plugin-geolocation (2.2.0)
- cordova-plugin-file (4.2.0)
- cordova-plugin-camera (2.2.0)
- cordova-plugin-media (2.3.0)
- cordova-plugin-media-capture (1.3.0)
- cordova-plugin-file-transfer (1.5.1)
- cordova-plugin-dialogs (1.2.1)
- cordova-plugin-vibration (2.1.1)
- cordova-plugin-contacts (2.1.0)
- cordova-plugin-globalization (1.0.3)
- cordova-plugin-inappbrowser (1.4.0)
- cordova-plugin-console (1.0.3)
- cordova-plugin-whitelist (1.2.2)
- cordova-plugin-splashscreen (3.2.2)
Optional
- cordova-sms-plugin (v0.1.9)
- com.arnia.plugins.smsbuilder (0.1.1)
- cordova-plugin-statusbar (2.1.3)
Custom RHMAP plug-ins:
4.2.3. Testing Apps in the Browser
If a plug-in is specified in the config.json file, the JavaScript object of the plug-in won’t be available until it is built and installed on the device. So if you reference the plug-in’s JavaScript object in your app, and try to load your app in App Preview in the Studio, you may get object undefined errors.
To solve this, use defensive checking when calling the plug-in APIs. For example, the following call to the Cordova camera API would result in an "object undefined" error:
navigator.camera.getPicture(success, fail, opts);
However, checking whether the API is defined lets you handle the error gracefully:
if(typeof navigator.camera !== "undefined"){
navigator.camera.getPicture(success, fail, opts);
} else {
//fail gracefully
fail();
}4.3. Using Secure Keys in your App
$fh.sec APIs provides the functionality to generate keys and data encryption/decryption. However, after the keys are generated, you may need to save them somewhere for future usage. For example, you have some data that needs to be encrypted with a secret key and saved on the device. Next time, when the app starts again, you need to get the same secret key and decrypt the data.
The best practice to achieve this is to save the keys on the cloud side, and associate the keys with the client using the client unique id (CUID) and app id.
4.3.1. CUID and App Id
Both the CUID and app id are sent by the client SDK in every $fh.act request. They are accessible via a special JSON object called __fh. The CUID is unique for each device and remain unchanged even if the app is deleted and re-installed. The app id is generated when the app is created on the platform and remain unchanged. You can use the following code to access them in the cloud code:
getKeyId = function(params){
var cuid = params.__fh.cuid;
var appid = params.__fh.appid;
var keyid = cuid + "_" + appid;
return keyid;
}
exports.getKey = function(params, callback){
var keyid = getKeyId(params);
//get a key using this keyid
....
}4.3.2. Key Persistence
You can use whatever persistent mechanism you like to save the keys in the cloud. One recommended approach is to use $fh.db. Here is some example code to show how to save and retrieve keys using $fh.db:
//read a key using $fh.db
var getKey = function(params, cb){
if(typeof $fh !== "undefined" && $fh.db){
$fh.db({
act:'list',
'type': 'securityKeys',
eq: {
"id": getKeyId(params), //The id is generated using the above example code
"keyType": params.type
}
}, function(err, data){
if(err) return cb(err);
if(data.count > 0){
return cb(undefined, data.list[0].fields.keyValue);
} else {
return cb(undefined, undefined);
}
});
} else {
console.log("$fh.db not defined");
cb("$fh.db not defined");
}
}
//save a key using $fh.db
var saveKey = function(params, cb){
if(typeof $fh !== "undefined" && $fh.db){
//first check if a key with the same id and type already exsists
$fh.db({
act:'list',
'type': 'securityKeys',
eq: {
"id": getKeyId(params),
"keyType": params.type
}
}, function(err, data){
if(err) return cb(err);
//a key with the same id and type already exists, update it
if(data.count > 0){
$fh.db({
'act':'update',
'type': 'securityKeys',
'guid': data.list[0].guid,
'fields' : {
'id': getKeyId(params),
'keyType': params.type,
'keyValue' : params.value
}
}, function(err, result){
if(err) return cb(err);
return cb(undefined, result);
})
} else {
//a key with the same id and type is not found, create it
$fh.db({
'act': 'create',
'type': 'securityKeys',
'fields': {
'id' : getKeyId(params),
'keyType': params.type,
'keyValue': params.value
}
}, function(err, result){
if(err) return cb(err);
return cb(undefined, result);
});
}
});
} else {
console.log("$fh.db not defined");
cb("$fh.db not defined");
}
}4.3.3. Sample Code
A reference application has been created which fully demonstrates how to use $fh.sec APIs. The code for this application is available on GitHub: https://github.com/feedhenry-training/fh-security-demo-app.
4.4. Debugging Apps
Debugging is an essential part of app development. With web applications this can be as simple as using the alert() function to show the value of a variable at a certain point in the code. For browsers that have a console, the console.log function can be used to log this kind of information passively. More advanced forms of debugging web applications include inspecting the state of the DOM, breakpointing JavaScript code and stepping through it, or updating the DOM and the associated styles on the fly.
This page gives an explanation of the debugging tools that can be used while developing cross platform apps. These tools can be used in the Studio or on device.
For more information about how to prepare an app for debugging and how to debug on iOS and Android, see this blog.
4.4.1. Studio console
Most browsers support the console logger. Various log levels can be called with a message for example,
console.log(message); console.error(message);
To debug this console output, you will need to open the relevant web debugging tools in your browser.
For debugging cloud code, simply use console.log() and console.error(). The corresponding log files can be viewed in the Studio under the 'Logs' section, or using FHC.
console.log('this goes to stdout.log');
console.error('this goes to stderr.log');4.4.2. Firebug
If your browser of choice for development is Firefox, the Firebug tool makes debugging very easy. Firebug is an add-on for Firefox that is quite active and has many updates to it. Here are some of the things that can be done using Firebug:
- view console output
- view resource requests
- debug script execution
- dynamically run code, even when breakpoint debugging
- view/update the DOM
- view/update styles
- view/update local storage (DB)
Using these features, debugging an app is made very easy. Getting an app working without Firebug showing any errors or problems gives the app a good chance of working cross platform.
4.4.3. Web Inspector with Chrome
Web Inspector is very similar to Firebug. It offers more or less the same features as Firebug, but has the advantage of being included with WebKit browsers out of the box. This means the Web Inspector can be used with Google Chrome and Safari. The tool is enabled by default with Chrome and can be started by context clicking any object on a web page, and selecting Inspect Element.
4.4.4. Safari / iOS 6+
Remote debugging on iOS with Safari can only be enabled for applications built with a Development provisioning profile. Ad Hoc and Distribution apps cannot be debugged this way.
- Go to the Settings app on your iOS device.
Navigate to Safari → Advanced, and then toggle on the Web Inspector switch.
In desktop Safari, go to Safari → Preferences, select Advanced, then check the Show Develop menu in menu bar check box.
- Connect your iOS device to your development machine via USB.
Open the app you want to debug, it will be available in Safari’s Develop menu.
- The Develop menu has additional tools such as the User Agent switcher. This allows the browser to pretend to be a different browser for example, Mobile Safari. This feature can be useful if developing a mobile Internet version of an app.
4.4.5. Chrome / Android 4.0+
Remote debugging on Android with Chrome can only be enabled for applications that flagged debuggable. If you are using Cordova 3.3 or newer, add android:debuggable="true" inside the <application> element in the AndroidManifest.xml file. If you are using Cordova 3.2 or older version, you have to enable WebView debugging.
Enable USB debugging on your Android device On Android 4.2 and newer versions, the developer option is hidden. To make it available, navigate to Settings → About phone, and tap the Build number seven times.
Go back to the previous screen to find Developer options, then check the USB debugging check box. Choosing the Stay awake option is also recommended.
- In the desktop Chrome browser, in the menu on the upper-right corner select Tools → Inspect Devices
- Check Discover USB devices, if it is not selected.
- Connect your Android device via USB
- If it is the first time you attached this device for developing, you may see an alert on device requesting permission for USB debugging from your development machine. To avoid appearing this alert every time you debug, check Always allow from this computer, then tap OK.
- To debug your app, you need to run it on device.
In Chrome, click the Inspect link to open the DevTools.
4.4.6. On-Device
Debugging on device is still in an early stage compared to debugging in a desktop browser. Some platforms, such as iOS, make the console available and show any javascript errors when Developer mode is enabled, but it is nowhere near as fully featured as Firebug or Web Inspector.
4.4.6.1. Weinre
Weinre is probably the best on-device debugging tool available at the moment. It officially only supports webkit browsers. This means it will work for Android and iOS. The full list and version numbers are available on its site.
Weinre works by setting up a remote debugging session from the app on the device to the Weinre server. Weinre runs a web server which can be used to access the Web Inspector, and remotely debug the app. At the time of writing, the features of this Web Inspector session allow debugging the DOM and updating it. The remote console is also shown, and the developer can dynamically run code in the app from the console.
To enable Weinre debugging in an application, there are a few steps.
Get the Weinre jar up and running on a machine that the device can connect to. There are 2 ways of doing this:
- Run the jar file on a machine accessible over the Internet
- Run the jar on a machine on the same network as the device, that is, device connected via WiFi to the same router/access point as the developers machine.
Note that when running the jar from the command line, it is advised to use the value -all- for the
boundHostso that it is listening on all interfaces.Add a script to the HTML of the app before building and deploying it to the device. According to the documentation, the script include will look something like this.
<script src="http://some.server.xyz/target/target-script-min.js#anonymous"></script>
The address used, some.server.xyz, must match the address (ip address should work too) of the machine that is running the Weinre server.
Deploy the app to the device and launch it. Opening the web page of the Weinre server (on the developer machine) should present a link to the debug user interface. This link opens up the Web Inspector and allows remote debugging of the app.
As these instructions are for a third party tool, it is best to check with the official site for any updates around this setup process.

Where did the comment section go?
Red Hat's documentation publication system recently went through an upgrade to enable speedier, more mobile-friendly content. We decided to re-evaluate our commenting platform to ensure that it meets your expectations and serves as an optimal feedback mechanism. During this redesign, we invite your input on providing feedback on Red Hat documentation via the discussion platform.