Skip navigation

The primary motive of this blog is to show how to

  • Enable Facebook login in Oracle MCS (16.4.x)
  • Implement Facebook login in Oracle JET Hybrid application by using Oracle MCS Cordova SDK
  • Calling a custom API secured using Social Login

 

Key Components

Below tables summarizes the key components involved in this solution:

 

Component
Details
Social Login - Facebook

Facebook Login is a secure, fast and convenient way for people to log into your mobile application. This mode of authentication is particularly useful for apps targeting consumers

Mobile Middleware - Oracle MCS

In Oracle MCS:

  • Configure mobile backend  to enable users to log in through Facebook login.
  • Add custom API's to this mobile backend secured with social login
Client Application - Oracle JET Hybrid applicationOracle JET Hybrid application is based on Apache cordova framework. We will integrate Oracle MCS Cordova SDK to simplify Social Login authentication

 

Functional Flow

Below is the application flow:

  1. The user presses Facebook login button created in our hybrid mobile application.
  2. The MCS Cordova SDK gets initialized and calls the Facebook Login service.
  3. The Facebook login page appears within the mobile app and user is prompted to enter credentials
  4. The social-login security check validates the credentials.
  5. Upon success, The social-login returns the access token
  6. The mobile app then uses the access token to access secure MCS APIs.

 

Component: Social Login - Facebook

The first step is to create a Facebook developer app. For more details, please refer Facebook developer documentation

 

Below are the steps to create the same:

 

Create a new App

Visit the Facebook Developer Apps Page and follow below steps:

 

Add-A-New-app.png

 

Basic Settings

Add basic settings of the application. "App ID" and "App Secret" will be used in Oracle MCS backend configuration.

 

Settings-basic.png

 

Advanced Settings

Please refer the advance settings in the image below:

 

Settings-advanced.png

 

 

 

Facebook Login Settings

Add the redirect OAuth URL as shown below.

FacebookLoginSettings.png

App Review

Once everything is tested, make your app public

AppReview.png

 

Once above steps are done, your facebook login setup is ready.

Component: Mobile Middleware - Oracle MCS

The next step is the create a new Mobile Middleware in Oracle MCS and perform following settings

 

Mobile Backend - Settings

  • Enable Facebook option
  • Enter the Facebook App ID and Secret you received when you registered your application.

mcs-settings.png

 

Secure Custom API

Create a custom API and enable the security using Social Identity

mcs-security.png

 

API Test

Once the custom API is ready, the next step is to test the same using facebook access token.

mcs-test-endpoint.png

 

Facebook User Access Token

Please follow below steps to obtainFacebook user access token

  1. Log into your Facebook account (the one with which you registered the mobile app).

  2. Navigate to https://developers.facebook.com/tools/accesstoken/ and find your app.

  3. Click the You need to grant permissions to your app to get an access token link to generate the token. A token is generated for you on the next page.

 

Copy the user token and paste in MCS Test screen as shown above

facebook-user-token.png

Please follow link "Getting a Facebook User Access Token Manually" for more deatils

 

Test Endpoint

After entering the user token, press "Test Endpoint" button to verify the result

mcs-test-endpoint.png

 

At this stage, the mobile backend providing social login and a secured custom API. The next step is to create client application utilizing this backend and facebook login page!

 

Component: Client Application - Oracle JET Hybrid application

 

Once the mobile back-end is up and ready, our next step is to develop client side application.

 

You may please refer to Troubleshooting while developing your First JET based Hybrid Application blog in case of initial issues faced during development/configuration issues.

Project Setup using Yeoman

Yeoman generator for Oracle JET lets you quickly set up a project for use as a Web application or mobile-hybrid application for Android and iOS.

Use following command to generate hybrid application for Android:

 

 

yo oraclejet:hybrid fbmcssample --appId=com.rdh.fbmcs --appName="fbmcssample" --template=navBar --platforms=android  

 

 

Cordova Plugin Required

Please refer to Cordova Applications section in Oracle Mobile Cloud Service to obtain details of the cordova plugin. Following cordova plugin needs to be added in our application:

 

  • cordova-plugin-inappbrowser: Plugin to provide Facebook authentication in your app
cordova plugin add cordova-plugin-inappbrowser -save

 

Adding Oracle MCS Cordova SDK

In order to communicate with Oracle MCS, following steps are required:

  1. Download the Cordova SDK from Oracle MCS. Extract the same on your local machine. It will contain Javascript based Cordova SDK , configuration files and documentation
  2. Add Oracle MCS Cordova SDK to your application, Copy mcs.js, mcs.min.js and oracle_mobile_cloud_config.js into the directory where you keep your JavaScript libraries.

 

For example, in this implementation, I have kept these files in mcs folder added in js/libs folder as shown in below image:

mcs-additions.png

 

Code Addition

 

Configuring SDK Properties for Cordova

Fill in your mobile backend details in oracle_mobile_cloud_config.js.

 

var mcs_config = {
  "logLevel": 3,
  "mobileBackends": {
    "RDXTESTSSO": {
      "default": true,
      "baseUrl": "http://XXX.us.oracle.com:7777",
      "applicationKey": "YOUR_BACKEND_APPLICATION_KEY",
      "synchronization": {
        "periodicRefreshPolicy": "PERIODIC_REFRESH_POLICY_REFRESH_NONE",
        "policies": [
          {
            "path": '/mobile/custom/taskApi/*',
            "fetchPolicy": 'FETCH_FROM_SERVICE_ON_CACHE_MISS_OR_EXPIRY',
            "expiryPolicy": 'EXPIRE_ON_RESTART',
            "evictionPolicy": 'EVICT_ON_EXPIRY_AT_STARTUP',
            "updatePolicy": 'QUEUE_IF_OFFLINE',
            "noCache" : false
          },
          {
            "path": '/mobile/custom/firstApi/tasks',
            "fetchPolicy": 'FETCH_FROM_SERVICE_ON_CACHE_MISS'
          },
          {
            "path": '/mobile/custom/secondApi/tasks',
          }
        ],
        "default" :{
          "fetchPolicy": 'FETCH_FROM_SERVICE_IF_ONLINE',
          "expiryPolicy": 'EXPIRE_ON_RESTART'
        }
      },
        "authorization": {
        "basicAuth": {
          "backendId": "YOUR_BACKEND_ID",
          "anonymousToken": "YOUR_BACKEND_ANONYMOUS_TOKEN"
        },
        "oAuth": {
          "clientId": "YOUR_CLIENT_ID",
          "clientSecret": "YOUR_ClIENT_SECRET",
          "tokenEndpoint": "YOUR_TOKEN_ENDPOINT"
        },
        "facebookAuth":{
          "facebookAppId": "21664XXXX175",
          "backendId": "cdXX781f-7fd4-4b42-88e1-XX409de0823f",
          "anonymousToken": "UFJJTUVfREVDRVBUSUNPTXXXT0JJTEVfQU5PTllNT1VTX0FQUElEOnZXXXXmwuamEwbTdu"
        }
        
      }
    }
  }
};

 

For details please refer this link

 

Update Main.JS for path mapping

After adding the physical files, update the paths mapping for mcs and mcs_cloud_config  in main.js file under requirejs.config section:

 

 paths:
                    //injector:mainReleasePaths
                            {
                                'knockout': 'libs/knockout/knockout-3.4.0.debug',
                                'jquery': 'libs/jquery/jquery-2.1.3',
                                'jqueryui-amd': 'libs/jquery/jqueryui-amd-1.11.4',
                                'promise': 'libs/es6-promise/promise-1.0.0',
                                'hammerjs': 'libs/hammer/hammer-2.0.4',
                                'ojdnd': 'libs/dnd-polyfill/dnd-polyfill-1.0.0',
                                'ojs': 'libs/oj/v2.0.2/debug',
                                'ojL10n': 'libs/oj/v2.0.2/ojL10n',
                                'ojtranslations': 'libs/oj/v2.0.2/resources',
                                'text': 'libs/require/text',
                                'signals': 'libs/js-signals/signals',
                                'mcs': 'libs/mcs/mcs',
                                'mcsconf': 'libs/mcs/oracle_mobile_cloud_config'
                            }

 

Implementation Steps

We will be implementing the entire code in dashboard.html and dashboard.js for easy implementation.

 

Add the additional modules: mcs and mcsconf to get loaded in dashboard.js file:

 

define(['ojs/ojcore', 'knockout', 'jquery', 'mcs', 'mcsconf', 'ojs/ojknockout','ojs/ojbutton'],
        function (oj, ko, $,mcs) {

Note: Please see that I have added "mcs" as a parameter to the function in dashboard.js file. This is required as I am using MCS SDK 16.3.x. In 16.3.3, Oracle  added support for RequireJS. So when MCS library is loaded in RequireJS environment, the global “mcs” variable is not declared like it was before in earlier version of the SDK.

 

Step 1: Loading Mobile Backend's Configuration

Get the mobile backend and set the authentication type to facebookAuth.

 

function initializeMCS() {
                    mcs.MobileBackendManager.platform = new mcs.CordovaPlatform();
                    mcs.MobileBackendManager.setConfig(mcs_config);
                    backend = mcs.MobileBackendManager.getMobileBackend("RDXTESTSSO");
                    if (backend != null) {
                        backend.setAuthenticationType("facebookAuth");
                        fbLogin();
                    }
                }

 

Step 2: Authenticate

Then add a function that calls Authorization.authenticate

 

function fbLogin() {
                    backend.Authorization.authenticate(
                            function (statusCode, data) {
                                console.log(data);
                                console.log(statusCode);
                                alert("FB Login success, status:" + statusCode);                                
                                invokeCustomTestAPI();
                            },
                            function (statusCode, data) {
                                console.log(statusCode + " with message:  " + data);
                                alert("FB Login failed, statusCode" + statusCode);
                            });
                }

Step 3: Invoke Custom API

Finally call the custom API secured by social identity:

 

function invokeCustomTestAPI()
                {
                    backend.CustomCode.invokeCustomCodeJSONRequest("TestFB/test", "GET", null, function (statusCode, data) {
                        console.log("statusCode"+statusCode);                        
                        console.log("data"+JSON.stringify(data)); 
                        alert("Status="+statusCode+"data="+JSON.stringify(data));                        
                    },
                            function (statusCode, data) {
                                console.log("statusCode"+statusCode);                        
                                console.log("data"+data);       
                                alert("Status="+statusCode+"data="+JSON.stringify(data));
                            });
                }

Build and Run

 

In your command prompt, please change directory to project folder and run the following command:

 

Build the application using following command

 

  1.  grunt build --platform=android  

 

Once build is success, then run the application using following command, assuming android emulator is already up and running:

 

 

grunt serve --platform=android  --disableLiveReload=true    

 

Output

Open App and Click on Login

  1. On opening, "Login via Facebook" button is shown
  2. Also open Chrome://Inspect to view logs
  3. Touch/Click Login via Facebook button

output1.png

 

Login via Facebook

Enter your facebook credentials

output2.png,

 

Facebook Authentication result

output3.png

Calling MCS Custom API Secured using Social Identity

output4.png

In this blog, I will present a sample implementation for a hybrid mobile app using Oracle JET (version 2.0.x) that will display data fetched from Oracle Sales Cloud via Oracle Mobile Cloud Service (version 16.3.x)

 

Building enterprise grade bespoke mobile apps pose a number of challenges. Implementing data retrieval in mobile application client code is incredibly complex because it needs to be shaped it in the required format within reasonable performance limits with all aspects of security handled appropriately. These requirements are addressed by mobile back-end implemented in Mobile Cloud Service (MCS), resulting into a superior user experience that implies increased user adoption.

 

In this sample, we will retrieve Opportunities for a specific Account from Sales Cloud and display on the mobile application.

 

Key Components

Below tables summarizes the key components involved in this solution:

 

Component
Details
Client Application (JET Hybrid app)A JET Hybrid application that communicates with Oracle MCS
Oracle MCSMCS (Mobile Cloud Service) delivers cloud-based, server-side mobile services to enable quick and easy app development.  It reduces complexity and redundancy when creating code blocks by providing ready-to-integrate features and templates.
Oracle  Sales CloudOracle Sales Cloud delivers a wide range of functionality to improve sales effectiveness, better understand customers, and build a pipeline for success. It exposes multiple public REST APIs that can be used to access data stored in Sales Cloud and construct integrations to other systems

 

Life-Cycle Flow

Below diagram shows the life-cycle flow for data flow from Oracle Sales Cloud to Mobile device via MCS:

 

jet-mcs-salescloud.png

 

Below are the main steps involved:

  1. The mobile app initiates connection with the mobile back-end server (MCS) and authenticate the logged in user.
  2. The mobile app make a REST call to custom API
  3. The custom API internally uses connector API to interact with Oracle Sales Cloud
  4. The response received to custom API’s is sent back to display data in the app

 

Below is the security approach followed:

  • Client Side: Hybrid Mobile Application:
    1. Authenticated the mobile application via SSO: On success , status 200 OK, API returns SSO TOKEN
    2. Used this SSO Token in Authorization header while calling MCS Custom API. This token is used to propagate identity to MCS Connector

 

  • Mobile Back-end: Oracle Mobile Cloud Service
    1. MCS API:
      • Developed custom API which in turn calls REST based connector (Oracle Sales Cloud)
    2. MCS Connector:
      • Developed Connector API pointing to Sales Cloud
      • Set the security policy to “oracle/http_saml20_token_bearer_over_ssl_client_policy” , keeping everything as default

1. In order to follow this security approach mentioned in this blog, please ensure that single sign-on (SSO) is set up for your Oracle Cloud account.

2. Both MCS and Sales Cloud service should be in same identity domain.

Component: Oracle Mobile Cloud Service

Step 1: Create a mobile back-end

  • Login into Oracle MCS and create a new mobile back-end, provide a suitable Name and description
  • Enable OAuth Consumer
  • Check-box to select "Enable Single Sign-On"

If the Mobile Backend is in Draft state and you don't see the Enable SSO checkbox, SSO isn't set up for your account. If you want to set it up, have your team's identity domain administrator go to the Oracle Cloud My Services page and configure SSO.

mcs-backend-settings.png

 

Step 2: Create a custom API

Here are the steps to create a custom API:

  • General: Create a new custom API, provide API display Name and API name. This API name translates to the external URL for the custom API for our mobile apps to connect with it.

mcs-api-general.png

  • Endpoints:  The next step is to define REST end points

mcs-api-endpoints.png

          Add details to the endpoint, in this case it is a GET request:

mcs-api-endpoint.png

 

  • Security: For sake of simplicity, we are keeping the disabling the credentials required to access this API

 

  • Implementation:  Here is the implementation code for this custom API, to know more about what you can do with custom code, I would recommend to visit “Implementing Custom APIs”

Package.json

{
  "name" : "rdhsalesapplapi",
  "version" : "1.0.0",
  "description" : "Sales Cloud API ",
  "main" : "rdhsalesapplapi.js",
  "oracleMobile" : {
    "dependencies" : {
      "apis" : { },
      "connectors" : { "/mobile/connector/RDOSCAPIConnectorOriginSecured": "1.0"}
    }
  }
}

 

rdhsalesapplapi.js

 

/**
 * Mobile Cloud custom code service entry point.
 * @param {external:ExpressApplicationObject}
 * service 
 */
module.exports = function (service) {
    /**
     *  The file samples.txt in the archive that this file was packaged with contains some example code.
     */
    service.get('/mobile/custom/RDHSalesApplAPI/opportunities', function (req, res) {
        var sdk = req.oracleMobile;
        var result = [];
        var statusCodeOk = 200;
        var statusCodeError = 404;
        // handling the Rest call response and processing the data
        var handler = function (error, response, body) {
            var responseMessage = JSON.parse(body);
            if (error) {
                responseMessage = error.message;
            } else {
                if (!responseMessage.items) {
                    res.send(statusCodeError, 'No Opportunities found for the user');
                }
            }
            var opps = [];
            opps = responseMessage.items;
            opps.forEach(function (oppty) {
                var temp = {};
                temp.TargetPartyId = oppty.TargetPartyId;
                temp.OptyId = oppty.OptyId;
                temp.OptyNumber = oppty.OptyNumber;
                temp.SalesStage = oppty.SalesStage;
                temp.Name = oppty.Name;
                temp.Revenue = oppty.Revenue;
                result.push(temp);
            });
            res.send(statusCodeOk, result);
            res.end;
        };
        //call for REST api to get list of opportunities
        var optionsList = {};
        var SalesAccountConnectorBaseURI = '/mobile/connector/RDOSCAPIConnectorOriginSecured';       
        optionsList.uri = SalesAccountConnectorBaseURI + '/salesApi/resources/latest/opportunities/';
        console.log('optionList  = ' + JSON.stringify(optionsList));
        sdk.rest.get(optionsList, handler);
    });
};

 

Step 3: Create a connector API

Before moving ahead, I would recommend you to go through this blog MCS Connector APIs: why should you be using them?  to know why connector APIs are required in spite of having the option to implement external service integration using Custom APIs directly

 

The next step is to create REST connector for accessing Oracle Sales Cloud:

 

  • General Configuration: Provide a name and description for new REST Connector API, and the path to the remote service it will expose.

  mcs-connector-general.png

  • Create Rules: User can create rules that automatically add default parameters when calling specific resources on this service. For this sample, we donot require any such rule so skip this option
  • Security Configuration: Use SAML as the client-side security policy in the MCS Connector, i.e. oracle/http_saml20_token_bearer_over_ssl_client_policy

mcs-connector-securityconfiguration.png

 

Step 4: Select API and associate with your Mobile Backend

 

The next step is to select the custom API created and associate it with your mobile  backend.

mcs-backend-api.png

 

Step 4: Test the Custom API

The last step is to test the custom API

 

A. Get Single Sign-On Auth Token

Open the following URL in an incognito or private browser window. The URL formation is as below:

 

<SSO_Token_Endpoint>?clientID=<client_ID>

 

example: https://xyz.oraclecorp.com:443/mobile/platform/sso/token?clientID=5xxxx7-bf49-45c1-aeda-2xxx4

 

The browser login screen shall look like:

browser-sso-login-screen.png

 

Upon Success, the browser will show Single Sign-On OAuth Token:

 

browser-sso-token-screen.png

 

B.  Test Custom API using MCS UI Test Endpoint

  • Select Mobile Backend
  • Paste SSO Token
  • Click Test Endpoint

mcs-api-testendpoint.png

 

 

Upon Success : Status 200 , data would be displayed:

mcs-api-testendpoint-result.png

 

Component: Oracle JET Hybrid Mobile App

Once the mobile back-end is up and ready, our next step is to display the data fetched data from MCS on the mobile interface.

You may please refer to Troubleshooting while developing your First JET based Hybrid Application blog in case of initial issues faced during development/configuration issues.

Project Setup using Yeoman

Yeoman generator for Oracle JET lets you quickly set up a project for use as a Web application or mobile-hybrid application for Android and iOS.

Use following command to generate hybrid application for Android:

yo oraclejet:hybrid oscmcssample --appId=com.rdh.oscmcs --appName="oscmcssample" --template=navBar --platforms=android  

 

 

Cordova Plugin Required

Please refer to Cordova Applications section in Oracle Mobile Cloud Service to obtain details of the cordova plugin.

 

Following cordova plugin needs to be added in our application:

  • oracle-mobile-cloud-cookies: Plugin for authenticating with MCS via SSO
  • cordova-plugin-inappbrowser: Plugin to provide a web browser view, required for displaying SSO Login Page

 

Adding Oracle MCS Cordova SDK

In order to communicate with Oracle MCS, following steps are required:

  1. Download the Cordova SDK from Oracle MCS. Extract the same on your local machine. It will contain Javascript based Cordova SDK , configuration files and documentation
  2. Add Oracle MCS Cordova SDK to your application, Copy mcs.js, mcs.min.js and oracle_mobile_cloud_config.js into the directory where you keep your JavaScript libraries.

 

For example, in this implementation, I have kept these files in mcs folder added in js/libs folder as shown in below image:

mcs-additions.png

 

2. Fill in your mobile backend details in oracle_mobile_cloud_config.js.

var mcs_config = {
  "logLevel": 3,
  "mobileBackends": {
    "RDXTESTSSO": {
      "default": true,
      "baseUrl": "https://xxx.oraclecorp.com:443",
      "applicationKey": "YOUR_BACKEND_APPLICATION_KEY",
      "synchronization": {
        "periodicRefreshPolicy": "PERIODIC_REFRESH_POLICY_REFRESH_NONE",
        "policies": [
          {
            "path": '/mobile/custom/taskApi/*',
            "fetchPolicy": 'FETCH_FROM_SERVICE_ON_CACHE_MISS_OR_EXPIRY',
            "expiryPolicy": 'EXPIRE_ON_RESTART',
            "evictionPolicy": 'EVICT_ON_EXPIRY_AT_STARTUP',
            "updatePolicy": 'QUEUE_IF_OFFLINE',
            "noCache" : false
          },
          {
            "path": '/mobile/custom/firstApi/tasks',
            "fetchPolicy": 'FETCH_FROM_SERVICE_ON_CACHE_MISS'
          },
          {
            "path": '/mobile/custom/secondApi/tasks',
          }
        ],
        "default" :{
          "fetchPolicy": 'FETCH_FROM_SERVICE_IF_ONLINE',
          "expiryPolicy": 'EXPIRE_ON_RESTART'
        }
      },
        "authorization": {
        "basicAuth": {
          "backendId": "YOUR_BACKEND_ID",
          "anonymousToken": "YOUR_BACKEND_ANONYMOUS_TOKEN"
        },
        "oAuth": {
          "clientId": "YOUR_CLIENT_ID",
          "clientSecret": "YOUR_ClIENT_SECRET",
          "tokenEndpoint": "YOUR_TOKEN_ENDPOINT"
        },
        "facebookAuth":{
          "facebookAppId": "YOUR_FACEBOOK_APP_ID",
          "backendId": "YOUR_BACKEND_ID",
          "anonymousToken": "YOUR_BACKEND_ANONYMOUS_TOKEN"
        },
        "ssoAuth":{
          "clientId": "5xxxxxx7-bf49-45c1-aeda-2xxxxx4",
          "clientSecret": "yxxxxxxx",
          "tokenEndpoint": "https://xxx.oraclecorp.com:443/mobile/platform/sso/token"
        }
      }
    }
  }
};

 

For more details, please See Configuring SDK Properties for Cordova.

 

After adding the physical files, update the paths mapping for mcs and mcs_cloud_config  in main.js file under requirejs.config section:

 paths:
                    //injector:mainReleasePaths
                            {
                                'knockout': 'libs/knockout/knockout-3.4.0.debug',
                                'jquery': 'libs/jquery/jquery-2.1.3',
                                'jqueryui-amd': 'libs/jquery/jqueryui-amd-1.11.4',
                                'promise': 'libs/es6-promise/promise-1.0.0',
                                'hammerjs': 'libs/hammer/hammer-2.0.4',
                                'ojdnd': 'libs/dnd-polyfill/dnd-polyfill-1.0.0',
                                'ojs': 'libs/oj/v2.0.2/debug',
                                'ojL10n': 'libs/oj/v2.0.2/ojL10n',
                                'ojtranslations': 'libs/oj/v2.0.2/resources',
                                'text': 'libs/require/text',
                                'signals': 'libs/js-signals/signals',
                                'mcs': 'libs/mcs/mcs',
                                'mcsconf': 'libs/mcs/oracle_mobile_cloud_config'
                            }
                    //endinjector

Implementation Steps

We will be implementing the entire code in dashboard.html and dashboard.js for easy implementation.

 

Add the additional modules: mcs and mcsconf to get loaded in dashboard.js file:

define(['ojs/ojcore', 'knockout', 'jquery', 'mcs', 'mcsconf', 'ojs/ojknockout', 'ojs/ojfilmstrip', 'ojs/ojpagingcontrol', 'ojs/ojbutton'],

 

Initialize following variables in dasbhoardViewModel function

var backend = 'empty';
                self.model = ko.observable('filmstrip-navdots-example');
                self.dataReady = ko.observable(false);
                self.data = ko.observableArray();
                self.buttonSSOLogin = function () {
                    initializeMCS();
                };

 

 

Updated dashboard.html file: Please find attached the updated dashboard.html file

 

Step 1.  Load Mobile Back end’s Configuration into the application:

function initializeMCS() {
                    mcs.MobileBackendManager.platform = new mcs.CordovaPlatform();
                    mcs.MobileBackendManager.setConfig(mcs_config);
                    backend = mcs.MobileBackendManager.getMobileBackend("RDXTESTSSO");
                    if (backend != null) {
                        backend.setAuthenticationType("ssoAuth");
                        ssoLogin();
                    }
                }

Step 2. Authenticate and Log In Using the SDK:

function ssoLogin() {
                    backend.Authorization.authenticate(
                            function (statusCode, data) {
                                console.log(data);
                                console.log(statusCode);
                                alert("SSO Login success, status:" + statusCode);                               
                                fetchSalesCloudData(data.access_token);
                            },
                            function (statusCode, data) {
                                console.log(statusCode + " with message:  " + data);
                                alert("SSO Login failed, statusCode" + statusCode);
                            });
                }

Step 3. In all REST calls to MCS APIs, include the given token in the Authorization header. In this case, we will be passing this token while calling API to fetch data from our SalesCloud custom API:

function fetchSalesCloudData(ssoToken)
                {
                    var mcsbackendURL = mcs_config.mobileBackends.RDXTESTSSO.baseUrl + "/mobile/custom/RDHSalesApplAPI/opportunities";
                    console.log(mcsbackendURL);
                    var token = "Bearer " + ssoToken;
                    console.log(token);
                    var settings = {
                        "async": true,
                        "crossDomain": true,
                        "url": mcsbackendURL,
                        "method": "GET",
                        "headers": {
                            "authorization": token
                        }
                    };
                    $.ajax(settings).done(function (response) {
                        console.log(response);
                        $.each(response, function () {
                            self.data.push({
                                Name: this.Name,
                                OptyId: this.OptyId,
                                OptyNumber: this.OptyNumber,
                                SalesStage: this.SalesStage,
                                Revenue: this.Revenue
                            });
                        });
                        self.dataReady = true;
                        displaySalesCloudData();
                    });
                }

Step 4: Display data using Oracle JET filmstrip component

function displaySalesCloudData()
                {
                    console.log("inside displayFilmStrip");
                    self.pagingModel = null;
                    getItemInitialDisplay = function (index)
                    {
                        return index < 1 ? '' : 'none';
                    };
                    getPagingModel = function ()
                    {
                        if (!self.pagingModel)
                        {
                            var filmStrip = $("#filmStrip");
                            var pagingModel = filmStrip.ojFilmStrip("getPagingModel");
                            self.pagingModel = pagingModel;
                        }
                        return self.pagingModel;
                    };
                }

 

Build and Run the application on Android emulator/device

 

In your command prompt, please change directory to project folder and run the following command:

 

Build the application using following command

 grunt build --platform=android

 

Once build is success, then run the application using following command, assuming android emulator is already up and running:

grunt serve --platform=android  --disableLiveReload=true  

 

Output

Please find attached the screen-shot output of the emulator:

1. Application Icon:

app-icon.png

 

2. SSO Login

 

app-dashboard-sso-login-button.png

 

3. SSO Login view in embedded web-view. Enter mobile user credentials and press SignIn Button

app-login-page.png

 

4. Success Alert message

app-login-success.png

5. Display of Sales Cloud data on view using JET Filmstrip component

app-dashboard-filmstrip.png

This blog is inspired by Geertjan's Blog on Track the Closest Beacon on Android via Cordova

In this blog, I will be using Oracle Mobile Cloud Services (MCS) version 16.3.x and above, Oracle JavaScript Extension toolkit (JET) hybrid cordova based application version 1.0.2 and Bluetooth low energy (BLE) beacon hardware device to demonstrate a sample use case to develop proximity based marketing and engagement for a retail store.

 

Using proximity marketing campaigns, retailers can keep consumers informed about the products, services, and actual special offers from each of the respective store sections. Retailers place these beacons in different store section which in turn continously broadcast a unique identifier that a Smartphone app can use to trigger appropriate action.

 

Key Concepts

Below tables summarizes the key components involved in developing proximity-based engagement

 

Components

Details

Beacon

Beacons use Bluetooth Low Energy transmissions to send out their identity. It basically broadcast four pieces of information:

  • UUID that identifies the beacon.
  • A Major number identifying a subset of beacons within a large group.
  • A Minor number identifying a specific beacon.
  • A TX power level in 2's compliment, indicating the signal strength few meter's from the device.

Oracle MCS

Oracle MCS Location services will be used to fetch list of devices by the given place ( latitude, longitude and radius)

Mobile app – Oracle JET Hybrid app

An application on the mobile phone picks up the nearby beacon information , and calculates its distance based on signal strength (txpower and rssi)

 

Proximity-based engagement flow

Below diagram shows the life-cycle flow for implementing a basic proximity-based engagement:

flow.png

 

 

Below are the main steps involved:

  1. Mobile application sends it’s current location – latitude, longitude and radius to Oracle MCS
  2. Oracle MCS sends back the beacon registry details and that get’s stored in the mobile application.
  3. Mobile application starts listening to these devices over Bluetooth
  4. Mobile application starts picking up signals from nearby beacons
  5. On getting micro-location and context ,the application triggers appropriate action

 

Below table summarizes key terms used:

Terms

Details

UUID

UUID stands for Universally Unique Identifier.  It contains 32 hexadecimal digits, split into 5 groups, separated by dashes , example: F4826da6-4fa2-4e98-8024-bc5b71e0893f

 

Component: Oracle Mobile Cloud Services (MCS)

The retail store decides to deploy iBeacon inside its store and make a mobile application that can tell the user once they arrive at a specific store, they would define a UUID that is unique to their app and the beacons inside their stores. Inside the stores, they would place beacon devices and configure each of them to use a different “minor” value.

 

For example, at the store A, they would place all beacon devices broadcasting the RDXApparel UUID, major value 1, minor 1 near the Kid’s toy section , minor 2 near the handbags section and minor value 3 near the cashier. At store B, they would use the same UUID, but major 2 and minor values according to the location inside the store.

 

In order to achieve this, at first we need to create a mobile backend, assign location of our retail store and then assign the device details that are present in that particular store.

 

Step 1: Create a mobile backend

Create a mobile backend to access and configure services, in this example we will incorporate mobile user management and location services

 

Step 2: Add Location and associate device(s)

The retail store location and related device detailed needs to be uploaded/added into Oracle MCS. In order to do that,  we need to first add a new place under "Location" section in Oracle MCS.

A place is a physical location associated with one or more location devices.

Add a Location

OracleLocationOverview.png

 

Associate device(s) with the location

Add a device.png

 

Step 3: Test the added/uploaded data

Once data is added, we need to test if user is able to download this information. We will use Location services platform, POST API Return Places by Query. Here is sample request:

 

POST /mobile/platform/location/places/query HTTP/1.1
Host: xxx.mobileenv.us2.oraclecloud.com:443
oracle-mobile-backend-id: 12345678-3297-4d93-87a8-e36dc7d6842c
Authorization: Basic abc=
Content-Type: application/json
Cache-Control: no-cache
{
  "inGeoFence" : {
    "gpsCircle" : {
      "longitude":77.3211437,
      "latitude": 28.5591575,
      "radius": 10000
    }
  }
}

 

Here is sample output:

{
  "items": [
    {
      "id": 10,
      "createdOn": "2016-08-28T07:54:55.826+0000",
      "createdBy": "xxx@oracle.com",
      "modifiedOn": "2016-08-31T05:23:20.785+0000",
      "modifiedBy": "xxx@oracle.com",
      "name": "RDxApparel Noida",
      "label": "RDApparelx",
      "description": "RDxApparel store in Noida Sector 127",
      "hasChildren": false,
      "address": {
        "gpsCircle": {
          "longitude": 77.321,
          "latitude": 28.549,
          "radius": 999.99999999
        }
      },
      "devices": [
        {
          "id": 10,
          "createdOn": "2016-08-28T08:16:12.302+0000",
          "createdBy": "xxx@oracle.com",
          "modifiedOn": "2016-08-28T08:19:32.341+0000",
          "modifiedBy": "xxx@oracle.com",
          "name": "RDxApparel Kids section",
          "description": "Thank-you for visiting kid's section! \nCongrats, you are now eligible for 10% discount on kid's section items , your coupon code is RDXKIDS10",
          "beacon": {
            "iBeacon": {
              "major": "65504",
              "minor": "65505",
              "uid": "74278BDA-1114-4520-8F0C-720EAF059935"
            }
          },
          "properties": {},
          "links": [
            {
              "rel": "canonical",
              "href": "/mobile/platform/location/devices/10"
            },
            {
              "rel": "self",
              "href": "/mobile/platform/location/devices/10"
            }
          ]
        },
        {
          "id": 11,
          "createdOn": "2016-08-29T08:53:49.813+0000",
          "createdBy": "xxx@oracle.com",
          "modifiedOn": "2016-08-31T05:20:08.898+0000",
          "modifiedBy": "xxxx@oracle.com",
          "name": "RDxApparel Handbag section",
          "description": "Thank-you for visiting Handbag section! Congrats, you are now eligible for 40% discount on handbags , your coupon code is RDXHANDBAGS40",
          "beacon": {
            "iBeacon": {
              "major": "16808",
              "minor": "19400",
              "uid": "748BEEA2-1111-44C2-A59C-706FFACA6A3B"
            }
          },
          "properties": {},
          "links": [
            {
              "rel": "canonical",
              "href": "/mobile/platform/location/devices/11"
            },
            {
              "rel": "self",
              "href": "/mobile/platform/location/devices/11"
            }
          ]
        }
      ],
      "properties": {},
      "links": [
        {
          "rel": "canonical",
          "href": "/mobile/platform/location/places/10"
        },
        {
          "rel": "self",
          "href": "/mobile/platform/location/places/10"
        }
      ],
      "children": []
    }
  ],
  "totalResults": 1,
  "limit": 100,
  "count": 1,
  "hasMore": false
}

 

Once we get status 200 OK, our back-end part is ready!

 

Component: Developing client-side Oracle JET Hybrid application

We will start implementing from scratch, you may please refer to Troubleshooting while developing your First JET based Hybrid Application blog in case of initial issues faced during development/configuration issues.

 

Project Setup using Yeoman

Yeoman generator for Oracle JET lets you quickly set up a project for use as a Web application or mobile-hybrid application for Android and iOS. Use following command to generate hybrid application for Android:

 

yo oraclejet:hybrid proximitysample --appId=com.rdh.proximitysample --appName="proximitysample" --template=navBar --platforms=android

 

The navBar template based native hybrid application code will be placed in “proximitysample” folder.

 

Cordova Plugin Required

Following cordova plugin needs to be added in our application:

 

  1. cordova-plugin-geolocation: This plugin provides information about the device's location, such as latitude and longitude. Link: https://cordova.apache.org/docs/en/latest/reference/cordova-plugin-geolocation/
  2. cordova-plugin-ibeacon: iBeacon plugin for cordova based hybrid application. Link: https://github.com/petermetz/cordova-plugin-ibeacon
  3. Cordova Local-Notification Plugin:  Plugin to display local notification, especially when application is not running in foreground. Link: https://github.com/katzer/cordova-plugin-local-notifications

 

cd hybrid
cordova plugin add cordova-plugin-geolocation 
cordova plugin add https://github.com/petermetz/cordova-plugin-ibeacon.git
cordova plugin add https://github.com/katzer/cordova-plugin-local-notifications

 

Implementation Steps

 

We will be implementing the entire code in dashboard.html and dashboard.js for easy implementation.

 

Below is the updated dashboard.html file

 

Untitled.png

 

Add below variables in dashboard.js file DashboardViewModel() function, they will be used in various function in given steps:

       var mRegions = [];
                var mNearestBeacon = null;
                var mNearestBeaconDisplayTimer = null;
                var beaconID = '00000';
                var winningCounter = 0;
                self.viewbeaconName = ko.observable();
                self.viewDiscountCoupon = ko.observable();

 

 

Below are the implementation steps to fetch micro-location and context and generating a location notification in the app to display relevant information:

 

Step 1:  Fetch the current location – latitude, longitude and radius and send it to Oracle MCS

 

               // fetches current latitude and longitude
                function getGeoLocationCoordinates()
                {
                    var onSuccess = function (position) {
                        var lat = position.coords.latitude;
                        var long = position.coords.longitude;
                        console.log(lat);
                        console.log(long);
                        // Pass the latitude and logitude to MCS location services
                        downloadBeaconRegistry(lat, long);
                    };
                    function onError(error) {
                        alert('code: ' + error.code + '\n' +
                                'message: ' + error.message + '\n');
                    }
                    navigator.geolocation.getCurrentPosition(onSuccess, onError);
                }
                function onDeviceReady() {
                    // Will execute when device is ready, or immediately if the device is already ready.
                    getGeoLocationCoordinates();
                }

 

Step 2:  Fetch all the iBeacon device details received from Oracle MCS Location Services Platform API in the application

 

// downloads device deatails based on location given from Oracle MCS Location Platform Service
                function downloadBeaconRegistry(gpsLat, gpsLong)
                {
                    var settings = {
                        "async": true,
                        "crossDomain": true,
                        "url": "https://xxx.mobileenv.us2.oraclecloud.com:443/mobile/platform/location/places/query",
                        "method": "POST",
                        "headers": {
                            "content-type": "application/json",
                            "oracle-mobile-backend-id": "your-oracle-mobile-backend-id",
                            "authorization": "Basic " + btoa("mobile-user-name" + ":" + "mobile-user-password")
                        },
                        "data": JSON.stringify({
                            inGeoFence: {
                                gpsCircle: {
                                    longitude: gpsLong,
                                    latitude: gpsLat,
                                    radius: 1000 // assuming the radius to be around 1000 meter
                                }
                            }
                        })
                    };
                    $.ajax(settings).done(function (response) {
                        // populate beacon registry in an array
                        for (var i in response.items[0].devices)
                        {
                            // save all device details in mRegions array
                            mRegions.push(
                                    {
                                        id: response.items[0].devices[i].id,
                                        name: response.items[0].devices[i].name,
                                        description: response.items[0].devices[i].description,
                                        uid: response.items[0].devices[i].beacon.iBeacon.uid,
                                        major: response.items[0].devices[i].beacon.iBeacon.major,
                                        minor: response.items[0].devices[i].beacon.iBeacon.minor,
                                        beaconID: response.items[0].devices[i].beacon.iBeacon.uid + ':' +
                                         response.items[0].devices[i].beacon.iBeacon.major + ':' + response.items[0].devices[i].beacon.iBeacon.minor
                                    });
                        }
                        startDetectingBeacons();
                    });
                }

 

Step 3: Start listening to devices over Bluetooth

 

 // start detecting given beacons
                function startDetectingBeacons()
                {
                    function onDidRangeBeaconsInRegion(result)
                    {                      
                        updateNearestBeacon(result.beacons);
                    }
                    var delegate = new cordova.plugins.locationManager.Delegate();
                    cordova.plugins.locationManager.setDelegate(delegate);
                    delegate.didRangeBeaconsInRegion = onDidRangeBeaconsInRegion;
                    for (var i in mRegions)
                    {
                        var beaconRegion = new cordova.plugins.locationManager.BeaconRegion(
                                mRegions[i].beaconID,
                                mRegions[i].uid,
                                mRegions[i].major,
                                mRegions[i].minor);
                        cordova.plugins.locationManager.startRangingBeaconsInRegion(beaconRegion)
                                .fail()
                                .done();
                    }
                    mNearestBeaconDisplayTimer = setInterval(displayNearestBeacon, 1000);
                }

 

 

Step 4: Find the nearest Beacon

 

 // generates uniqueId based on uuid, major and minor number
               function getBeaconId(beacon)
                {
                    return beacon.uuid + ':' + beacon.major + ':' + beacon.minor;
                }               
                function isSameBeacon(beacon1, beacon2)
                {
                    return getBeaconId(beacon1) === getBeaconId(beacon2);
                }
               // beacon.accuracy returns the distance of beacon from mobile device
                function isNearerThan(beacon1, beacon2)
                {
                    return beacon1.accuracy > 0
                            && beacon2.accuracy > 0
                            && beacon1.accuracy < beacon2.accuracy;
                }
                function updateNearestBeacon(beacons)
                {
                    for (var i = 0; i < beacons.length; ++i)
                    {
                        var beacon = beacons[i];
                        if (!mNearestBeacon)
                        {
                            mNearestBeacon = beacon;
                        } else
                        {
                            if (isSameBeacon(beacon, mNearestBeacon) ||
                                    isNearerThan(beacon, mNearestBeacon))
                            {
                                mNearestBeacon = beacon;
                            }
                        }
                    }
                }

 

Step 5: On getting micro-location and context, calculate how far the user is from a given beacon (i.e. retail store section) and display relevant information on the mobile app

 

 function findBeacon(beaconObj)
               {                    
                    return (beaconObj.beaconID).toUpperCase() === beaconID.toUpperCase();
                }
                function displayNearestBeacon()
                {
                    if (!mNearestBeacon) {                        
                        return;
                    }                    
                    beaconID = getBeaconId(mNearestBeacon);              
                    var objBeacon = mRegions.find(findBeacon);                   
                   self.viewbeaconName('You are now just '+ mNearestBeacon.accuracy + ' meters away from our ' + objBeacon.name +'!');
                   if(mNearestBeacon.proximity === 'ProximityNear' || mNearestBeacon.proximity === 'ProximityImmediate' )
                    {
                        self.viewbeaconName('Welcome to '+ objBeacon.name +'!');                        
                        winningCounter++;                        
                    }                    
                    if(winningCounter > 30)
                    {
                        winningCounter = 0;
                        showLocalNotification(objBeacon.name, objBeacon.description);                 
                     }
                }
Step 6: Trigger a local notification displaying important information based on time spent by user near a section

 

 function showLocalNotification(beacontitle, beacondescription)
                {
                    cordova.plugins.notification.local.schedule({
                        title: beacontitle,
                        message: beacondescription
                    });                 
                   self.viewDiscountCoupon(beacondescription);                    
                }

 

Finally, update handleDetached function to reset the timer interval:

 self.handleDetached = function () {
                    document.removeEventListener('deviceready', onDeviceReady);
                    clearInterval(mNearestBeaconDisplayTimer);
                    mNearestBeaconDisplayTimer = null;
                };

 

This is the one of the easiest way to interact. However, the user context information is of real advantage as we can send this information to big data systems for extracting information like user behavior , analytics.

 

Build and Run the application on Android device

In your command prompt, please change directory to project folder and run the following command:

 

  1. Build the application using following command
grunt build --platform=android

 

Please ensure to turn ON your mobile's Bluetooth, GPS and mobile data  before running the application. Also please allow the app to use Bluetooth and GPS when app runs.

  1. Once build is success, then run the application using following command:
grunt serve --platform=android  --disableLiveReload=true

Demo Video

Below is the video output of the Mobile application:

 

 

**The views expressed in this post are my own and do not necessarily reflect the views of Oracle.

In this blog, I will be covering step-by-step process to implement Push-Notification in Oracle JavaScript Extension Toolkit (JET) hybrid application. To complete the entire Push-notification ecosystem, the notification will be sent from Oracle Mobile Cloud services (MCS) to Firebase Cloud Messaging (FCM) as the notification server, and these notifications will be received by our JET hybrid app.

Note: Google Cloud Message (GCM) will be upgraded to Firebase Cloud Messaging (FCM) soon, so this blog is applicable to both GCM and FCM

Key Concepts

Below tables summarizes the key components involved in implementing for Push Notification:

ComponentDetails
GCM/FCM serverGCM/FCM will be involved in sending messages between Oracle MCS and the client app.
Oracle MCSOracle MCS sends data to the client application via the GCM/FCM server.
Client Application (JET Hybrid app)A JET Hybrid application that communicates with Oracle MCS

 

 

Push Notification Life-cycle Flow

Below diagram shows the life-cycle flow for implementing Push Notification:

 

Push Notification Flow.png

Below are the main steps involved:

  1. First android device sends Sender ID, application ID to GCM/FCM for registration
  2. Upon successful registration, GCM/FCM server issues Registration ID to android device
  3. After receiving registration id, android device will send this registration id to Oracle MCS
  4. Oracle MCS will store registration id for later use
  5. Whenever push notification is required, it will be sent via Oracle MCS to GCM/FCM , it will send message and registration ID
  6. GCM/FCM server will deliver  that message to mobile device.

 

 

Below table summarizes key terms used:

CredentialsDetails
Sender IDThis is the “Project Number” in Google Developer Console. The sender ID is used in the registration process by the application with GCM/FCM
Application ID

The  JET hybrid client application that is registering to receive messages.  Application ID will be the Package name (from application manifest) incase of hybrid app running on android device

Registration IDThe registration ID issued by GCM/FCM server to the client application that allows it to receive messages, i.e. notifications

 


Component 1: Cloud Messaging Server: FCM/GCM

Firebase Cloud Messaging (FCM) is the new version of GCM, so demonstrating FCM instead of GCM.

The first step is to enable Notification from Firebase network, below are the details:

 

  1. Go to https://console.firebase.google.com/ and  Create a New Project
  2. Provide Project Name and  Country/Region
  3. Click on "Add APP" and select Android version
  4. Add Firebase to your app, enter Package Name,  please note that the package name should match exactly with your hybrid application name
  5. Click on Add App, a google-services.json file will be downloaded on your system
  6. Please take note of  “project_number” and “api_key” values, these values will be used in Oracle MCS and in client app

 

google-services.png

 

Component 2: Our Application Server: Oracle MCS

The next step is to register the client application in Oracle MCS:

  1. Click menu icon in the upper left corner of the page and select Applications > Mobile Backends.
  2. Select the mobile backend you want to use and click Open.
  3. In the left navigation bar, click Clients.
  4. In the Client Applications part of the page, identify the client application, and click Register Client.
  5. In the dialog, select the platform and fill in the information needed, based on your platform.
  6. For Android, you insert the Google API Key in the API Key field.
  7. Make a note of the value of the Application Key that is shown in the dialog when you create the client. You'll need to add this key to the configuration file

 

GoogleCloudMessagingKey.png

 

Component 3: Client Application

Before starting the client application, we need to configure our system for setting up the pre-requisites for developing for Android device, below are the same:

 

Android Settings in your machine

Please ensure following items are updated on your system:

  1. Android SDK 23 version or above (latest version is preferred)
  2. Upgrade Android SDK Tools for following to their latest version available:
    • Android Support Library version
    • Local Maven repository for Support Libraries (Android Support Repository)
    • Google Play Services version

 

sdktools.png

 

Developing client-side Oracle JET Hybrid application

We will start implementing from scratch to implement receiving push notification in oracle jet hybrid application. You may please refer to Troubleshooting while developing your First JET based Hybrid Application blog incase of initial issues faced during development/configuration issues.

 

Project Setup using Yeoman

Yeoman generator for Oracle JET lets you quickly set up a project for use as a Web application or mobile-hybrid application for Android and iOS. Use following command to generate hybrid application for Android:

 

yo oraclejet:hybrid pushnotifysample --appId=com.rdh.pushnotify --appName="pushnotifysample" --template=navBar --platforms=android

 

 

The navBar template based native hybrid application code will be placed in “pushnotifysample” folder.

 

Cordova-plugin-push

  • In command prompt, go to pushnotifysample\hybrid folder
  • Now, add cordova-plugin-push plugin.This plugin offers support to receive and handle native push notifications with a single unified API, and with no dependency on any other plugin’s. Here is the link: https://github.com/phonegap/phonegap-plugin-push

 

cordova plugin add phonegap-plugin-push --variable SENDER_ID=" XXXXXXXX"

 

Where the XXXXXXX in SENDER_ID="XXXXXXX" maps to the project number in the Firebase developer console

 

 

Adding Oracle MCS Cordova SDK

In order to communicate with Oracle MCS, following steps are required:

  1. Download the Cordova SDK from Oracle MCS. Extract the same on your local machine. It will contain Javascript based Cordova SDK , configuration files and documentation
  2. Add Oracle MCS Cordova SDK to your application, Copy mcs.js, mcs.min.js and oracle_mobile_cloud_config.js into the directory where you keep your JavaScript libraries.

 

For example, in this implementation, I have kept these files in mcs folder added in js/libs folder as shown in below image:

mcs-additions.png

2. Fill in your mobile backend details in oracle_mobile_cloud_config.js.

 

mcs_config.png

 

For more details, please See Configuring SDK Properties for Cordova.

 

After adding the physical files, update the paths mapping for mcs and mcs_cloud_config  in main.js file under requirejs.config section:

     paths:
               //injector:mainReleasePaths
                            {
                                'knockout': 'libs/knockout/knockout-3.4.0.debug',
                                'jquery': 'libs/jquery/jquery-2.1.3',
                                'jqueryui-amd': 'libs/jquery/jqueryui-amd-1.11.4',
                                'promise': 'libs/es6-promise/promise-1.0.0',
                                'hammerjs': 'libs/hammer/hammer-2.0.4',
                                'ojdnd': 'libs/dnd-polyfill/dnd-polyfill-1.0.0',
                                'ojs': 'libs/oj/v2.0.2/debug',
                                'ojL10n': 'libs/oj/v2.0.2/ojL10n',
                                'ojtranslations': 'libs/oj/v2.0.2/resources',
                                'text': 'libs/require/text',
                                'signals': 'libs/js-signals/signals',
                                'mcs': 'libs/mcs/mcs',
                                'mcsconf': 'libs/mcs/oracle_mobile_cloud_config'
                            }
                    //endinjector

 

 

Implementation Steps

 

Add the additional modules: mcs and mcsconf to get loaded in dashboard.js file:

 

define(['ojs/ojcore', 'knockout', 'jquery', 'mcs', 'mcsconf'],

 

Below are the four main steps of push notification implementation, they need to be called only once in the application life cycle.

 

 

Step 1.  Load Mobile Back end’s Configuration into the application:

function initializeMCS() {
    mcs.MobileBackendManager.platform = new mcs.CordovaPlatform();
    mcs.MobileBackendManager.setConfig(mcs_config);
    mcsBackend = mcs.MobileBackendManager.getMobileBackend("BACKEND_NAME_AS_MENTIONED_IN_CONF_FILE");
    if (mcsBackend != null) {
        mcsBackend.setAuthenticationType("basicAuth");
    }
}

 

 

Step 2. Authenticate and Log In Using the SDK

               function login(mcsBackend, username, password) {
                    mcsBackend.Authorization.authenticate(username, password, success, failed);
                    function success(response, data) {
                        alert("Login Success!");
                        registerDeviceForMCSPush(mcsBackend);
                    }
                    function failed(response, data) {
                        alert("Login failed!");                       
                    }
                }

 

 

Step 3. Below code initializes, registers the device and is ready to receive notification or error from GCM/FCM

   function registerDeviceForMCSPush(mcsBackend) {
        var defer = $.Deferred();
        if (typeof PushNotification !== 'undefined') {
            try {
                var push = PushNotification.init({
                    "android": {
                        // TODO replace Google Project Number here
                        senderID: "XXXXXXXXX"
                    }
                });
                push.on('registration', function (data) {
                    var regId = data.registrationId;
                    deviceHandshakeforCordova(mcsBackend, regId);
                });
                push.on('notification', function (data) {
                    alert("Push Notification from Oracle MCS: " + data.message);
                });
                push.on('error', function (e) {
                    alert("Push Notification Error=" + e.message);
                });
            } catch (ex) {
                alert("Error registering device with MCS" + ex);
                defer.reject();
            }
        } else {
            alert("PushNotification NOT Defined!");
            defer.reject();
        }
        return $.when(defer);
}

 

 

Step 4. Device Handshake, here the application sends Registration Id to Oracle MCS

function deviceHandshakeforCordova(mcsBackend, registrationID)
{
    var appId = "your_package_name_here";
    var appVersion = "1.0";
    mcsBackend.Notifications.registerForNotifications(registrationID, appId, appVersion,
            function (statusCode, headers, data) {
                var success_msg = "sucess:statusCode=" + statusCode + ",data=" + data + "headers=" + headers;
                console.log(success_msg);
            },
            function (statusCode, data) {
                var failure_msg = "failure:statusCode=" + statusCode + ",data=" + data;
                console.log(failure_msg);
            });
}

 

Build and Run the application on Android emulator/device

 

In your command prompt, please change directory to project folder, e.g. pushnotifysample in this case and run the following command:

 

  1. Build the application using following command
grunt build --platform=android

 

  1. Once build is success, then run the application using following command, assuming android emulator is already up and running:
grunt serve --platform=android  --disableLiveReload=true

Test Push notification

At this point of time the client app is ready to receive push notifications from GCM/FCM

 

Sending notification from MCS console

To test the application, we can send a notification from MCS console

pushnotifyconsole.png

 

The message would be sent to FCM, which in turn will send to our registered application. If the application is in background, it will receive the notification in the notification area, on tapping the notification, it will land you to your app for further action

device-2016-08-11-171917.png

 

Troubleshooting section

Issue 1: ERROR: During build process, encounter following error:

 

Could not resolve com.google.android.gms:play-services-gcm:9.0.2+

googleplayservices-bug.png

Possible Solution:

Please update following to the latest:

  • Android Support Library
  • Local Maven repository for Support Libraries (formerly Android Support Repository)
  • Google Play Services

 

 

Issue 2: Client Application throws 400 Bad Request after logging is success

 

Failed to load resource: the server responded with a status of 400 (Bad Request)

 

Possible Solution:

 

Please confirm that you are sending correct registrationID, appId and appVersion to mcsBackend.Notifications.registerForNotifications function.Example :

Registration ID: "AxdkfjfDfkfkfkfjfFdjfjjf=",

appId: "com.yourcompany.project"

appVersion: "1.0"

 

***EDIT on 18-Aug-2016,  Change log: Added Issue 3***

 

Issue 3: During building the application, I get "No platforms added to this project" error.

Error log on console:

 

D:\jetapps\jetdemo>grunt build --platform=android
Running "build" task
Running "clean:www" (clean) task
>> 0 paths cleaned.
Running "copy:wwwDev" (copy) task
Created 212 directories, copied 1274 files
Running "copy:merges" (copy) task
Created 8 directories, copied 37 files
Running "includeCordovaJs" task
Running "shell:cordovaPrepare" (shell) task
>> Error: No platforms added to this project. Please use `cordova platform add <platform>`.
>>
Warning: Done, with errors: command "cordova prepare android" (target "cordovaPrepare") exited with
code 1. Use --force to continue.
Aborted due to warnings.

 

Possible Solution:

Probably  it's path problem, you didn't add android SDK path in your environment variable. Please download latest android SDK and give path in environment variable and try again

In-case of Windows: Go to System Properties ->  Environment Variable : Add ANDROID_HOME as variable and path should be path to your Android SDK, For example path is C:\Users\rdh\AppData\Local\Android\Sdk

 

 

**The views expressed in this post are my own and do not necessarily reflect the views of Oracle.

Want to get started with Oracle JavaScript Extension Toolkit (JET) Hybrid Application Development but not sure what you need to know first? I will cover here what the tools/frameworks you need to get up and running  and resolving common issues faced while developing your first JET based hybrid app.  Oracle JavaScript Extension Toolkit (JET) provides a seamless hybrid mobile development experience that any organization can leverage to create simple, secure and visual mobile applications.; this link is the best place to get started.

 

This blog is divided in three parts:

  • Development Machine Setup
  • Creating a JET Mobile App
  • Troubleshooting common issues

 

Part-I: Development Machine Setup

Here are the main frameworks/tools that need to be setup in the machine to get started. For more detailed documentation, please see the following link. Prerequisites for Developing Applications with Oracle JET

 

 

Framework/Tool

Usage in Oracle JET

Website

Node.js

Used as package manager for development tools

https://nodejs.org

Bower

Package manager for web site components that can contain HTML, CSS, JavaScript, fonts, and image files

http://bower.io/

Yeoman

Open source tool used to scaffold web or hybrid applications


http://yeoman.io/

Grunt

Used for Building and serving

http://gruntjs.com/

Cordova

Cross-platform development targeted to multiple platforms with one code base

http://cordova.apache.org/

Android/iOS

SDK for android and iOS

Android and iOS SDK page

 

Install Node.js

node --version

Node Proxy Setup

Node takes config settings to set the proxy server for http and https. Copy and paste these commands into a shell to execute.

npm config set proxy http://proxy.company.com:80

npm config set https-proxy http://proxy.company.com:80

 

After installing node.js , user  has to use node package manager (npm command) to install the below tools (in any given order)

 

Install Bower

npm install -g bower

Bower Proxy Configuration

Bower requires a file named .bowerrc in your home directory.

  • Create a file called .bowerrc with the following JSON text.  Bower reads this file to obtain its proxy information.

{ "proxy":"http://proxy.company.com:80", "https-proxy":" http://proxy.company.com:80" }

  • Create the .bowerrc file in the %HOME% directory

,

Install Yeoman and Grunt

npm install -g yo

npm install -g grunt-cli

Yeoman uses the environment variables HTTP_PROXY and HTTPS_PROXY for proxy settings, so nothing additional needs to be done. Verify whether the installation is completed by running the commands to check the versions:

yo --version

grunt --version

Install Cordova

npm install -g cordova

Verify installation by running this command:

cordova --version


Install Android SDK

 

For installing the Android SDK refer to the following link.  Alternatively you could also download Android studio and update it’s SDK and tools to latest

Part-II: Create a JET Mobile App

Scaffold a Mobile Application

yo oraclejet:hybrid --appName=JETMobileDemo --template=navBar --platforms=android

Build

grunt build:dev --platform=android  (By default it will assume emulator)

Serve

grunt serve --platform=android (By default, it will assume emulator)

Part-III: Troubleshooting

Here are some tips to resolve the common issues encountered when deploying your first hybrid application:

Issue 1: Grunt build or Grunt serve command getting stuck or failing

If you are building or installing your application for the first time, especially behind corporate firewalls, you may face issues of build getting failed.

 

Possible Resolution:

This particular problem may arise in case you are behind corporate firewall and there is some proxy setting that's not correct or proxy itself not set. Please set (or check if already set) your npm and bower proxy settings as mentioned in the above section.

 

Issue 2: Not able to launch Hybrid mobile app in emulator

There may be a possibility that you are able to build and launch your hybrid mobile application in your Android device, but not able to launch the same application on Android emulator

For instance, you may receive the following logs on your console and they keep on waiting:

Running "serve" task

Running "customServe" task

Invoking cordova serve

Static file server running on: http://localhost:8090 (CTRL + C to shut down)Invoking cordova run

Starting watch

Running "watch" task

  1. Waiting...

 

Possible Resolution:

Generally when we issue the grunt serve without starting the emulator, grunt will try to start the emulator and any commands that grunt issues might not work as emulator is still booting up.

So in order to avoid this issue:

  • Please start the emulator first!
  • Don't specify the destination parameter for grunt serve (it will deploy to the open/default emulator)
  • Then grunt serve to install the app on your emulator
  • Ensure  grunt build before the grunt serve

Issue 3: Running into CORS issue while debugging

There may be possibility that user is not able to interact with any mobile middleware , .e.g. Oracle Mobile Cloud Service (MCS), e.g like performing authentication while using emulator/web and live debugging (enabled to true by default).

 

Possible Resolution:

While running on an emulator, please disable the live reload feature otherwise a CORS error will happen when interacting with MCS.

Use the --disableLiveReload feature during grunt serve command

grunt serve --platform=android  --disableLiveReload=true

Issue 4: LiveReload not working on device, alternatives for troubleshooting

Unfortunately when you serve to device, livereload won't work due to a known bug.

Alternate Resolution:

The recommended process is to first develop the app contents within browser using the --web=true flag.  This will lead to faster reloading and faster serve.

grunt serve --platform=android –web=true

 

Next, then use livereload in emulator (though much slower in Android native emulator).

grunt serve --platform=android (By default, it will install on emulator)


Then at the very last, you can serve your app to device.

grunt serve --platform=android --destination=device --disableLiveReload=true

 

The views expressed in this post are my own and do not necessarily reflect the views of Oracle.