Product Information
What’s new in Mobile development kit client 4.0 SP01
I am happy to announce that a new release of the Mobile Development Kit is available for all Mobile Services customers and can be downloaded on the SAP Software Center (and also available on community Download page).
This release adds incremental functionality over the previous MDK Client 4.0 release.
Mobile Services Client is also available in Apple AppStore and Google Play Store.
SAP Mobile development kit (MDK) extends SAP Cloud Platform Mobile Services and SAP Web IDE to provide you with a complete set of mobile application development and management tools, onboarding, offline support, and central lifecycle management. It offers a metadata-driven approach to create native supported applications so no experience of creating iOS or Android apps is required.
The main focus of this release are:
-
-
- New UI control: Profile Header
- Support rendering image via HTTPS URL
- Support ClearHistory in Navigation Action
- Support Stateful OData Services
- Support OData CreateRelatedMedia action
- Support OData CreateRelatedEntity action
- Add metadata function to choose between platform specific values
- Support sending authenticated GET and POST request to SAP Cloud Platform Mobile Services
- Support Offline OData Function Imports
- Support multiple formats with DateFormat and TimeFormat
- Support Image Collection in Sectioned Table on Android
-
New UI control: Profile Header
We now support Profile Header control conforming Fiori for iOS & Android guideline.
Profile header helps the user recognize and learn more about a person.
[Updated 10.01.2020] : Profile Header control is now available under available control in Section page in MDK page editor
"Sections":[
{
"ProfileHeader":{
"ActivityItems":[
{
"ActivityType":"Phone",
"ActivityValue":"{PhoneNumber}"
},
{
"ActivityType":"VideoCall",
"ActivityValue":"{PhoneNumber}"
},
{
"ActivityType":"Email",
"ActivityValue":"{EmailAddress}"
},
{
"ActivityType":"Detail",
"ActivityValue":"This is an alert"
}
],
"Description":"{CustomerId}",
"DetailImage":"/DemoProj/Images/contact-cell.png",
"DetailImageIsCircular":true,
"Headline":"{{#Property:FirstName}} {{#Property:LastName}}",
"Styles":{
"BackgroundColor":"ProfileHeaderBackgroundColor",
"Description":"ProfileHeaderDescription",
"Headline":"ProfileHeaderHeadline",
"Subheadline":"ProfileHeaderSubheadline"
},
"Subheadline":"{City}"
},
"Visible":true,
"_Name":"Control0",
"_Type":"Section.Type.ProfileHeader"
}
],
"_Name":"SectionedTable",
"_Type":"Control.Type.SectionedTable"
}
Check the documentation for more details.
Support rendering image via HTTPS URL
We now support rendering image via https URL for values in image properties e.g. DetailImage in ContactCell.
Control | Attribute in control | Documentation Reference |
ObjectHeader | DetailImage, StatusImage, SubstatusImage | Reference |
ProfileHeader | DetailImage | Reference |
ObjectCell | DetailImage, Icons, StatusImage, SubstatusImage | Reference |
ContactCell | DetailImage | Reference |
GridRowItem | Image Row Item | |
ImageCell | Image | Reference |
Here in ProfileHeader control
"DetailImage": "https://icon-library.net/images/0234605a9c_92936.png",
Support ClearHistory in Navigation Action
We now have introduced a new property “ClearHistory” in Navigation Action to clear the history stack. It accepts a Boolean value. Default value is false.
If set to true, the navigation back-stack should be cleared and after the navigation action is completed the back button should not be visible anymore in the target page (because the backstack is now empty).
{
"ClearHistory":true,
"PageToOpen":"/DemoProj/Pages/Customers/Customers_List.page",
"_Type":"Action.Type.Navigation"
}
Check the documentation for more details.
Support Stateful OData Services
You should be now able to handle and store the stateful services session so that session info can be easily retrieved and can be used.
A new property is available in Service > OnlineOptions > ServiceOptions > StatefulService (type: boolean)
If set to true, the session information returned from the CallFunction API is automatically stored in #Application/#ClientData/#Property:Session/#Property:[SessionPropertyName] for subsequent use in actions or rules.
Example:
#Application/#ClientData/#Property:Session/#Property:SessionID
Check the documentation (Online Service Options) for more details.
Support OData CreateRelatedMedia action
Create Related Media action is used to create a media enity(an OData EntityType with HasStream=”true” attribute). The new media entity is linked to its parent entity(an entity has a navigation property linking to the new media entity)
e.g. “Image” EntityType is a Media Entity and it has an associated media stream:
<EntityType Name="Image" HasStream="true">
<Key>
<PropertyRef Name="id"/>
</Key>
<Property Name="id" Type="Edm.Int64" Nullable="false"/>
<Property Name="label" Type="Edm.String" Nullable="true"/>
<Property Name="created" Type="Edm.Date" Nullable="true"/>
<Property Name="updated" Type="Edm.Date" Nullable="true"/>
<NavigationProperty Name="artist" Type="Self.Artist"/>
</EntityType>
Parent EntityType “Artist” has a navigation property linking to “Image”:
<EntityType Name="Artist">
<Key>
<PropertyRef Name="id"/>
</Key>
<Property Name="id" Type="Edm.Int64" Nullable="false"/>
<Property Name="firstName" Type="Edm.String" Nullable="false"/>
<Property Name="lastName" Type="Edm.String" Nullable="false"/>
<Property Name="dateOfBirth" Type="Edm.Date" Nullable="true"/>
<NavigationProperty Name="images" Type="Collection(Self.Image)"/>
</EntityType>
{
"_Type": "Action.Type.ODataService.CreateRelatedMedia",
"Target" : {
"EntitySet" : "Images",
"Service" : "/AssetWorkManager/Services/Amw.service"
},
"Properties" : {
"ClassName": "#CurrentPage/#Control:ClassName/#Value",
"ClassType": "#CurrentPage/#Control:ClassType/#Value",
"ObjectKey": "#CurrentPage/#Control:ObjectKey/#Value",
"FileName": "#CurrentPage/#Control:FileName/#Value"
},
"ParentLink": {
"Property": "images",
"Target": {
"EntitySet": "Artists",
"ReadLink": "{@odata.readLink}"
}
},
"Headers" : {
"slug" : {
"ClassName": "#CurrentPage/#Control:ClassName/#Value",
"ClassType": "#CurrentPage/#Control:ClassType/#Value",
"ObjectKey": "#CurrentPage/#Control:ObjectKey/#Value",
"FileName": "#CurrentPage/#Control:FileName/#Value"
}
},
"IsOnlineRequest": true,
"Media":"#CurrentPage/#Control:Attachment/#Value",
"OnSuccess" : "/AssetWorkManager/Actions/ODataCreateEntitySuccessMessage.action",
"OnFailure": "/AssetWorkManager/Actions/ODataCreateEntityFailureMessage.action"
}
Note:
CreateMedia action: creates a new media entity against its own entity set. This action does not support linking to another existing entity set.
CreateRelatedMedia action creates the new media entity against the navigation property of an existing entity with which the relationship is to be established.
Check the documentation for more details.
Support OData CreateRelatedEntity action
CreateRelatedEntity action is used to create an entity in the target system, related to a parent entity via a parent navigation property.
{
"_Type": "Action.Type.ODataService.CreateRelatedEntity",
"Target": {
"EntitySet": "SalesOrderHeaders",
"Service": "/MDKDevApp/Services/OnlineSampleService.service"
},
"Properties": {
"SalesOrderId": "/MDKDevApp/Rules/GetSalesOrderId.js"
},
"ParentLink": {
"Property": "SalesOrders",
"Target": {
"EntitySet": "Customers",
"ReadLink": "{@odata.readLink}"
}
},
"ActionResult": {
"_Name": "OData"
},
"OnSuccess": "/MDKDevApp/Actions/Messages/Success.action",
"OnFailure": "/MDKDevApp/Actions/Messages/Failure.action"
}
Note:
CreateEntity (with CreateLinks) action: creates the new entity against its own entity set. The entity is then linked or bound to an existing entity with which the relationship is to be established.
CreateRelatedEntity action creates the new entity against the navigation property of an existing entity with which the relationship is to be established.
Check the documentation for more details.
Add metadata function to choose between platform specific values
You can now format things like date, time, currency etc that returns the appropriate value based on the runtime platform (iOS or Android).
$(PLT, <iOS>, <Android>)
If the platform is iOS the first parameter is returned.
If the platform is Android the second parameter is returned
If the parameter is blank then the property where the function is evaluated should behave as if the property is not specified.
It supports the following value types:
- $(PLT, ‘ABC’, true) <- in iOS return string ‘ABC’, in Android return boolean true
- $(PLT, 123.4, ‘false’) <- in iOS return number 123.4, in Android return a string ‘false’
- $(PLT, ‘123.4’, null) <- in iOS return string ‘123.4’, in Android return a null
- $(PLT, {MyProperty}, {\{#SomeTargetPath/#Property:SomeProperty}}) <- in iOS return string value of MyProperty binding, in Android return value of #SomeTargetPath/#Property:SomeProperty
Check the documentation for more details.
Support sending authenticated GET and POST request to SAP Cloud Platform Mobile Services
We already supported to get the deviceID & UserID for the registered user. Now, you can also get the SAP Cloud Platform Mobile Services AppID and server endpoint.
Once you get the Mobile Services URL and AppID, you can construct a full URL to access Mobile Services REST API/destinations via clientAPI
sendMobileServiceRequest(path: string, params?: any): Promise<any>;
/**
* Describe this function...
* @param {IClientAPI} context
*/
export default function DoSomePostRequest(context) {
debugger;
let userid = context.evaluateTargetPath('#Control:User/#Value');
let appId = context.evaluateTargetPath('#Application/#ClientData/#Property:MobileServiceAppId');
let uri = '/my/rest/api/v1/doSomething';
let body = {
"FirstName": "John",
"LastName": "Doe",
"Address": {
"Street": "Some Street",
"City": "AB",
"Country": "CD"
},
"UserId": userid
};
let header = {
"x-smp-appid": appId,
"Content-Type": "application/json"
};
let params = {
'method': 'POST',
'header': header,
'body': JSON.stringify(body)
};
return context.sendMobileServiceRequest(uri, params).then((result)=>{
console.log(Result: ${result});
console.log(Result Content: ${result.content});
console.log(Result statusCode: ${result.statusCode});
if (result && result.statusCode === 201 && result.content) {
//DO WHAT YOU NEED WITH THE result.content here e.g.
let data = JSON.parse({ "result": ${result.content.toString()}});
context.getPageProxy().setActionBinding(data);
return context.executeAction("/MyApp/Actions/ShowResult.action");
} else if (result) {
console.log(Failed Result: ${result.statusCode});
}
else {
console.log(Failed Result: ${result.content});
}
});
}
Check the documentation for more details.
Support Offline OData Function Imports
CallFunction action
- supports POST, PUT, PATCH and DELETE. method on OData v2
- Will always immediately return empty result because the request is not truly send until you sync to the server
- Need to sync to backend to commit the transaction
- Function Import requests cannot/will not be merged with other requests.
- In V2, function imports can only use primitive types as parameters.
Function Import requests cannot/will not be merged with other requests. They can, however, be automatically bundled into the same ‘transaction’ if the appropriate TransactionID header is used.
In V2, function imports can only use primitive types as parameters.
{
"OnSuccess":"/DemoSampleApp/Actions/UpdateStatusSuccess.action",
"Target":{
"Function":{
"Name":"UpdateSalesOrderStatus",
"Parameters":{
"id":"{SalesOrderId}",
"newStatus":"R"
}
},
"Service":"/DemoSampleApp/Services/SampleServiceV2.service"
},
"_Type":"Action.Type.ODataService.CallFunction"
}
Check the documentation for more details.
Support multiple formats with DateFormat and TimeFormat
We have now added new customOptions parameter for formatDate, formatDateTime, formatTime function via IClientAPI to display date and time in the specified format. Supported format style: short, medium, long, full. Default for date is medium. Default for time is short (MDK default). e.g. { format: ‘long’ }
// Display in date format
formatDate(date: Date, customLocale?: string, customTimeZone?: string, customOptions?: any): string;
// Display in datetime format
formatDatetime(date: Date, customLocale?: string, customTimeZone?: string, customOptions?: any): string;
// Display in time format
formatTime(date: Date, customLocale?: string, customTimeZone?: string, customOptions?: any): string;
You can also use it via Internationalized and Localized Data.
e.g.
- $(D,’2017-12-25T11:40:00Z’,null,’Europe/Berlin’,{format:’long’})
- $(DT,’2017-12-25T11:40:00Z’,null,’Europe/Berlin’,{format:’long’})
- $(T,’2017-12-25T11:40:00Z’,null,’Europe/Berlin’,{format:’long’})
Support Image Collection in Sectioned Table on Android
Image Collection is now fully supported in Android.
New to MDK development?
Follow these tutorials
- Get started with MDK
- Enhance your MDK app with some advanced functionalities
- Level Up with the Mobile Development Kit
- Brand Your Customized App with Mobile Development Kit SDK
Many thanks to our dev colleagues to share inputs in writing up this post.
Regards
Jitendra Kansal
Product Management, SAP Cloud Platform Mobile Services
SAP SE
Very helpful blog.
Hi Jitendra,
In mdk matadata, In Web IDE I am using form page in that I need password format like **** when user fill anything in that field.Is there any control so that I can use this. Could you please help me on this?
Thanks
Sani Kali
Hello Jitendra Kansal,
we are facing same issue, Do you know if it is planned to address this requierement on following quarters?
Also Do you think that can be feasible if we build this change via CSS or nativescript extension.
Best Regards
Felix
Felix Dia Morales
In MDK client 5.0 release, we have introduced additional keyboard types for Simple Property Form Cell control to mask the input values.
Thanx for your time.
Actually I have designed login page in that I have added two fields i.e., User Id and Password. but in password field I don’t want password(abcdef) should be visible to us. Can we display password like **** in password field instead of abcdef.
Please see below screenshot for reference.
Thanks & Regards,
Sani Kali.
Please have a look at this answer by my colleague.
sani kali
In MDK client 5.0 release, we have introduced additional keyboard types for Simple Property Form Cell control to mask the input values.
Hi Jitendra,
Thanks for you blog. We were looking for a method like sendMobileServiceRequest.
We are able to call this method with http method "POST" however we received 403 response from backend. On debugging, I find out that it give error saying "CSRF Token validation failed". Could you please?
Thanks
Arvind
Arvind looks like you are missing X-CSRF-Token required by your backend.
You should update your code to:
to the same backend resource.
Hi Ming,
I am having same issue as Arvind, I am getting error 403: CSRF Token Validation Failed.
I tried to fetch the x-csrf-token by doing a GET. However, the returning parameter do not have headers that can retrieve the CSRF token. Any idea?
Basically I am doing a get $metadata, and it retrieved successfully but I cannot find the Csrf token to do a POST.
cc Jitendra Kansal , please advise.
Thanks