Skip to Content

Hi Folks,

UPDATE:- How we can consume ODATA through SMP3.0 in our Kapsel/Hybrid SAPUI5 App (Step 5 to Step 6).

Since last few days I was working on one Hybrid App development for Android platform with SMP 3.0 using SAPUI5 as a UI framework. I followed the great blog Getting Started with Kapsel – Part 1 by Daniel Van Leeuwen which helped me alot in making a kick start to my development with SMP3.0.

By following each and every step of the blog i was able to register my application on SMP3.0 and was able to call my SAPUI5 views(UI). But one thing which i noticed was that even after performing the registration process, whenever i reopen the app after closing, then also it was performing the registration process from the initial step again every time even if it is registered. So, after analyzing the code, i found that it was happening because applicationContext variable was initialized null which was global in scope and which needs to be global as what i think. So, that we can access its parameter across the application (like accessing the back-end point URL or ConnectionId).

So, every time we reopen the app, applicationContext variable is set to null and on clicking the register button it starts registering the app again, but every time the application connection id which i was getting was same and which was very obvious.

Below is my index.html file which i was using.


<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
        <title>Kapsel Android app Logon on SMP 3.0 with UI5</title>
         //- Loading from the publicly available server.  Only load the mobile lib "sap.m" and the "sap_bluecrystal" theme -->
        <script src="https://sapui5.netweaver.ondemand.com/resources/sap-ui-core.js"
        id="sap-ui-bootstrap"
        data-sap-ui-libs="sap.m"
        data-sap-ui-theme="sap_bluecrystal"
        data-sap-ui-xx-bindingSyntax="complex"
        data-sap-ui-resourceroots='{
            "com.app": "./"
        }'>
        </script>
        <script type="text/javascript" src="cordova.js"></script>
//- Code for registering the Application on SMP3.0-->
        <script type="text/javascript">
 
          applicationContext = null;
    
         window.onerror = onError;
         function onError(msg, url, line) {
                var idx = url.lastIndexOf("/");
                var file = "unknown";
                if (idx > -1) {
                    file = url.substring(idx + 1);
                }
                alert("An error occurred in " + file + " (at line # " + line + "): " + msg);
                return false; //suppressErrorAlert;
         }
        
         function logonUnregisterSuccessCallback(result) {
                alert("Successfully Unregistered");
                applicationContext = null;
                //sap.Logon.unlock(function () {},function (error) {});
         }
         /* Function called on Success */
         function logonSuccessCallback(result) {
                alert("Successfully Registered");
                applicationContext = result;
                    var oShell = new sap.m.Shell({
                                           app : new sap.ui.core.ComponentContainer({name:"com.app"}),
                                               });
                   oShell.placeAt("content");
    }
    function register() {
    alert("Application Context"+applicationContext);
          if (applicationContext) {
                    alert("Already Registered");
                    return;
                }
                var appId = "com.sap.app"; // Change this to app id on server
        
                // Optional initial connection context
                var context = {
                    "serverHost": "SMP Server URL", //Place your SMP 3.0 server name here
                    "https": "false",
                    "serverPort": "8080",
                    "user": "SMP UserId", //Since the application com.mycompany.logon uses the No Authentication Challenge provider, any user name and password will work.
                    "password": "SMP Password", //once set can be changed by calling sap.Logon.changePassword()
                    "communicatorId": "REST"
                };
        
                sap.Logon.init(logonSuccessCallback, logonErrorCallback, appId, context);
    
                //sap.Logon.unlock(logonSuccessCallback, errorCallback);  //No need to call this as init shows the register/unlock screen when called.
            }
            function logonErrorCallback(error) {   //this method is called if the user cancels the registration.
                console.log("An error occurred:  " + JSON.stringify(error));
                if (device.platform == "Android") {  //Not supported on iOS
                    navigator.app.exitApp();
                }
            }
            function unRegister() {
                if (applicationContext == null) {
                    alert("Not Registered");
                    return;
                }
                sap.Logon.core.deleteRegistration(logonUnregisterSuccessCallback, unRegisterErrorCallback);
            }
            function unRegisterErrorCallback(error) {
                console.log("An error occurred:  " + JSON.stringify(error));
            }
        </script>
    </head>
    <body class="sapUiBody" id="content"/>
        <button id="register" onclick="register()">Register</button>
        <button id="unregister" onclick="unRegister()">Unregister</button>
    </body>
</html>

But what i think and have also observed in my past native app development experience using SMP3.0, that once the application is registered on SMP3.0 it should not go for registration process again.

So, now i thought to implement the following 2 points in my app which are:-

1) Once the application is registered, registration process should not be repeated unless n until it is uninstalled or unregistered.

2) The registration process should be done automatically without any user interaction when the app is runned very first time after installation.

3) And consuming OData services from my Hybrid/kapsel SAPUI5 App using SMP 3.0 end-point URL.

So, to implement above functionalities, i thought to do it with WebSQL database which uses the SQL Lite DB of devices.

Below is the step by step process to do the same.

Prerequisites

1) Set up the development enviroment

2) Have completed all steps till Getting Started with Kapsel – Part 2 — Logon


Step 1 :- Run the below command using the cmd

1) cd C:\Kapsel_Projects\LognDemo

2) cordova plugin add https://github.com/brodysoft/Cordova-SQLitePlugin


then at last 3) cordova -d prepare


Step 2 :- Create a new File as “register.js” for writing the code to register our application on SMP 3.0



var db;
applicationContext = null;
appURL = "";
window.onerror = onError;
function onError(msg, url, line) {
    var idx = url.lastIndexOf("/");
    var file = "unknown";
    if (idx > -1) {
        file = url.substring(idx + 1);
    }
    alert("An error occurred in " + file + " (at line # " + line + "): " + msg);
    return false; //suppressErrorAlert;
}
function logonUnregisterSuccessCallback(result) {
    alert("Successfully Unregistered");
    applicationContext = null;
    //sap.Logon.unlock(function () {},function (error) {});
}
function register() {
        if (applicationContext) {  // if applicationContext exists i.e.,app is already registered call the Component of SAPUI5 already registered
                  alert("Already Registered");
            
                  var oShell =new sap.m.Shell({app : new sap.ui.core.ComponentContainer({name:"com.app"}),
          });
          oShell.placeAt("content");
              }
        else{           // Else initialize the LOGON screen to register the application on SMP
              var appId = "com.sap.app"; // Change this according to your app id on SMP server
         
              // Optional initial connection context
              var context = {
                  "serverHost": "SMP SERVER URL", // your SMP 3.0 server name/ IP address
                  "https": "false",
                  "serverPort": "8080",
                  "user": "UserId", //SMP UserId
                  "password": "password", //once set can be changed by calling sap.Logon.changePassword()
                  "communicatorId": "REST"
              };
              sap.Logon.init(logonSuccessCallback, logonErrorCallback, appId, context);
     
              //sap.Logon.unlock(logonSuccessCallback, errorCallback);  //No need to call this as init shows the register/unlock screen when called.
          }
}
function logonSuccessCallback(result) {
    alert("Successfully Registered");
    applicationContext = result;
    // If application is registered successfully then insert the applicationConnection ID into APPDATA table and load the Component of SAPUI5
    insert();
var oShell =new sap.m.Shell({app : new sap.ui.core.ComponentContainer({name:"com.app"}),
          });
          oShell.placeAt("content");
}
function logonErrorCallback(error) {   //this method is called if the user cancels the registration.
    console.log("An error occurred:  " + JSON.stringify(error));
    if (device.platform == "Android") {  //Not supported on iOS
        navigator.app.exitApp();
    }
}
function unRegister() {
    if (applicationContext == null) {
        alert("Not Registered");
        return;
    }
    sap.Logon.core.deleteRegistration(logonUnregisterSuccessCallback, unRegisterErrorCallback);
}
function unRegisterErrorCallback(error) {
    console.log("An error occurred:  " + JSON.stringify(error));
}
// Function which is initially called when the cordova device is ready
function onDeviceReady() {
         db = window.sqlitePlugin.openDatabase({name:"Database",version: "1.0", location:-1});
         db.transaction(function(tx) {
    
// Creating table to store the applicationConnection Id
          tx.executeSql('CREATE TABLE IF NOT EXISTS APPDATA (id integer primary key, appId text,  endURL text)');
// Reading the table to get the application connection ID
          tx.executeSql("SELECT appId, endURL from APPDATA;", [], function(tx, res) {
    
// Calculating the number of rows in table
          var len = res.rows.length;
// Checking whether application ID exists or not
    
               if(len>0){         
               applicationContext = res.rows.item(0).appId;
               appURL = res.rows.item(0).endURL;
       
               }
// Calling the register function to register the app
               register();
            },null);  
      
         });
      }
// Function to read the values from the SQLLite DB
function read(){
  db.transaction(function(tx) {
    tx.executeSql("SELECT appId from APPDATA;", [], function(tx, res) {
        alert("tx"+res);
          console.log("res.rows.length: " + res.rows.length + " -- should be 1");
          appId = res.rows.item(0).appId;
          alert("appId-->"+appId);
       });
 
    });
}
// Function to insert the data in SQLLite DB
function insert(){ // inserting the applicationConnection ID in APPDATA table
  db.transaction(function(tx) {
  tx.executeSql('CREATE TABLE IF NOT EXISTS APPDATA (id integer primary key, appId text, endURL text)');
  tx.executeSql("INSERT INTO APPDATA (appId, endURL) VALUES (?,?)", [applicationContext.applicationConnectionId, applicationContext.applicationEndpointURL], function(tx, res) {
 }, function(e) {
          console.log("ERROR: " + e.message);
        });
});
}



Step 3 :- Call the “register.js” and onDeviceReady function on index.html as below


<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <meta name="format-detection" content="telephone=no" />
        <meta name="msapplication-tap-highlight" content="no" />
    
        <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height, target-densitydpi=device-dpi" />
        <link rel="stylesheet" type="text/css" href="css/index.css" />
        <link rel="stylesheet" type="text/css" href="util/style.css">
        <script type="text/javascript" src="js/register.js"></script>
    
           
        <title>Kapsel Logon</title>
    
        <script src="https://sapui5.netweaver.ondemand.com/resources/sap-ui-core.js"
        id="sap-ui-bootstrap"
        data-sap-ui-libs="sap.m"
        data-sap-ui-theme="sap_bluecrystal"
        data-sap-ui-xx-bindingSyntax="complex"
        data-sap-ui-resourceroots='{
            "com.app": "./"
        }'>
        </script>
     
        // Calling the onDeviceReady function to initiate the registeration of Application on SMP 3.0-->
        <script>
        document.addEventListener("deviceready", onDeviceReady, false);
       </script>  
       </head>
    <body class="sapUiBody" id="content">    
        <script type="text/javascript" src="cordova.js"></script>
    </body>
</html>

Step 4 :- Creating Component.js



jQuery.sap.declare("com.app.Component");
sap.ui.core.UIComponent.extend("com.app.Component", {
  metadata : {
        name : "Kapsel Logon App",
        version : "1.0",
        includes : [],
        dependencies : {
            libs : ["sap.m", "sap.viz"],
            components : []
        },
  },
init:function(oEvent){
  sap.ui.core.UIComponent.prototype.init.apply(this);
},
createContent:function(){
/
  var oView = sap.ui.view({
  id : "app",
  viewName : "com.app.views.main", //ID of view
  type : "JS",
  });
  return oView;
}
})

Step 5 :- Defining View.



sap.ui.jsview("com.app.views.main", {
  getControllerName : function() {
  return "com.app.views.main";
  },
  createContent : function(oController) {
  var oLine = new sap.viz.ui5.Line("LineChart",{width:"100%",title:new sap.viz.ui5.types.Title({visible:true,text:"Line Chart"})});
  return new sap.m.Page({
  content: [oLine ]
  });
  }
});

Step 6 :- Defining Controller and Consuming ODATA.



sap.ui.controller("com.app.views.main", {
  onInit: function() {
  var LineChart = new sap.ui.getCore().byId("LineChart");
  var mHeader = {"X-SMP-APPCID":applicationContext}; // applicationContext is the global variable which we have declared in the register.js
  var url = appURL; // appURL is the URL which we get while calling onDeviceReady function in register.js
  var oDataModel = new sap.ui.model.odata.ODataModel(url,true,"user","password",mHeader);
  var oDataset = new sap.viz.ui5.data.FlattenedDataset({
       dimensions: [{
       axis:1,
       name: 'E1',
       value: '{Entity1}'
       }
       ],
       measures: [{
         name: 'E2',
         value: "{Entity2}"
       }, {
         name: 'E3',
         value: "{Entity3}"
       }],
       data: {
         path: "/EntitySet",
       
       }
     });
  LineChart.setDataset(oDataset);
  LineChart.setModel(oDataModel);
  },
// onBeforeRendering: function() {
//
// },
// onAfterRendering: function() {
//
// },
// onExit: function() {
//
// }
});


Step 7 :- Run the app using your ADT as your android application.


Note:- Here i have used the SAPUI5 resoures from the public server which take some time while launching the app and my also give the “Cordova timeout error”.

In this way i implemented the above functionalities and consumed ODATA via SMP3.0. So, thought to share with you all which may help someone who want to try the same. Now, the registration will happen automatically if the application is not registered.


thanks & cheers 🙂

Deepak Sharma

To report this post you need to login first.

1 Comment

You must be Logged on to comment or reply to a post.

Leave a Reply