Building a SAP mobile app with Sencha Touch 2

In this tutorial we are going to build a mobile app which connects to SAP systems through SAP Gateway. The app is developed completely in JavaScript using the Sencha Touch 2 framework. Once development is completed we will package the application as a native iOS app using the new Sencha Packager.

In this tutorial we will cover:

  • an outline of the tools we are going to use
  • JavaScript code for basic functional app
  • running the app in a desktop browser
  • packaging and running the app in the iPhone simulator
  • running the app on your iPhone

Introducing the cast…

Sencha Touch is a leading mobile JavaScript framework. It provides an extensive set of UI components which you can use to quickly build mobile apps that can run on many mobile devices. Sencha Touch 2 (ST2) is the latest version, and currently in Beta 3. Download the latest version.

SAP NetWeaver Gateway is a SAP server add-on that allows mobile devices (and other consumers) to connect to SAP systems using OData-based REST services. The SAP Gateway front-ends SAP systems like ERP, CRM, SRM and enables controlled read/write access to business data using HTTP(S) and OData.SAP Gateway is a centerpiece of SAP’s mobile strategy and many mobile apps provided by SAP and its business partners are using SAP Gateway as well.

At this moment, SAP Gateway (version 2 SP3) only supports OData’s AtomPub XML format.

SAP graciously provides an online demo system where you can test-drive the SAP Gateway and the ERP and CRM systems. Our mobile app is going to connect to this demo system, using the demo user account provided by SAP. On SDN (SAP Developer Network) you will find more information on SAP Gateway and you will also find examples of other integration scenarios.

Same Origin Policy

Our Sencha Touch app will need to contact a remote SAP Gateway server to exchange XML data. In a web application, the browser will enforce the Same Origin Policy (SOP). This implies that the HTML file which contains the application must be served from the same domain, port and protocol as the XHR requests are sent to.

Let’s quickly explore the options:

  • JSONP is not an option: not supported by SAP Gateway. In addition limited to read-only scenarios.
  • Use a reverse proxy, which front-ends both the SAP Gateway and the webserver which serves up the application HTML/JS/CSS files. This way the HTML file and SAP Gateway appear to be on the same server. Good option, but adds a moving part to the solution.
  • Native packaging. In a native app, the SOP does not apply. Say again?  Because the HTML file is called by webkit using the file:// protocol, the SOP does not apply. This means there are no cross domain restrictions.

For our demo app we will opt for native packaging.

A closer look at the SAP data

Before we can start building the app we need to understand the content and structure of the data we will fetch from the server. Our first basic app will fetch Activity data from the SAP CRM demo system. Let’s lookup the activities in the SAP CRM system, so we know what activity data to expect:

image

As you can see, there are 5 open Activities for the demo user. To retrieve the activities from the SAP Gateway as an OData feed, get the following service url:

http://gw.esworkplace.sap.com/sap/opu/sdata/IWCNT/ACTIVITY/ActivityCollection?sap-user=<username>&sap-password=<password>

Visit the SAP Gateway Demo page to find the username and password to use.

The server will respond with XML in OData atom feed format. Each activity is contained in an “entry” element.image

The entry element contains the properties of an Activity:image

Developing the SAP mobile app

Enough talk, time to start coding! Our initial goal is to build a first, very basic mobile app which will show the user’s open Activities in SAP CRM. In Sencha Touch we need the following classes:

  • an Activity model: a class representing an Activity (on the client side!).  Defines the fields we want to use.
  • a Gateway Proxy: responsible for fetching data from the SAP Gateway server. It cleverly uses the field definitions of the Activity model to parse the response into Activity model instances which are handed over to the store.
  • an Activities store: holds a collection of activities in the browser. The store is filled by the output of the Gateway Proxy
  • an ActivityList: a UI component which renders a list of activities contained in the store

Looking at the structure of the OData xml, we can define the Activity model class. The fields configuration tells which properties we want to be extracted from the server response into our activity objects. The fetching and parsing is delegated to the proxy:

// Define the Activity model
Ext.define('App.model.Activity', {

    extend: 'Ext.data.Model',

    // the proxy config requires the sap_gateway
    requires: ['App.proxy.sap_gateway'],
    config: {

        // define the fields which we want to extract from the OData response.
        fields: [
            { name: 'Description', type: 'string' },
            { name: 'ActivityLocation', type: 'string' },
            { name: 'CategoryDescription', type: 'string' },
            { name: 'PriorityDescription', type: 'string' }
        ],

        // provide a proxy configuration
        proxy: {
            // use the special sap_gateway proxy
            type: 'sap_gateway',
            url: "https://gw.esworkplace.sap.com/sap/opu/sdata/iwcnt/activity/ActivityCollection?sap-user=<usern>&sap-password=<passsword>"
        }
    }
});

As you can see, the Activity model uses a special proxy type, identified by ‘sap_gateway’. ST2 will look for classes with an alias of proxy.sap_gateway. Also note that you need to require the proxy class in the Model before you can use it.

The proxy encapsulates the communication with remote SAP Gateway server. Our proxy needs to convert the XML data response to Model instances. Because the response is in XML, we can use an XML reader to extract the data from the server response. The XML reader uses the Activity model field definitions to determine which data to extract. With that, the SAP Gateway proxy is remarkably simple:

Ext.define('App.proxy.sap_gateway', {

    // The SAP Gateway proxy extends the built-in Ajax proxy
    extend: 'Ext.data.proxy.Ajax',

    // It requires an XML reader class to parse the response
    requires: 'Ext.data.reader.Xml',

    // Set an alias, so we can use { type : 'sap_gateway' }
    alias: 'proxy.sap_gateway',

    config: {
        // Disable use of paging params (limit, page, start)
        enablePagingParams: false,

        // Disable cache busting
        noCache: false,

        // Configure a XML reader to process the server response.
        // Each activity is contained in an 'entry' element.
        reader: {
            type: 'xml',
            record: 'entry'
        }
    }
});

Please note:

  • this proxy class is re-usable in many Model/Stores combinations. SAP backend systems provide a vast amount of ‘classes’ (in OData parlance: Entity Types): Activities, Accounts, SalesOrders, Currencies, Invoices, etc.You can re-use this proxy with any of these Entity Types.
  • the proxy is read-only: to fetch data from SAP Gateway. A read-write proxy will require additional code.

With the Activity model and Gateway Proxy in place, we can define the Activities store class:

// An Activity store is just a basic Store,
// with a preconfigured Activity model.
Ext.define('App.store.Activities', {
    extend: 'Ext.data.Store',
    config: {
        model: 'App.model.Activity'
    }
});

This completes the data part of the application. Now let’s turn to the UI. We need a List to show the results when the Store has loaded the data from the SAP Gateway.

Ext.define('App.view.ActivityList', {
    extend: 'Ext.List',
    requires: ['Ext.TitleBar'],
    config: {
        // make sure this view uses the full viewport
        fullscreen: true,

        // item template: for each activity in the list,
        // show the description
        itemTpl: '{Description}',

        // put a titlebar on top of the list
        items: [{
            xtype: 'titlebar',
            docked: 'top',
            title: 'SAP CRM Activities'
        }]
    }
});

The most important part is the itemTpl configuration. The item template determines how to format the activities properties in a list item. We’ll keep it very simple and just output the Description field.

Next, we need to tie all the classes together in an Ext.application and tell the application what to do upon launch.


// Don't let the loader generate unique urls to prevent caching
Ext.Loader.setConfig({
    disableCaching: false
});

// Configure the application
Ext.application({
    name: 'App',
    models: ['Activity'],
    views: ['ActivityList'],
    stores: ['Activities'],
    launch: function () {

        // Create an Activity store
        var activityStore = Ext.create('App.store.Activities');

        // Create an ActivityList which takes its
        // data from the Activity store
        Ext.create('App.view.ActivityList', {
            store: activityStore
        });

        // Instruct the store to load the Activities from the
        // server. After the Activities are received, the activity
        // list is updated automatically.
        activityStore.load();
    }
});

As you can see, the App requires the Activity model, the Activities store and the ActivityList. Upon launch, all the application does is create a store, create the view and load data into a store.

To complete our first SAP mobile app, we will need an index.html to contain the ST and app files.

<!DOCTYPE html>
<html>
    <head>
        <title>SAP demo</title>
        <link rel="stylesheet" href="lib/sencha-touch.css" type="text/css">
        <script type="text/javascript" src="lib/sencha-touch-debug.js"></script>
        <script type="text/javascript" src="app/app.js"></script>
    </head>
    <body>
    </body>
</html>

ST2 comes with various builds. I use the sencha-touch-debug.js version, which contains the core library and uses a dynamic script loader to fetch dependencies. I found this worked well in a development setting. However, I disabled cache busting. This prevents the loader from appending unique strings in the url when it fetches the source files. Otherwise you will loose your debugging breakpoints when you refresh your browser.

Running the app in the desktop browser

OK, time to run and test the app in our desktop browser! We’ll use an http server on our local machine to serve the files to our browser. I use the development server built into VS2010, but anything will do. Let’s assume your http server runs on port 35000 and your index.html file is served at http://localhost:35000/index.html .

Remember that we need to overcome the SOP restriction to be able to test the app in our desktop browser? Luckily Chrome provides a command line option which disables the SOP.  (Safari has the same switch but it only takes effect on a Mac, not in Windows).

So, start your Chrome browser with –disable-web-security command line option:

C:\path\to\chrome.exe –disable-web-security

Enter the url for the index.html:

http://localhost:35000/index.html

And lo and behold, we see the Activities that are fetched from the remote SAP CRM system!

SNAGHTML1989016

Let’s look at Network traffic in Chrome Developer tools. You can see all the traffic caused by the dynamic loader. Our call to the SAP Gateway system is indeed allowed by Chrome (try using Chrome without the disable-web-security option and it will throw an error).

SNAGHTML19d1211

Use the XHR option in the bottom toolbar to only show the requests to SAP Gateway.

Extending the app

Now we have this basic app running we can start adding functionality. Next to CRM Activities, the SAP Gateway demo systems offers access to other business data like CRM Accounts and Sales Orders. By adding models, stores, views and navigation we can create a more advanced SAP mobile app. Check out the Sencha Touch 2 guides to see what’s possible. Here are some examples of views and detail screens that you can build:

imageimage

imageimage

Packaging and running the app on iPhone simulator

Now our application development is completed, we are going to package it up as a native app, using the new Sencha packager which is part of ST2. We are going to create a native package for iOS. See this guide for more info.

To use the Sencha Packager you will need a Mac OS X machine with the latest XCode installed. Following the guide, you need to create separate configuration files for each type of deployment. In this tutorial we will create 2 configuration filess:

  • simulator.json: to run the app in the iPhone Simulator
  • development.json: to run the app on your own iPhone

I created the following folders structure to house the demo project. Please note that the www folder contains all the code which we developed earlier. The app folder contains a typical folder layout for a Sencha Touch app.

image

The content of the simulator.json file is:

{
  "applicationName":"SapDemo",
  "applicationId":"com.oxida.sapdemo",
  "outputPath":"~/Projects/SapDemo/simulator",
  "versionString":"1.0",
  "webAppPath":"~/Projects/SapDemo/www/",
  "configuration":"Debug",
  "platform":"iOSSimulator",
  "deviceType":"iPhone",
  "orientations": ["portrait"]
}

This configuration tells the packager to build a version of the app for Simulator and place the SapDemo.app file in the simulator folder.

We have all the files and folders in place. Let’s package and run the app. Open a Terminal window, change to your working directory and run the packager:

image

If all is well, your iPhone simulator will start and run the app:

image

This screencast shows the app in action on the iPhone simulator.

Running the app on an iPhone

Finally, we want to run our app on a real device. To run the app on a real device you need certificates and provisioning profiles, which you can request from the Apple Developers Provisioning Portal (you will need a Apple iOS developer license).

The use of certificates and profiles is,… well …, non-trivial. So if you are new to this, check out some tutorials which explain the concepts in more detail. For those of you who are already familiar with certificates and profiles, here’s a high-level reminder.

You want to… Certificate needed Provisioning profile needed
Run app in iPhone simulator none none
Run app on your own device Development certificate Development
Send app to selected group of users (e..g. beta tester) Distribution certificate Ad Hoc Distribution
Send app to the App Store Distribution certificate App Store Distribution

Now, back to the Sencha Packager!

To create a version of the app that can run on a real device, we need to set the configuration option to “Release”. The Sencha packager will by default use your distribution certificate and App Store distribution profile. For a deployment to your own device, you have to explicitly specify your developer certificate, using the certificateAlias option.

So the development.json  configuration file contains:

{
  "applicationName":"SapDemo",
  "applicationId":"com.oxida.sapdemo",
  "outputPath":"development",
  "versionString":"1.0",
  "webAppPath":"~/Projects/SapDemo/www/",
  "configuration":"Release",
  "platform":"iOS",
  "deviceType":"iPhone",
  "certificateAlias":"iPhone Developer: Your Name",
  "orientations": ["portrait"]
}

Please note: at this moment (Feb 16, 2012) this requires you to install a patch described in this forum post. This patch will be included a future update of Sencha SDK tools versions and I will update this tutorial when the patch is not required anymore.

We can now run the Sencha Packager using development.json as configuration file and build the app. This will create an app version which is code-signed with your developer certificate. As a last step, transfer the Development provisioning profile and the app file to your device. You can use this using iTunes, Organizer in xCode or (my preference) the iPhone Configuration Utility.

Now you should be able to start your app from your device. This is a screenshot from my iPhone:

IMG_0783[1]

Phew..! It’s been a long way but we have our SAP mobile app running on an iPhone!

Where to go from here

We gone through the steps to create a basic app and deliver a development version to our iPhone device. As next steps you can:

  • Further extend the app
  • Create a production build from your Javascript sources (concat source files, change the ST lib build)
  • Create an AdHoc distribution and distribute to up to 100 testers

For final deployment you can consider the Apple AppStore, Enterprise deployments or SAP Mobile App Store, which offers and sells mobile apps build by SAP and its partners.

I hope this post has inspired you to further explore the exciting opportunities of using Sencha Touch 2 to create custom mobile experiences for users of SAP systems.

Thanks for reading!

14 thoughts on “Building a SAP mobile app with Sencha Touch 2

  1. Very cool tutorial ! Thank you very much for that… One question: Is it very complex to make this proxy support all HTTP verbs (POST, UPDATE, DELETE) ? As I understand your proxy inherits from the AJAX proxy, so POST would probably work with a XML writer. Any thoughts about that ?

  2. Hi Alan,

    Glad you like the tutorial! It’s certainly possible to add the other verbs, but it will be slightly more complex. You need to build the XML payloads for the request, instead of just parsing server results. Indeed, you would need to extend XMLWriter and override the write method.

    For updates, consider the use of MERGE instead of PUT. MERGE allows partial updates (only the attributes provided in the request are updated), while PUT will reset attributes to default values if they are not provided in the request.

    If there is more interest in a full read/write proxy, I will consider adding this to the code.

  3. Fantastic Tutorial!!! I am very much intrested in Read/Write proxy as i want to develop some SAP Applications that needs CRUD Operations….

    Thanks in advance….

  4. hi istak i am also building sap application. i getting the list of PO in first screen but i want to select perticular PO and get the detail but i am not able to pass the PO no to another URL to get the details of that perticular PO can you suggest some code to pass the value from one URL to another URL .

    • Have a look at the Id element in the OData response. It contains the full url for to fetch the details. Make sure your model uses this as Id. Then you can use record.getId() to get the url value.

  5. Hey Istak, did you already made a mobile app using the Sencha Touch oData Connector for SAP? It would be nice if there was a (CRUD) tutorial, using SAP GW.

  6. Hi Istak, even if i package the app into android i have always the probleme of same origin policy
    can you please explain me how can i overcome the sop ?

    Regards,

  7. Pingback: Sencha Touch开发资料汇总 « 求索.NET

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s