Skip to Content
Product Information
Author's profile photo Jitendra Kansal

What’s new in Mobile development kit client 5.0

Updated 03 December 2020:  MDK web wording

I am happy to announce that a new release of the Mobile Development Kit is now available for all Mobile Services customers and can be downloaded on the SAP Software Center and community Download page).

SAP Mobile Services Client 5.0 is also available in Google Play Store and in Apple app store.

SAP Mobile Development Kit (MDK) extends SAP Mobile Services and Editor (SAP Web IDE/SAP Business Application Studio/Visual Studio Code extension) to provide you with a complete set of mobile application development and management tools including on-boarding, offline support, and central lifecycle management. It offers a metadata-driven approach to create native supported applications, so no experience with creating iOS or Android apps is required. Additionally, MDK now extends that capability to the Web as well.

The release includes the following:

MDK Web Runtime

We introduce MDK Web Runtime, which extends the MDK capabilities to the desktop, complementing existing MDK Mobile Clients (Android & iOS). You can now build and maintain a single app that runs natively on Mobile (Android & iOS) and as a web application (online) in the browser.  The MDK Web Runtime is available in trial and as well as productive accounts. MDK Web Runtime is an important delivery of the SAP Extension Suite and offers new Low-Code features which helps business developers to contribute in building extensions.

You can find more details in the announcement post.

Master Detail –  Flexible Cloumn Layout

There is a new page type “Master Detail Page” supporting two columns, so you can have a split screen where you can have a list and details on the same screen. This is available in both MDK Mobile & Web.

Note: Master-detail two sections floor plan are only for Tablet with both of landscape and portrait. It will automatically default to Master-only on mobile phones in both landscape and portrait modes.

Check the documentation for more details.

Side Drawer Navigation

There is a new page type “Side Drawer Navigation Page” which provides a slide out menu navigation option.

This page type can be used to provide the similar functionality to the bottom navigation page type but supports more than 5 areas within your application. This page type can only be used as the MainPage in the Application.app file.

Check the documentation for more details.

Support Header Type control & Tabs in a page

We have enhanced tabs pages to support displaying the header above the tabs so you can have a persistent header (Object, KPI, Profile).

Check the documentation for more details.

Searching across multiple sections in the same page

We have enhanced the search to support searching across multiple sections of the page. Previously, search was only available when you had a single section. You can now set multiple sections within the page to support search and each section will apply the search criteria and update the Target query options based on the input.

Password Input Type in Simple Property control

We introduced two additional Keyboard Types: Password & NumberPassword for the Simple Property Form Cell control.  Values input in Simple Property fields with these keyboard types will automatically mask the input values.

Note: NumberPassword will show only numeric keyboard.

Check the documentation for more details.

SetFocus API for Title, SimpleProperty and Note Form Cell controls

We are introducing a new SetFocus API to allow the developers to programmatically set focus to the following Form Cell field type (Title, Simple Property, Note).

Some possible use cases include:

  • Moving the input to a certain field based on the input in the current field.
  • If the field is a specific length, the app could set focus to the next field once the value has been validated or reached the specific length of the field.
  • If an error occurs on the screen, taking the user to the specific field which is in error

Check the documentation for more details.

New Page level PullDown event

We have added a new page level event so you can define an action to execute on pull down of a page. It’s up to developer what they want to do. One use case is to for an online application to refresh the list when the user pulls down on the page.

PullDown event will be executed when user swipes down from the top of the page.

//Excerpt of a page

"PullDown": {
    "OnPulledDown": "/MDK50/Actions/Service/Initialize_SampleSrvc_online.action",
    "Styles": {
        "BackgroundColor": "#b23965",
        "IndicatorColor": "#b4bfc6"
    }
},

Check the documentation for more details.

Activity indicator when loading the page

You can now display an activity indicator when page is being loaded and will be dismissed when its content is rendered.

//Excerpt of a page

"LoadingIndicator": {
    "Enabled": true,
    "Text": "Data loading please wait..."
},

Check the documentation for more details.

Busy indicator at lazy loading time

You can now display a busy indicator when the lazy loading happens. This indicator is shown below the list while the new set of data is being downloaded.

You need to set DataPaging properties of the controls.

//Excerpt of a page

"DataPaging": {
    "LoadingIndicatorText": "Loading more items, please wait...",
    "ShowLoadingIndicator": true
},

Check the documentation for more details.

New Unified OData Service Initialize Action

We have now unified the Offline OData Initialize, OData Service Create and OData Service Open actions into a single action: OData Service Initialize.

This new action can be used to initialize either offline or online OData services. You can now easily switch between offline or online by just changing the OfflineEnabled flag in .service file.

With the introduction of this new action, the following actions are now deprecated:

  • Offline ODataInitialize (Type.OfflineOData.Initialize)
  • OData ServiceCreate (Type.ODataService.Create)
  • OData ServiceOpen (Type.ODataService.Open)
//Excerpt of a page

{
    "ActionResult": {
        "_Name": "init"
    },
    "DefiningRequests": [{
        "Name": "Categories",
        "Query": "Categories"
    }],
    "OnFailure": "/MDK50/Actions/Service/InitializeOfflineFailureMessage.action",
    "OnSuccess": "/MDK50/Actions/Service/Initialize_SAM2005Online.action",
    "Service": "/MDK50/Services/ODataDemo.service",
    "_Type": "Action.Type.ODataService.Initialize"
}

Check the documentation for more details.

Support Partial Uploads for Offline OData

From an offline perspective, you can now define categories for your transactions and upload only certain transactions.

Possible use cases:

  • you can just send Status updates,
  • If a user is on a cellular network he may want to just sync partial changes to the backend
  • If a uses adds an attachment to one of the work orders and subsequently makes a status update to another workorder then the user may want to just update the workorder status for one and upload the attachment for other only when user is in a Wi-Fi network.

In an OData actions, you need to set UploadCategory in RequestOptions property of the action.

//Excerpt of a page

{
    "OnFailure": "/MDK50/Actions/PartialUpload/CreateCustomerEntityFailureMessage.action",
    "OnSuccess": "/MDK50/Actions/CloseModalPage_Complete.action",
    "Properties": {
        "FirstName": "#Control:FCCreateFirstName/#Value",
        "LastName": "#Control:FCCreateLastName/#Value"
    },
    "Target": {
        "EntitySet": "Customers",
        "Service": "/MDK50/Services/Sample.service"
    },
    "RequestOptions": {
        "UploadCategory": "Customer"
    },
    "_Type": "Action.Type.ODataService.CreateEntity"
}

Check the documentation for more details.

And in the OfflineOData Upload action, you need to provide UploadCategories property to selectively upload data.

//Excerpt of a page

{
    "Service": "/MDK50/Services/sample.service",
    "UploadCategories": [
        "Customer"
    ],
    "_Type": "Action.Type.OfflineOData.Upload",
    "ActionResult": {
        "_Name": "upload"
    },
    "OnSuccess": "/MDK50/Actions/PartialUpload/DownloadStartedMessage.action",
    "OnFailure": "/MDK50/Actions/PartialUpload/UploadFailureMessage.action"
}

Check the documentation for more details.

Added OData Deep Insert support

A deep insert is an OData POST request to create an entity that also contains inline related entities. When a deep insert is processed, the top-level entity and all its related entities are created and related together as a single operation.

MDK now supports Deep Insert in CreateEntity action. Please keep in mind that while using deep insert, you as a developer needs to take care for managing temporary data especially in case of 1:many. You need to track and manage UI to be able to input an array of items and make one call (POST) to the backend.

Note: Offline OData only supports 1-to-1 deep link relationships while online can support both 1-to-1 and 1-to-Many relationships.

Check the documentation for more details.

REST Service support with Target binding

  • We have added support for REST Service endpoints (e.g., REST API from SAP Business Hub, Public API with no authentication) by providing an additional option in the Service definition.
  • Consuming REST services is similar to how we support online OData services.
  • You need to first define REST endpoint as a destination in Mobile Services (for Mobile app) or in Cloud Foundry (for web app) and then while creating a service file, select “REST Service” option.

You can then easily bind a RestServiceTarget to an MDK control e.g., ObjectTable, ContactCell, ObjectCollection etc. and select GET method in RequestProperties. This assumes the REST service returns JSON similar to how OData requests are returned.

  • We have also introduced a new Action “RestService SendRequest Action” (equivalent of the sendRequest API) to make directly call against REST endpoint.

Example for RESTService SendRequest Action (POST method):

//MyApp/Actions/CreatePet.action
{
    "_Type": "Action.Type.RestService.SendRequest",
    "Target": {
        "Path": "/pet",
        "RequestProperties": {
            "Method": "POST",
            "Body": {
                "name": "{#Control:FCCreateCategory/#Value}"
            }
        },
        "Service": "/MDK50/Services/Pet_store.service"
    },
    "ActionResult": {
        "_Name": "create"
    },
    "OnFailure": "/MDK50/Actions/CreateEntityFailureMessage.action",
    "OnSuccess": "/MDK50/Actions/CloseModalPage_Complete.action"
}
  • We have also enhanced the sendRequest API to support setting the request body directly with:
    • JSON object which will automatically be converted to JSON string with header Content-Type: application/json, if you have not provided your own Content-Type header.
    • Binary data, you need to set the appropriate Content-Type.
    • Array for multiple part form data by setting the header Content-Type: multipart/form-data

Check the documentation for more details.

Support complex Filter and Sort criteria returns

We have enhanced the Filter returns so that you can create complex expressions in the filter to make it easier for developers to define Filter criteria on lists.

  • Rules support for filter and sorter form cell
  • Support of standard OData logical operators such as less than, greater than, not equals and others
  • Support of standard OData functions such as startswith, endswithand others
  • Support of standard ascending and descending operators for sorter form cell
  • Support for Lambda operators (any & all) for OData V4 and offline V2

Expose OData Error response body in Action result

We have enhanced the results coming back from OData servers to expose the full error response body in the action result.  In case of errors the application can parse the response and display the server returned error message. This applies to online OData service calls.

ActionResult.error now contains the following new properties

  • responseCode – this is the HTTP error code in the response returned by the OData service (e.g., #ActionResults:update/responseCode)
  • responseBody – this is the response body pay load returned by the OData service in string format. If the payload is a JSON string, you can parse it to be an JSON object for further processing. (e.g., #ActionResults:update/responseBody)

Check the documentation for more details.

Action support in Banner Message & Progress Banner

Banner Message & Progress Banner now support interactivity which can be used to execute an action or rule on click.

Expanded Font Icon Styling

We have now introduced support for styling on font-icon e.g. sap-icon://add.

//Excerpt of a page

"Styles": {
    "DetailImage": "font-icon-class",
    "StatusImage": "font-icon-class",
    "SubstatusImage": "font-icon-class"
}
////Excerpt of a Less file

.font-icon-class {
    font-size: 8;
    color: red;
}

Enhanced List Picker to support defaulting the selection if only one value exists

You can now default the list picker if there is only one value. This helps the user by not  having to click into the list to make a selection when there is only one choice.

//Excerpt of a page

{
    "AllowDefaultValueIfOneItem": true,
    "AllowEmptySelection": false,
    "AllowMultipleSelection": false,
    "Caption": "Product",
    "IsEditable": true,
    "IsVisible": true,
    "PickerItems": {
        "DisplayValue": "{Name}",
        "ReturnValue": "{ProductId}",
        "Target": {
            "EntitySet": "Products",
            "Service": "/MDK50/Services/sample.service"
        }
    },
    "PickerPrompt": "Please select one single item",
    "_Name": "FormCellListPicker0",
    "_Type": "Control.Type.FormCell.ListPicker"
},

Check the documentation for more details.

New Default Value Metadata function

We now provide you a Default Value metadata function to return a default value if a binding is evaluated to undefined, null or empty string. This will save having to write a rule every time to check if a value exists and return either the value or default.

Format:

$(DV,<binding value, rule, target path>,<default value,rule,global>)

 e.g. $(DV,{Name},’Unknown’)

  • If {Name} contains “ABC”, then it should resolve to “ABC”
  • If {Name} contains “” or null or undefined, then it should resolve to “Unknown”

Some additional examples:

$(DV,{Name},{AnotherBindingOrTargetPath})
$(DV,{Name},'/MyApp/Globals/SomeGlobalProp.global')
$(DV,{Name},'/MyApp/Rules/SomeRules.js')
$(DV,{Name},$(L,'some_localized_string_key'))

Check the documentation for more details.

Avatar and Circular Icon Support for Action Bar Item

We introduce 2 additional properties in Action Bar:

  • IconText : is used to generate a text based avatar image
  • IsIconCircular: can be used to render a circular icon.
//Excerpt of a page
{
    "IsIconCircular": true,
    "Position": "right",
    "Visible": true,
    "IconText": "MDK Developer"
}​

Check the documentation for more details.

Support scanning InApp QR Code for onboarding from Mobile Services cockpit in Cloud Foundry

MDK Mobile client now supports the In-App QR code available in Mobile services cockpit of Cloud Foundry.

ILODATA tool included in the MDK SDK

Mobile Development Kit Client package now includes the ILOData tool in the SDK Tools/ilodata folder.

The Interactive Local OData (ILOData) tool is a command line utility that lets you execute OData requests, upload and download against a local offline store (.udb file). For details please see the README.html in the folder.

 

New to MDK development?

Follow these tutorials to get your hands dirty and learn more about Mobile development kit!

Further Information:

You can learn more in documentation :

I am looking forward to your feedback and comments.

Jitendra

Assigned Tags

      17 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Naga Prakash
      Naga Prakash

      Hi Jitendra,

       

      Great blog! Can we customize the MDK App provided in App/Play Store as per the customer branding?

      Thanks,

      Naga

      Author's profile photo Jitendra Kansal
      Jitendra Kansal
      Blog Post Author

      Naga Prakash

      MDK client (SAP Mobile Services Client) available in app store is managed by SAP and mainly meant for demo and development or learning purposes.

      You can build your MDK client using MDK SDK / Cloud build service.

      Author's profile photo Naga Prakash
      Naga Prakash

      Thank you Jitendra!

      Author's profile photo Jeff Renshaw
      Jeff Renshaw

      Hi Jitendra,

      Thanks for this blog.  Some really nice new features.  A couple of questions.

      1.  When will these new features be available for the cloud build service?  I tried to do a rebuild on one app and it is still using the 4.X framework versions and the new features like the persistent object header on the tabbed page don't yet work.
      2. I have one app which I am using a tabbed page with an object header.  From that page an update can be called to approve / reject in the OData service.  The object header includes a status field that is updated when the update takes place.  I notice that the object header on the tabbed page doesn't update / redraw with the new status value after the update action occurs.  All of the pages within the tab page update with the new binding values, but not the object header.  Is this a bug?  Or is there something additional that needs to be done to make that occur?

      Thanks,

      Jeff

      Author's profile photo Jitendra Kansal
      Jitendra Kansal
      Blog Post Author

      Jeff Renshaw

      1. We are in process of updating Cloud Build service to MDK SDK 5.0 release.
      2. What is MDK version you are using?
      Author's profile photo Jeff Renshaw
      Jeff Renshaw

      Thanks for the quick response.  I look forward to the cloud build service update.

      This one is using the latest.  It is a new one I am testing these new features with.  I am developing it in Business Application Studio mobile services space.  And testing on your SAP Mobile services client with the 5.0 update.

       

      Thanks,

      Jeff

      Author's profile photo Jitendra Kansal
      Jitendra Kansal
      Blog Post Author

      Jeff Renshaw

      I would like to suggest you to open a ticket (select component MOB-MDK) to further investigate into this issue.

      Author's profile photo Jeff Renshaw
      Jeff Renshaw

      Sure.  I can do that.

       

      Thanks,

      Jeff

      Author's profile photo Lucas Uccello
      Lucas Uccello

      Good morning, we are having a problem using the Signature Capture control, it does not have the Value property, which we need to obtain the binary content of the signature. Do you know why? or where can I find information about it?

      Thank you!!!

      Author's profile photo Jitendra Kansal
      Jitendra Kansal
      Blog Post Author

      Lucas Uccello

      Can you please create a new post for your queries?

      Author's profile photo Apoorv Bhargava
      Apoorv Bhargava

      Hi Jitendra,

      thanks for the blog.

       

      most of the links which are expected to point to official documentation

      are not working

      can you please check and correct the link

      I am looking for official documentation on supported screen layout and controls

      thanks

      Apoorv

       

      Author's profile photo Jitendra Kansal
      Jitendra Kansal
      Blog Post Author

      Apoorv Bhargava

      Thanks for reporting, seems documentation links are broken, we are looking into it. Will update you once it's fixed.

      Author's profile photo Jitendra Kansal
      Jitendra Kansal
      Blog Post Author

      Apoorv Bhargava

      Fixed, you should be able to access the documentation.

      Author's profile photo Santosh Naidu1
      Santosh Naidu1

      Hello Jitendra,

      Thankyou for yet another very helpful blog.

      I am trying to create a simple MDK application and trying to make it work for both web and as mobile app. However I am only able to either make it work for mobile or web based on destination I choose in the initial creation, i.e. if I choose the destination from BTP and deploy it to both Cloud foundry and Mobile , the app perfectly works on the web but the same app fails to work on mobile when I access it from SAP mobile services client app (app store).

      If I choose the destination in the initial creation from Mobile services then it works fine on mobile but fails to work as a web app.

      I am sure I am missing a step to do here but not able to figure it out, can you please help ?

      One other thing that I noticed is , I am able to get a successful ping from the destination that I created in mobile services, how ever when I go to the "API" tab (where destination url is displayed under the QR code), if I take that destination URL and paste it in the browser I get a HTTP 400 error, not sure if that's a normal behavior.

      Author's profile photo Jitendra Kansal
      Jitendra Kansal
      Blog Post Author

      Santosh Naidu

      I see you have also opened this as a new question here, please follow the suggestions mentioned in the reply by my colleague.

       

      Author's profile photo Karan Shaheri
      Karan Shaheri

      Jitendra Kansal : Read this blog and I see that Deep Insert cannot work with 1:many relationship for offline MDK apps. We tried to do a workaround and use Changeset action to achieve this. Inside ChangeSet action, our 1st Action is "CreateEntity" action for Parent and 2nd Action in the chain is "CreateRelatedEntity" for Child. We are able to achieve alternative of deep insert with single entry in child.Now we are stuck here as to how we can pass multiple entries for child as an array in "CreateRelatedEntity" action as our child entity will have multiple rows.Can you please help us out with this scenario.  Most of the places, I have seen the examples with Child Entity having Single entry only.

      Thanks,

      Karan.

      Author's profile photo Karan Shaheri
      Karan Shaheri

      Jitendra Kansal : From the post I can see that deep insert is not possible for 1:many relationship for offline MDK apps. We have tried to do a work around to achieve 1:many relationship in offline mode using "ChangeSet action" where our 1st action in the chain is "CreateEntity" for Parent and 2nd Action in chain is "CreateRelatedEntity" for Child with its link to Parent. We were able to create Parent and Child together but with Child having only single row. Now we are stuck here and don't know how to pass multiple rows as an array to "CreateRelatedEntity" as our Child Entity can have multiple rows. Can you please help on this scenario.

      Regards,

      Karan Shaheri.