Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

How to Mash Up JET and MCS Mobile Apps

DZone's Guide to

How to Mash Up JET and MCS Mobile Apps

MCS is a good fit for JET applications, as it is capable of publishing APIs and out-of-the-box services for both mobile and web applications.

· Mobile Zone
Free Resource

Discover how to focus on operators for Reactive Programming and how they are essential to react to data in your application.  Brought to you in partnership with Wakanda

Late last year, I took the chance to investigate Oracle's JavaScript Extension Toolkit (JET) for web and hybrid mobile development. Here on DZone, I shared what I had learned by publishing a number of articles about the basics of JET. I hope those articles have been useful to you; they certainly helped me learn JET while writing them.

Overall, as a mobile product manager at Oracle, my goal in learning JET was to work out how I could mash JET with Oracle's Mobile Cloud Service (MCS), an MBaaS-oriented PaaS. At Oracle, we see MCS as a good fit for JET applications, as MCS is capable of publishing APIs and out-of-the-box services for both mobile and web applications — which JET itself excels at. It's somewhat ironic that people think MCS does only mobile and JET does only web, when in fact, they're both capable of web and mobile and are a good combination together. Oh, well — I guess it's my job to convince you!

Having learned the basics of JET, my goal is to now explore how to make use of MCS in JET. I have a number of topics that I will hopefully explore over a new series of articles, time permitting.

In this specific article, I want to investigate how to set up the MCS JavaScript SDK and MCS Cordova SDK inside a JET application. This forms the prerequisite for any future articles with MCS and JET, so it is an important first step to explore.

Which MCS Client SDK Do I Use?

Oracle JET is predominately an HTML5/CSS3/JavaScript package of tools and libraries. It is capable of delivering both web applications that run in a browser and hybrid mobile solutions piggybacked on Apache Cordova for Android, iOS, or Windows.

In essence, the applications are web-JavaScript-based or hybrid-mobile-JavaScript-Cordova-based. Regardless of which technology stack a JET application runs on, rarely will a JET application run in isolation. A JET app will also make use of backend (on-premise/cloud) services.

Image title

Independently, in order to support all the different platforms that want to connect to Oracle MCS to access its services, not only does MCS provide REST APIs for all of these; it also provides SDKs for Android, iOS, Windows, JavaScript, and Cordova. We're free to call the REST APIs published by MCS, but we can save much work writing boilerplate REST API calls in our client's native language by using the provided well-tested client SDKs from MCS.

Considering all the client SDKs available via MCS for a JET application, it's these two last SDKs that are of interest (the JavaScript SDK and Cordova SDK).

The MCS JavaScript SDK is aimed at web-JavaScript applications and provides libraries to call the MCS services like storage, push notifications and so on. The MCS Cordova SDK (which ultimately is JavaScript-based, too) is a superset of the MCS JavaScript SDK aimed at Cordova applications.

Thus, if we're building a JET web application, the MCS JavaScript SDK is for us. Alternatively, if we're building a JET hybrid mobile application using Cordova, the MCS Cordova SDK is the SDK we should use.

Keep that in mind as we move forward in this article.

A common question is has to do with the difference between the two different SDKs. The MCS Cordova SDK is a superset of the MCS JavaScript SDK. At the time of writing, the Cordova SDK has more authentication options than the JavaScript SDK, and also support for data sync via the sync express feature. However, inside Oracle, I know there have been discussions to possibly merge the two SDKs in the future, or at least share features, so this may change (with the usual safe harbor disclaimer Oracle staff are so famous for).

What Is Needed to Configure MCS to Support a JET App?

As beginners to MCS won't know much about MCS, I'd like to cover what we need to set up in MCS to support a JET application first, before we consider what to configure on the JET side.

The very first thing we need to create in MCS is a Mobile Backend, accessible via the hamburger > Applications > Mobile Backend menu. A Mobile Backed (MBE) represents the logical backend of our mobile application and is the portal to under which all the services MCS provides can be exposed to our mobile application. In the following picture, I've created an MBE for our JET app called MyJETApp (an inspirational name, I know).

Image title

Of importance, once the MBE is created, is the Settings page. This includes settings that our JET application will need to know about, such as the base URL for the MCS instance, as well as various identifiers for different authentication schemes that we may choose. We'll refer back to these shortly.

For the purposes of this article, we'll assume the mobile client uses HTTP basic authentication to authenticate users, so the Mobile Backend ID and Anonymous Key will be required by the JET application.

While we're here we can take note of the Diagnostics page in the MBE.  Once we start to build out our JET applications and sending requests to MCS via the SDK, if the calls fail, this page will help us understand what MCS sees in terms of requests via the associated graphs and logs.

Image title

Another needed MBE page is the Clients page.  When creating an application, we may have several instances of the application, an Android version, an iOS version, a Windows version or even a web version. Maybe these will be native applications or they'll be written in a cross-platform solution like JET that caters for all of them. Regardless of whether we have one native code base for each platform or one hybrid code base that covers multiple platforms, for every runtime platform we support within the MBE Clients page, we will need to create a Client for each.

Imagine we're using Oracle JET to create a hybrid mobile application on Android and iOS only. As a result, we would need to create 2 MBE Clients in MCS, one for Android, and one for iOS, even though our JET application will only have one code base. The following dialog demonstrates the setting we need to supply for a fictitious Android application. It's fairly self-explanatory, you'd agree, with similar settings for iOS and so on:

Image title

Having created each Client, MCS will give us per Client — that is, for a Client representing each mobile or web platform our application supports, MCS will give us an application key. Similar to the MBE settings page, this key will be important in a moment for configuring the JET application.

Image titleA final piece of the puzzle for building a JET application is that when the JET application connects to MCS, it will need to authenticate the user. We mentioned earlier that for this article, we would use HTTP basic authentication for our JET application, one choice of several authentication schemes we could have also chosen. We also talked about an anonymous key for basic authentication.

For HTTP basic authentication, the JET application user must supply a username and password as a base64 encoded string for each HTTP request to MCS that MCS will use to authenticate the user. Unauthenticated access to MCS APIs is provided by sending the anonymous key as the HTTP basic base64 encoded username and password instead. Truly, this isn't anonymous, as we're still supplying an HTTP basic username and password — but it's as anonymous as MCS allows.

In order to create a mobile user for our HTTP basic authenticated application, we can create new users under the MBE Users screen. On creating a user, an email will be sent to the supplied email address to verify the account should be created, and the user should set their password. Once done, this user can be used for our JET application.

Image title

For our application, I'll use user Joe Jones moving forward.

Building Our JET application

In the previous DZone article series I covered how to create the basic JET application scaffold, and I'll let readers review those articles rather than covering the same again. You can view them here and here

Assuming we've installed all the necessary software for development, for this article, let's also assume we want to create a JET hybrid mobile applications that run on Android and iOS.  To do this, we issue the following call from the command line on one line:

yo oraclejet:hybrid MyJETApp --template=basic-platform=android,ios --appid=com.acme.MyJETApp --appname="My JET App"

Once built, we can run the application in the Android emulator by:

cd MyJETApp
grunt serve --platform=android --destination=MyEmulatorAVDName

...or iOS:

grunt serve --platform=ios --destination=emulator

...or, we can run the app in our browser, which is often faster:

grunt serve --destination=browser

Be it as it may, at this point we have a running JET application ready for the MCS SDK of our choosing.

Thanks to some code we'll talk about in a moment, we also need to install the Cordova Devices plugin which will allow us to determine at runtime what platform our application is running on.  To do this we execute the following to download the plugin:

cd hybrid
cordova plugin add cordova-plugin-device

...and we wait for it to conclude successfully.

Adding the MCS SDK to Our JET Application

With the MCS server side configuration out of the way, and with the basic JET application ready to go, let's investigate adding the MCS SDK to our JET application. We'll add the MCS SDK, create an initialization class, then make the SDK available to our JET application's JavaScript code.

Early on, I made the point with JET, if we choose to build a JET web app, we should use the MCS JavaScript SDK. However, if we choose to build a JET hybrid mobile app, we should use the MCS Cordova SDK.  For the purposes of this article we have chosen to build a hybrid mobile Android and iOS JET application, so that means the MCS Cordova SDK is for us.

To obtain the SDKs, we hit the MCS hamburger icon > Applications page, then the link to SDK Downloads. Among the different SDKs available we download the MCS Cordova SDK and unzip the file:

Image title

The resulting contents contain the following:

Image title

Of interest to us for this article:

  • mcs.js file: A non-minified JavaScript library of MCS-specific SDK code, suitable for debugging and what we'll use in this article.

  • mcs.min.js: The same file but minified for production applications.

  • oracle_mobile_cloud_config.js: This includes a JSON object containing the required configuration properties to be set when running the SDK to connect to our MCS instance.

With these files in hand, we need to copy the mcs.js file into our JET application's src/js directory.

Next, within the main.js file in the JET scaffold that has the RequireJS config call, in the Paths setting, we add the new mcs library so that it is appropriately managed by RequireJS among all the other required libraries when the app starts:

requirejs.config({
            baseUrl: 'js',
            paths:
            //injector:mainReleasePaths
            {
                'knockout': 'libs/knockout/knockout-3.4.0.debug',
                'jquery': 'libs/jquery/jquery-3.1.0',
                'jqueryui-amd': 'libs/jquery/jqueryui-amd-1.12.0',
                'promise': 'libs/es6-promise/es6-promise',
                'hammerjs': 'libs/hammer/hammer-2.0.8',
                'ojdnd': 'libs/dnd-polyfill/dnd-polyfill-1.0.0',
                'ojs': 'libs/oj/v2.3.0/debug',
                'ojL10n': 'libs/oj/v2.3.0/ojL10n',
                'ojtranslations': 'libs/oj/v2.3.0/resources',
                'text': 'libs/require/text',
                'signals': 'libs/js-signals/signals',
                'customElements': 'libs/webcomponents/CustomElements',
                'proj4': 'libs/proj4js/dist/proj4-src',
                'css': 'libs/require-css/css',
                'mcs': 'mcs'
            }

Note the extension .js is assumed, so it is excluded.

Having loaded the MCS SDK library, we then need to initialize it at runtime.  An emerging pattern to do this is to create a separate RequrieJS module by creating a new file src/js/mcsconfig.js.  From the SDK zip directory we then copy the contents of the oracle_mobile_cloud_config.js file into this new file, and add some extra code as follows:

define(['mcs'], function(mcs) {

This defines the RequireJS module, stating that for this module, the mcs library is a dependency, and we'll refer to it in the following code:

  var applicationkey = (device.platform === "iOS" ? "f996eb7c-f73d-4b4e-8d73-6b61020672c6" : "5b4490e1-628e-4116-b261-8865b3e1e49b");

  var mcs_config = {
      "logLevel": mcs.LOG_LEVEL.INFO,
      "logHTTP": true,
      "mobileBackends": {
          "MyJETApp": {
              "default": true,
              "baseUrl": "https://xx.mobileenv.us2.oraclecloud.com:443",
              "applicationKey": applicationkey,
              "authorization": {
                  "basicAuth": {
                      "backendId": "e53739ff-bea5-4250-8cf4-967798cbd497",
                      "anonymousToken": "UE1FTkFCTEVGRUIxN19QTUVOQUJMRUZFQl9NT0JJTEVfQU5PTllNT1VTX0FQUElEOkxpdjB3YXpwcy55ZDZn"
                  }
              }
          }
      }
  };

This contains the code copied from oracle_mobile_cloud_config.js. If you have a look at that file, you will note I've cut out any settings to do with non-HTTP basic authentication, as well as the settings for sync and syncExpress, as they're not relevant to this article. In addition, from the MBE Settings page in the MCS UI, I've also copied in the necessary values for each key.

Also, note the application key. Earlier in the article, we noted that for each client platform our application runs on, MCS via the MBE Clients screen will give us a separate application key. As our app will run on Android and iOS, we need to dynamically determine what value to give for this key.

Via the variable applicationkey above with a call to device.platform, we're making use of the Cordova Device plugin we added to our application, where the platform property tells us what platform we're running on, which we've then used to determine at runtime what application key to return.

Continuing in our code:

 function McsConfig() {
     var self = this;

     mcs.MobileBackendManager.platform = new mcs.CordovaPlatform();
     mcs.MobileBackendManager.setConfig(mcs_config);

     self.MobileBackend = mcs.MobileBackendManager.getMobileBackend("MyJETApp");
     self.MobileBackend.setAuthenticationType("basicAuth");
 };

 return new McsConfig();
 });

Finally, the McsConfig code tells the MCS SDK that it's running on Cordova and initializes itself with the mcs_config settings we just created. At the end, it makes available to the whole application via a handle to MobileBackend for the MyJETApp MBE we defined earlier, set up for HTTP basic authentication.

The overall code is as follows:

define(['mcs'], function(mcs) {

    var applicationkey = (device.platform === "iOS" ? "f996eb7c-f73d-4b4e-8d73-6b61020672c6" : "d1c60237-1fa9-4989-870b-45f070313672");

    var mcs_config = {
        "logLevel": mcs.LOG_LEVEL.INFO,
        "logHTTP": true,
        "mobileBackends": {
            "MyJETApp": {
                "default": true,
                "baseUrl": "https://xx.mobileenv.us2.oraclecloud.com:443",
                "applicationKey": applicationkey,
                "authorization": {
                    "basicAuth": {
                        "backendId": "e53739ff-bea5-4250-8cf4-967798cbd497",
                        "anonymousToken": "UE1FTkFCTEVGRUIxN19QTUVOQUJMRUZFQl9NT0JJTEVfQU5PTllNT1VTX0FQUElEOkxpdjB3YXpwcy55ZDZn"
                    }
                }
            }
        }
    };

    function McsConfig() {
        var self = this;

        mcs.MobileBackendManager.platform = new mcs.CordovaPlatform();
        mcs.MobileBackendManager.setConfig(mcs_config);

        self.MobileBackend = mcs.MobileBackendManager.getMobileBackend("MyJETApp");
        self.MobileBackend.setAuthenticationType("basicAuth");
    };

    return new McsConfig();
});

Having created the mcsconfig.js file, like we did for the mcs.js file, we must add this to the main.js RequireJS.config paths property like follows so it can manage the initialization module:

requirejs.config({
            baseUrl: 'js',
            paths:
            //injector:mainReleasePaths
            {
                ..snip..
                'mcs': 'mcs',
                'mcsconfig': 'mcsconfig'
            }

Having set up the initialization code for MCS, we're now in a position to make use of it in our JET application.

What Can We Do?

With the SDK ready to go, we can now make use of the remote MCS features, such as storage, push notifications, location-based services, and so on. If you're interested in the capabilities from the SDK perspective, check out the doc links for more information on what the MCS Cordova SDK and MCS JavaScript SDK provide.

Before we call all these services, in reality, the first thing we really will want to do is authenticate our mobile user against MCS. Showing how to do this in the article also proves we have the MCS SDK up and running correctly because if the authentication doesn't work, it means some of our configuration is wrong.

For the generated application we're going to keep this pretty simple.  I'll add a login button to the landing page, and in the corresponding JavaScript module for the page, the click handler to call the mcsconfig code to call the MCS authentication logic.

So, to start with, in the generated index.html page, I'll add the following <button> between the main content <div>:

<div role="main" class="oj-hybrid-applayout-content">
    <button id="button" data-bind="click: loginClick, ojComponent: { component: 'ojButton', label: 'Login' }"></button>
</div>

From here, we need to provide our loginClick JavaScript logic. As the index.html page is backed by the main.js module to provide its JavaScript logic (which contains the core require() module definition), we'll modify the require() module to include the mcsconfig as a dependency like follows:

require(['ojs/ojcore', 'knockout', 'appController', 'mcsconfig', 'ojs/ojknockout',
            'ojs/ojbutton'
        ],
        function(oj, ko, app, mcsconfig) {

Note the inclusion of mcsconfig in the dependency array, and then the same named handler in the function() definition.  The handler then allows us to make use of the mcsconfig instance at runtime we created earlier. In continuing with the code, we can now add our loginClick as follows:

require(['ojs/ojcore', 'knockout', 'appController', 'mcsconfig', 'ojs/ojknockout',
            'ojs/ojbutton'
        ],
        function(oj, ko, app, mcsconfig) {

            function MainViewModel() {
                var self = this;

                self.toolbarButtons = app.toolbarButtonDataSource;

                // Custom login code
                self.loginSuccess = function(response, data) {
                    alert("Login success!");
                };

                self.loginFailure = function(response, data) {
                    alert("Login failed :-(");
                };

                self.loginClick = function(data, event) {
                    // mcsconfig.MobileBackend.Authorization.authenticateAnonymous(self.loginSuccess, self.loginFailure);
                    mcsconfig.MobileBackend.Authorization.authenticate('joe', 'password1234', self.loginSuccess, self.loginFailure);
                }
                // End of custom login code

In the loginClick function, I've included examples of calling the MCS SDK code to authenticate the user anonymously (this option is commented out), or with a real username and password.  Without a doubt, in a real application, we wouldn't hardcode the username and password. We'd provide a login screen with text inputs to derive these from. However, for the purposes of our article, and providing the SDK has been configured correctly, this code suffices.

As we also note, both login methods include success and failure callbacks where we can then add further custom logic for our application. For purposes of the article, simple alerts will suffice for us too.

With all this in place, we can then kick off our application via the command line. Here, we'll use the Android emulator to start a custom AVD I have on my machine:

grunt serve --platform=android --destination=MyAVD

With our app running, we hit login...and...*add drumroll*:

Image title

Hmm. OK. Off to Chrome for a debug session. We soon discover that we've hit a CORS exception:

Image title

For MCS to accept requests from remote JET apps we need to add an exemption. We do this via opening the MCS Administration page, downloading the policy.properties file, and adding an exemption for the IP addresses the Android & iOS Cordova apps run as follows:

*.*.Security_AllowOrigin=http\://10.0.2.2\:8000,http\://127.0.0.1\:8000

Once uploaded back to the MCS Admin page, with the Android emulator still running, this time, we see the following message when we log in:

Image title

Voila. All is good with the world!

Learn how divergent branches can appear in your repository and how to better understand why they are called “branches".  Brought to you in partnership with Wakanda

Topics:
oracle jet ,mobile ,android ,ios ,hybrid mobile ,tutorial ,mcs

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}