Skip to Content
Technical Articles

Creating an Offline CRUD hybrid mobile app in SAP Web IDE Full-Stack with Hybrid Application Toolkit

Updated 4 January 2019: Added a section providing hints for troubleshooting.

Important note: although hybrid apps are a valid way to implement offline apps, we strongly recommend using more modern mobile technologies instead. 

When you start developing a new mobile app, we strongly recommend that you consider developing this with either MDK (Mobile Development Kit) for cross platform applications, or our native SDKs (SAP Cloud Platform SDK for iOS or SAP Cloud Platform SDK for Android).

A new milestone and a bit of background

As a Product Owner, it is always good to see your product reach a new milestone. Last week, you’ve seen the announcement of Hybrid Application Toolkit release 1805 in Britt’s blog. In this release, we’ve made some fundamental changes in the way we build hybrid apps in the cloud from SAP Web IDE.

It is not my intention to repeat Britt’s blog; but let me just highlight the most important part of this release: Developers have a lot more control on what is packaged into a hybrid app. This opens the door to more possibilities and allows developers to more easily resolve challenges by themselves.

One of the hot topics we did not completely cover in this release is the ability to create offline apps. Many developers have been asking for this. In December 2017, I’ve announced our plans to ‘end-of-maintenance’ the HAT local add-on. We have provided you one offline specific template in SAP Web IDE (with that I mean the Eclipse Orion based version) that could only be used in conjunction with the HAT local add-on. The template is not available in SAP Web IDE Full-Stack. Meanwhile, our colleagues from SAP Web IDE have shut down the old SAP Web IDE and you are advised to migrate projects to the Full-Stack version. So how do you build offline hybrid apps in SAP Web IDE Full-Stack, if we don’t provide the template anymore?

Before answering, let’s look back into the history of this toolkit. When we started, we had no cloud build feature. Instead, we were relying on the locally installed tools for developing Cordova apps. There were templates in Web IDE that kept evolving over time. At some point we’ve decided to grab a snapshot of a UI5 Master Detail template and adapt it to support offline. This template was shipped with HAT, the Web IDE plugin. We then tried to keep up with changes in the original template. At some point, the original template was replaced with a Fiori Master-Detail Application template. We did not further update our offline template, unless really needed.

Although we could have created new mobile specific templates in HAT, we actually wanted the opposite: any template should by default support mobile; hence there should not be mobile variants at all. The functionality we’ve provided last year was actually doing this. When the HAT plugin in Web IDE was active, a newly created project was automatically enabled for mobile. We were adding some magic in the background to make this happen. However, although we’ve tried to make it easier, in reality things got a lot more difficult (especially troubleshooting).

We do not plan to provide you an offline template in SAP Web IDE Full-Stack. The main reason is that every app is unique and requires specific customization around the topic of offline. It is very difficult to provide you this as part of a one-fits-all template. Instead, we will give you guidelines on how to implement offline functionality in your app and provide you with an example below.

Creating an offline app based on the Fiori CRUD Master-Detail template

Prerequisites

Before we start creating the example app, let us first ensure we can access the Mobile Service Sample Service from SAP Web IDE. In your SAP Cloud Platform cockpit, go to Connectivity > Destinations and create a new destination as shown below. Make sure you add the additional properties as indicated. The url is not completely visible is the screenshot. Please enter https://hcpms-<your account number>trial.hanatrial.ondemand.com/SampleServices/ESPM.svc. I am using a trial account for this blog post. You’ll obviously have to change the url for productive environments.

After saving the destination settings, it can take up to a few minutes to have the new destination active.

Now let’s start creating the app from scratch in SAP Web IDE Full-Stack. You can find this version of SAP Web IDE in your SAP Cloud Platform cockpit’s services list:

Although not required at this point, please make sure you have activated Hybrid Application Toolkit. Once you are in SAP Web IDE Full-Stack, go to the preferences and ensure the feature Hybrid App Toolkit is activated. Don’t forget to save your selection and reload SAP Web IDE.

When using a trial account, you will use the Cloud Build feature based on Mobile Services. Customers who access a productive environment could see the following in the Hybrid Application Toolkit preferences (depending on your subscription):

If you don’t see the Cloud Build Service mentioned in the preference, you will be using Mobile Services by default. If you do see the radio buttons, please ensure the radio button regarding Cloud Build Service is enabled for Mobile Services (not the deprecated one for SAP Fiori).

Creating a new project from a template

In SAP Web IDE, please select File > New > Project from Template. To avoid possible issues with the latest innovation version, I have selected a CRUD Master-Detail template based on SAPUI5 version 1.52. Feel free to use a different version.

In the next step, fill in the details.

In this example I am using the Mobile Service Sample Service to consume OData from a Service URL. We have exposed this service to SAP Web IDE through the destination we have created earlier.

In the Template Customization step, I have selected the following:

Once finished, you can run the application from SAP Web IDE in your web browser. It will show you the data from the data source (read) and you can create new entries (create), change it (update) and remove entries (delete). Also referred to as “CRUD”.

Mobile enable the project

Right-click on your project to bring up the context menu and select Mobile > Enable as Hybrid Mobile Project.

This step will add a ‘mobile’ folder to your project, containing some source files only relevant for when your app runs on a device or emulator (as Packaged app, or Developer Companion app).

Take note that during the cloud build process, the contents of the webapp folder and the mobile folder will be merged into the www folder of your Cordova project. The index.html file in the mobile folder will replace the one in your webapp project (if your project has one).

We’ve decided to use this approach, so you can still deploy the webapp to SAP Cloud Platform.

Creating a hybrid app from this project

You can create a Packaged app based on this project by selecting in the context menu: Mobile > Build Packaged App.

In the first step of the build wizard, you can change the app’s name as visible on your device’s home page. You can also select an app icon and images for the splash screen.

In the next step, you indicate for which platform you want to build your app. You’ll need to provide a valid the signing profile. For Android devices, you can simply generate one on our service. The provisioning profile for iOS is a bit more tricky. I recommend creating a wildcard App ID on developer.apple.com and include that in the profile which allows you to install the application on your device. Note that this is wildcard App ID is only for development; not for production. You’ll then need to export your certificate and provisioning profile and import it here.

Currently, we only have two UI5 versions to select from. We will gradually add more versions.

At this point you can hit the Build button. Once the Cloud Build Service is finished generating your app, a QR code and hyperlink will be displayed, so you can download the app onto your device.

During this build process, Hybrid Application Toolkit will automatically create a new application on Mobile Service, and also create the related Cloud Platform destination for you.

Adding Cordova plugins (optional)

Although not related to the offline topic, I have received several queries on how to add Cordova plugins. So let’s quickly discuss this.

In case you want to make use of one or more of the more than 2300 publicly available Cordova plugins in your project, open the context menu and choose Mobile > Select Cordova plugins. You can browse and search for plugins. Once you are done, make sure to save your selection.

When you trigger a new build, the plugins will automatically be added in your Cordova app.

Note that there is a tab called “Default (34)”, which does not allow you to make a selection. It merely lists down the plugins we add to your app by default. You’ll notice most of the Kapsel plugins are listed there. You don’t need to select them. They will be part of your app by default.

Adding the offline capabilities

Before we discuss the offline capabilities, I want to highlight one thing regarding Developer Companion: since this type of app is typically an online app, we cannot use Developer Companion for developing offline apps. Offline will only work for Packaged Apps.

Users who have already created offline apps before using our cloud build service are probably familiar with the way to add the Kapsel Offline OData plugin to the project. This is actually triggered by adding a “sap.mobile” section that defines ‘stores’ in the project’s manifest.json. We have kept this in the new delivery, so that existing projects can more easily transition. The content of this section is actually not important anymore. What matters is that this section is there. Before the HAT 1805 release, the content was used in the build process. As long as you specify the bare minimum, you are fine:

	},
	"sap.mobile": {
		"definingRequests": {},
		"stores": [
		]

As a result, your Packaged app built with Cloud Build Service includes the SAP Kapsel Offline OData plugin. Now we need to add some more code to make use of this.

Initializing the offline store

The file mobile/hybrid/sap-mobile-hybrid.js contains most of the bootstrap code for the hybrid app. You are free to make changes here. We are going to add a function to create and open the offline store that will be used to store the data relevant for the app on the device.

    openStore: function() {
        console.log("In openStore");
        jQuery.sap.require("sap.ui.thirdparty.datajs");  //Required when using SAPUI5 and the Kapsel Offline Store
        var properties = {
            "name": "store_mainService",
            "host": sap.hybrid.kapsel.appContext.registrationContext.serverHost,
            "port": sap.hybrid.kapsel.appContext.registrationContext.serverPort,
            "https": sap.hybrid.kapsel.appContext.registrationContext.https,
            "serviceRoot": fiori_client_appConfig.appID + "_" + mobile_appRoutes[0].destination,

		"definingRequests": {
			"supplierset": "/Suppliers?$expand=Products"
		}
        };
    
        store = sap.OData.createOfflineStore(properties);
    
        var openStoreSuccessCallback = function() {
            console.log("In openStoreSuccessCallback");
            sap.OData.applyHttpClient();  //Offline OData calls can now be made against datajs.
            sap.hybrid.startApp();
        }
    
        var openStoreErrorCallback = function(error) {
            console.log("In openStoreErrorCallback");
            alert("An error occurred" + JSON.stringify(error));
        }
    
        store.open(openStoreSuccessCallback, openStoreErrorCallback);
    },  

An important piece to mention here is the serviceRoot specified in the properties. The serviceRoot is basically the location where the offline store will fetch its data, indirectly through Mobile Service. In this particular example I am using the Mobile Service Sample Service; but I could easily change this to use a different destination. The Cloud Platform destination used here was automatically generated by HAT, after triggering the build previously. Also note that the above code assumes one single data source and hence, one single offline store. If your app needs to consume data from multiple sources, you’ll need to open multiple offline stores here.

In the same file, the appLogon function needs to be adjusted a little bit. Once the logon is done, we call the newly added openStore function, instead of the startApp function.

		if ('serverHost' in context && 'serverPort' in context && 'https' in context) {
			// start SCPms logon
			sap.hybrid.kapsel.doLogonInit(context, appConfig.appID, sap.hybrid.openStore);

Modification of the datasource uri in the manifest file is no longer required. You can use the same project for running it as online as well as standalone offline app. For existing projects that were mobile enabled, it is advised to remove the ‘mobile’ folder from the project (you might want to save a copy) and re-enable for mobile. New projects will automatically get the latest code needed when the project is enabled for mobile.

Read-only offline app.

Trigger a new cloud build and download your app on your device. After the authentication screen and passcode screen, the screen will go blank for a while. We should actually show something here, so the end-user knows what is happening. This is an improvement to be added later. At this point, the offline store is being synchronised with the backend database. Once this is done, the UI will show up and display the data (this can take around 15 seconds).

You can put your device into airplane mode and continue accessing the data.

Congrats! You’ve built an offline app.

It is nice to be able to Read data when offline, but how about Create, Update and Delete?

The application template is actually already allowing modifications, removal and adding new data entries. But how do we handle this when the device is not connected to the network? The data is simply stored in the on-device offline store. When network connectivity returns, we can synchronise the changes between backend database and on-device store.

To get the latest changes from the backend, we use the refresh function. To upload locally made changes to the backend, we use the flush function.

For the refresh, the most obvious way of implementing this, is as part of the pull-to-refresh. The flush should be triggered once the network connection is back. But for the sake of this demo and making it easier to test, I’ll just add two buttons to the footer bar: a Refresh and a Flush button.

Let’s open the file webapp/view/Master.view.xml and add the following buttons in the customFooterContent.

	<semantic:customFooterContent>
	    <Button text="Refresh" width="80px" id="__button1" press="onRefreshButton"/>
	    <Button text="Flush" width="70px" id="__button0" press="onFlushButton"/>
	</semantic:customFooterContent>

Now open the file webapp/controller/Master.controller.js and add the following code for handling the button press:

		onRefreshButton: function() {
			if (typeof sap.hybrid !== 'undefined') {
				sap.hybrid.refreshStore();
			}
		},
		
		onFlushButton: function() {
			if (typeof sap.hybrid !== 'undefined') {
				sap.hybrid.flushStore();
			}
		},

I have added the type check to make sure these calls are only done for a hybrid app. The web app should not call these functions.

We will add the functions called in the file mobile/hybrid/sap-mobile-hybrid.js

	refreshStore: function() {
		console.log("Offline events: refreshStore");
		if (!store) {
			console.log("The store must be open before it can be refreshed");
			return;
		}
		store.refresh(sap.hybrid.refreshStoreCallback, sap.hybrid.errorCallback, null, sap.hybrid.progressCallback);
	},

	refreshStoreCallback: function() {
		console.log("Offline events: refreshStoreCallback");
	},

	flushStore: function() {
		console.log("Offline events: flushStore");
		if (!store) {
			console.log("The store must be open before it can be flushed");
			return;
		}
		store.flush(sap.hybrid.flushStoreCallback, sap.hybrid.errorCallback, null, sap.hybrid.progressCallback);
	},

	flushStoreCallback: function() {
		console.log("Offline events: flushStoreCallback");
	},

	errorCallback: function(error) {
		console.log("Offline events: errorCallback");
		alert("An error occurred: " + JSON.stringify(error));
	},

	progressCallback: function(progressStatus) {
		// console.log("Offline events: progressCallback");

		var status = progressStatus.progressState;
		var lead = "unknown";
		if (status === sap.OfflineStore.ProgressState.STORE_DOWNLOADING) {
			lead = "Downloading ";
		} else if (status === sap.OfflineStore.ProgressState.REFRESH) {
			lead = "Refreshing ";
		} else if (status === sap.OfflineStore.ProgressState.FLUSH_REQUEST_QUEUE) {
			lead = "Flushing ";
		} else if (status === sap.OfflineStore.ProgressState.DONE) {
			lead = "Complete ";
		} else {
			alert("Unknown status in progressCallback");
		}
		console.log(lead + "Sent: " + progressStatus.bytesSent + "  Received: " + progressStatus.bytesRecv + "   File Size: " +
			progressStatus.fileSize );
	},

The refresh and flush functions are asynchronous and will take some time. For demo purposes, I’ve kept the implementation rather simple and added some console logging to have an idea of what is going on. For your enterprise mobile applications, you should implement a way to inform the user about progress and update the UI when needed.

After saving all your code changes, please trigger another cloud build. The result will be an app that allows you to work with your data in online, as well as offline mode. You trigger a refresh to update the on-device store. You can flush the changes made in the on-device store to the data service.

What about data conflicts?

There is one important aspect that I will not discuss in this blog: data conflicts. How do you handle errors when data on the service has changed, while your device was offline, and your user also made changes on the same data?

I think this topic is worth a separate blog post.

Conclusion

With this blog post I’ve shown you how to create an offline app in SAP Web IDE Full-Stack. The example code provided is very basic. There is surely room for improvement to get this to production level apps. My goal was to show you the basics here, to get you started quickly. I hope this blog post is useful to you and I encourage you to try it out yourself. You can easily get started using our trial landscape.

Our online documentation is here.

Troubleshooting

After providing support to several users, I’m adding this section to help you in resolving issues you might be facing.

  • You can test the URL used for OData access in the Mobile Service admin cockpit. Select the application and go to Connectivity. Make sure you can Ping the destination. Use the OData application destination test (the icon on the left side of Ping). Specify the relative path as used by your app and click next. You should be able to view data available in the service. If this is not working, then your app will not be able to retrieve data either. Resolve this first before continuing to debug your app.
  • When the offline store is initialised on your device, it will be based on the serviceRoot provided. If you want to make changes to the serviceRoot, you have to delete the existing offline store from your device. Otherwise it will still exist when you restart the app, using the serviceRoot it was initialised with. On iOS, you can remove the store by deleting the app. On Android, removing the app is not sufficient. You also need to clear the app data and cache.
  • A common issue for several users is that the initialisation of the offline store fails. In the example code I am using an alert to indicate this. In case of doubts, you can put a breakpoint on the success callback and error callback to see what is happening.
  • In the file mobile/index.html there is some code to adjust your app’s XMLHttpRequests to use URLs that work locally. Please check whether the URL used matches with the serviceRoot you’ve defined. If the path doesn’t match, the app will not use the on-device store.
  • The offline store communicates with Mobile Service over a dedicated channel called Mobilink. You won’t be seeing data exchange in the (web) app’s logs, as this is handled via native code. Using the Trace functionality in Mobile Service admin cockpit (see Analytics), you will be able to generate a HAR file and get detailed information about the communication between the client app and Mobile Service AND ALSO between Mobile Service and your backend. Check for error messages in the traces to understand why there are failures happening.

Reporting issues

Although I have verified and tested the above flow several times and received confirmation from several users that this works, the results for you might be different. This might be due to interruptions in service availability or changes on the various systems involved. Also take note that I have not tested other scenarios (e.g. on-premise, with Cloud Connector) myself.

For users who are trying to add offline capability to their own app and it fails: please try reproducing exactly the same as described above. Once you have this working, it will be a good reference for your  own application. Adding offline capabilities to a hybrid app is not trivial.

In case you are running into issues, please raise a (BCP) ticket for component CA-WDE-MOB. You can also comment down below, but take note that I will not be monitoring this blog very frequently.

Also, please check my latest blog post “What’s new with Hybrid Application Toolkit in 2019” for the latest updates, tips and tricks, ways to resolve issues.

If you found this posting useful, please let me know by hitting the like button.

Thank you!

289 Comments
You must be Logged on to comment or reply to a post.
  • Hi Ludo,

    I am trying to add my gateway box to SCPms via cloud connector. I am able to register the backend via cloud connector. I have a couple of question here.

    1. While registering backend via HCC on SCPms what would be the the SSO mechanism.
    2. While creating mobile destination in SCPms with proxy type Cloud connector the url would be virtual IP and port that we have created in HCC while adding gateway. right?
    3. On testing destination always its give me below message.

    4. Then i am using this as a destination to SCP with appending the service url i.e; “/sap/opu/odata/sap/service_name”

    5. Here in the user i tried adding backend user and Pxxxxxxx user also every time i am getting 403 forbidden error.

     

    Am i missing anything or any roles.Please suggest me the solution, i am stuck here for a week.

     

     

    Regards

    Shadan

  • hi ludo,

     

    i followed you steps , but  while assessing the mobile service , i am getting forbidden error 403. Actually i was able to replicate your application , Now i am trying with my own service .Are there any user roles or permission that has to be provide to assess the mobile service in destinations.

    • If you were able to replicate my app, then you have all the user roles and permissions you need.

      It is more likely that you have not configured the destination properly. You can test the connection from the Mobile Services admin cockpit. If the ‘ping’ works and you are able to get some (meta)data, then this part is fine.

      If this doesn’t help, you have two features in Mobile Services that can help identify the problem. In the Analytics tab, check the logs. If this doesn’t tell you enough, you can use the trace function to record the network activity related to your app. Take note that when debugging your app through Chrome (Android) or Safari (iOS), you will not be able to see the exchange done over mobilink, which is the protocol used by the offline store. But you can see it in the traces.

      Hope this helps.

  • Hi ludo

    the steps that i follwed where

    1. first i created a service in Destination with the backend system. I am passing just the bankend system general url .(everything is fine here).
    2. the i created a mobile destination using this cloud destination (ping is succesfull here).
    3. while accessing the api for destination of that particular application i am getting
      HTTP Status 403 – Neither Application connection id nor Application id is provided.

      4. then i am trying to use this mobile service in my cloud destination there i am getting 403 forbidden error.

    Questions:

    1. should i pass full service url in the cloud destination including my oadta service name?

    2.while creating the mobile destination is  there a requirement of header that should be passed ?.

     

     

    • I suspect there is a problem with the destination you’ve configured. Although you can ping it successfully, you are getting a 403 at step 3. Try to resolve this first, before trying to consume it through mobile services.

       

      • Can youhelp with the steps if I create using my own odata service.

        If I create mobile destination and use it in for webide destination , I don’t get the link between the application I’d  and destination before application is even created . I am new to this . Am I missing some step?

         

         

  • Hi,

    How did you manage to put a breakpoint in the sap-mobile-hybrid.js ? If I put a breakpoint there nothing happens because my code doesn’t reach it.

    • Hi Tyler,

      When you initially start the app, you will probably not be able to trigger a breakpoint as the code execution has already happened before you are able to do so. Reloading the web app in Safari (or Chrome in case of Android) will allow you to break in this code.

      Regards,
      Ludo

  • Hi Ludo,

     

    Great blog ! I was able to replicate your example. In a separate app I was also able to use my own OData (using my on premise DEV system). I have a question:

    When I am offline, let’s say I want to validate one input field , for example customer. How can I do a look up to a master table for validation? Should the master table be part of the OData?  Do you have any suggestions on how to do a look up?

    Louis

     

    • Hi Luis,

      How would you do this for an online app? If you are using an OData source for the master table look up, then it makes sense to offline that table as well. The way to implement it is just like when your source is online.

      You can create multiple offline stores if needed.

      Cheers,
      Ludo

       

    • Hi louis

      Can you help me with the steps if I am consuming my odata services.

      Actually the steps before consuming mobile destination in web ide.that ludo has described.

        • Hi Luis ,

          • I created cloud destination for webIde basic application .
          • I created a simple list application where i binded the data from the service.
          • And i added a button on the screen on click of which i can add random data to the list  , through create service.
          • This application is fully functional in chrome.  

          Now for the mobile application part .

          1. I enabled the hybrid toolkit feature and , i right clicked on the application and enabled for the application .
          2. Then i build the companion application.
          3. Mobile folder got generated in my application.
          4. I went to mobile services and check if my application is generated . There my application was generated and connection was generated .
          5. Now i tried to open the application in my mobile .
          6. Application gets opened but i don’t receive the data .
          7. when i try to create the data it gets created .In the error log it shows application is in offline mode.

          If I create a app and add service to that , and try to use that in Scp destination. it gives 443 forbidden error .

          If i use the sample mobile service as mentioned by ludo ,read service on offline works fine .

          Can you please guide me through end to end steps . I am working on hybrid application for first time.

           

          Thanks i advance .

    • Hi Luis,

      I was also able to replicate the example given by Ludo. But while i am trying to use my own oData i am facing issue like my destination with own oData is not displaying in the Service URL list.

      Can you help me on this how you created destination for your own oData ? This will be very helpful to me.

      Thank you,

      Satya

    • This can be avoided by setting the following value in config.xml:

      <preference name=”SAPKapselHandleX509Challenges” value=”false” />

      However, currently there is no way for you to change this value from SAP Web IDE. We are planning an enhancement for this.

      Meanwhile, if really needed, you can change this by downloading the Android project, modifying the file and rebuilding the project locally.

       

        • config.xml is added by Cordova during a Cloud Build. It is currently not available in the SAP Web IDE project.

          As indicated earlier, you won’t be able to modify this file now. We are working on an enhancement for this.

          • Hi Arne, we are planning a new release around early May that will allow you to edit the config.xml file in SAP Web IDE. You will also be able to remove plugins currently added by default, which should allow you to optimise the footprint a bit.

            Thanks,
            Ludo

             

          • Hi Ludo,
            As far as I know, we should be able to see the config.xml file in the SAP Web IDE by now. Unfortunately it is still not visible in my project. Could this be because I am using a trial account?

          • Hi Mathias,

            Please check the HAT extension version available in SAP Web IDE on your trial account. It should be version 1.32.1. If not, then try to clear your browser’s cache and reload.

            See my recent blog for more details.

            Thanks,
            Ludo

  • Hi Ludo,

    Nice blog, very informative and helpful. Though While following the blog and trying to explore more on offline functionality I faced some issues, will really appreciate your comments on the below points.

    I have followed all the steps as mentioned while using a simple custom service (entity1: parent, entity2: child association 1:n from parent to child) custom odata service. Overall it works fine but with some issues (all issues faced are with the mobile device):

    1. Create an entry -> flush -> refresh -> refresh the list -> leads to duplicate entries in the mobile one local and the other from the server.
    2. Delete operation fails with the message “cannot delete this entity instance. Another entity instance depends on it”, and I did put a breakpoint in the backend dpc_ext class method but its not hitting it and also it works fine in desktop. (I want to debug this scenario but not sure how we can debug, please suggest if possible)
    3. Also please suggest if there is any way to debug the file sap-mobile-hybrid.js file(or any other way to debug and understand the offline functionality better like can we play around with the offline store at the client) . I did import the project in android studio but was unable to put a breakpoint at any of the relevant code.

    Thank you again!

    Warm Regards,

    KBS

     

    • Hi KBS,

      Are you facing these issues also when using the Mobile Services sample data service, or only when using your own service?

      Debugging sap-mobile-hybrid.js is possible by setting breakpoints using the Safari (in case of iOS) or Chrome (in case of Android) browser. Once set, hit the reload button in the browser.

       

      Regards,

      Ludo

      • Hi Ludo,

        Thank you for your help on Debugging sap-mobile-hybrid.js by setting breakpoints. Took me some time but figured it out now.

        Regarding the below issue of dual records, this issue exist only with my custom oData service.

        Create an entry -> flush -> refresh -> refresh the list -> leads to duplicate entries in the mobile one local and the other from the server.

        Comment Update on 29th October – the above issue has been resolved

        Warm Regards,

        KBS

        • Kunj Bihari Shukla ,

          How did you manage to resolve this issue. We are facing similar more or less the same, wherein the successfully flushed entries do not get deleted from the store, thereby creating a pile of records which is preventing some of our validations and requirement  achievement.
          Thanks in advance.

          Regards,
          Harsha

    • Hi Angel,

      It looks like you data model has issues for which an entity is defined too large. Please check your data model and refine the properties.

       

    • Hi Mikaël,

      With custom plugins, you mean plugins you have created yourself, which are not part of a public repository ? If the answer is positive, then I can tell you that we currently do not plan to support this. The alternative is to download the complete project from our cloud build service and continue app development on a local system.

      Thanks,
      Ludo

      • Hi Ludo,

        Thank you for your reply.

        Yes I want to add a plugin created by myself in the project. Do you know if in the next upgrade of Web IDE we will have this functionnality ?

        As a workaround do you know if I can use HAT version 1.29.7 with SAP Web IDE ? (I have some problems to install it).

         

        Thank you for your help.

        Regards,

        Mikaël.

  • Hi Ludo,

    We have followed the same steps as in your system and have tried configuring offline code. As soon as we add offline code we are getting the error, as shown in the error screenshot, Please could you help on this. The pain part is that the error message doesn’t give much information nor it has much logs in the mobile services.

    Below is the code we added for offline configuration.( It was working fine, before the below code was added).

    “sap.mobile”: {
    “_version”: “1.1.0”,
    “definingRequests”: {},
    “stores”: [{
    “name”: “ODATA”,
    “serviceRoot”: “/sap/opu/odata/sap/ZTEST/”,
    “definingRequests”: {
    “ValueList”: “/List”
    }
    }]
    }

     

    We are trying this on the productive account( not on trail account).

    Regards,
    Harsha

    • Hi Harsha,

      I recommend creating a trace of this in Mobile Services cockpit and check the log for details on why you are receiving a 403.

      Also, besides the configuration you mentioned, did you implement the offline initialisation code accordingly ? The details in the manifest.json will be ignored; it has to be part of the openStore() function.

      Thanks,
      Ludo

  • Hi Ludo Noens

     

    Thanks for this comprehensive blog, I was trying a different approach but somehow I am lost, can you advise? Please pardon me since I’m really new at UI5, but I’ve been reading all the post and comments and still can’t be sure I’m doing it right

     

    Context:

    • I want to build a Hybrid UI5 to be deployed in Android
    • I built a destination in SCP named [D17], where the URL is referring to the SAP Cloud Connector to SAP backend which I named as https://virtual:8080
    • [D17] works fine with regular CRUD app which I named [CRUD] that I built from scratch (because I want to figure out how exactly the code works without getting mislead by generated codes
    • I am using service Catalog instead of service URL
    • I was using New->OData menu, which got reflected in manifest.json
      "dataSources": 
      {
         "ZMM_EMP_SRV": {
            "uri": "/sap/opu/odata/sap/ZMM_EMP_SRV/",
            "type": "OData",
            "settings": {
      	 "odataVersion": "2.0",
      	 "localUri": "localService/metadata.xml"
            }
         }
      }
      ...........
      "models": {
         "EmpData": {
            "uri": "/sap/opu/odata/sap/ZMM_EMP_SRV/",
            "type": "sap.ui.model.odata.v2.ODataModel",
            "settings": {
      	"defaultOperationMode": "Server",
      	"defaultBindingMode": "OneWay",
      	"defaultCountMode": "Request"
            },
            "dataSource": "ZMM_EMP_SRV",
            "preload": true
         }
      }
      ...........​
    • FYI the particular set that I am working on is called EmployeeSet
    • As I don’t want to spoil a working prototype, exported [CRUD] and imported back as [CRUDOffline] to prepare setup

    My Walkthrough with Your Guide:

    • Adding offline capabilities (Doubts: I Just need to add blank segment in manifest.json as below?)
      "sap.mobile": 
      {
         "definingRequests": {},
         "stores": []
      }​
    • Initializing the offline store (Doubts: Do I need to change only the defining request portion as below?)
      var properties = { 
         "name": "store_mainService", 
         "host": sap.hybrid.kapsel.appContext.registrationContext.serverHost, 
         "port": sap.hybrid.kapsel.appContext.registrationContext.serverPort, 
         "https": sap.hybrid.kapsel.appContext.registrationContext.https, 
         "serviceRoot": fiori_client_appConfig.appID + "_" + mobile_appRoutes[0].destination,
         "definingRequests": 
            { "EmployeeSet": "/EmployeeSet" } 
      };​
    • Replace call to startApp in appLogon() with openStore
    • If I read the comments above, since I do not create the project from template, I have to create destination in
      https://hcpmsadmin-pXXXtrial.dispatcher.hanatrial.ondemand.com/sap/mobile/admin/ui/index.html
    • So I tried creating them to mimic  generated destination from CRUD Template
      URL: https://XXX/sap/opu/odata/sap/ZMM_EMP_SRV/
      Proxy Type Internet
      Basic Authentication
    • https://XXX/sap/opu/odata/sap/ZMM_EMP_SRV/$metadata works fine on chrome.
    • When I Ping, I get error “Failed to execute ping” (Doubts: Please advise where I went wrong?)

     

    Best Regards

     

    Andre Julius

    • I would take a different approach and start with using the CRUD template available in SAP Web IDE.

      You can use the OData source from the service catalog as well; no problem. Make sure the app works as online web app (if it runs fine in SAP Web IDE preview, you are good).

      To trigger the cloud build to include the offline plugin, a blank mobile segment is sufficient. We’ll ignore the content.

      When you trigger a cloud build, Hybrid App Toolkit will create a new app on Mobile Services and a corresponding destination.

      The defining request you specified should be sufficient.

      Once you have this working, you have a reference that will help to figure out what is missing in your approach.

      I suspect there is some issue with the destination you’ve created. But it is difficult to tell. At first glance, it should work…

       

      • Hi Ludo Noens

         

        Following your advice, so far I seem to be able to make it work for service URL based app. Service URL / Service Catalog, both would generate [MS Destination] URL according to URL in [SCP Destination]

        Since in my Service URL SCP destination config [SURL] I already have the full path…my app is working

        https://S17:80/sap/opu/odata/sap/ZMM_EMP_SRV/

        However….in the case of service catalog config [SCAT]…I am pointing to the system as a whole

        https://S17:80

         

        Thus, when the service catalog based app is trying to read metadata it returns a fail, as they are trying to read

        https://S17:80/$metadata
        
        instead of the supposed
        
        https://S17:80/sap/opu/odata/sap/ZMM_EMP_SRV/$metadata

        I played around tried the rewrite URL, adding relative path “sap/opu/odata/sap/ZMM_EMP_SRV/” on the [SCAT] but it seems it still try to read  “https://S17:80/$metadata”

        I wonder, whether I am supposed to tamper with the code below in order to make it work for service catalog scenario? i.e.: by adding a hardcoded “sap/opu/odata/sap/ZMM_EMP_SRV/” behind the serviceRoot? Doubts: is this the right way to go?

        var properties = {
           "name": "store_mainService",
           "host": sap.hybrid.kapsel.appContext.registrationContext.serverHost,
           "port": sap.hybrid.kapsel.appContext.registrationContext.serverPort,
           "https": sap.hybrid.kapsel.appContext.registrationContext.https,
           "serviceRoot": fiori_client_appConfig.appID + "_" + mobile_appRoutes[0].destination, 
           "definingRequests": {
        	"EmployeeSet": "/EmployeeSet"
           }
        };

         

        Best Regards

         

        Andre Julius

        • Hi Andre,

          Change your code to the following :

          "serviceRoot": fiori_client_appConfig.appID + "_" + mobile_appRoutes[0].destination + "/sap/opu/odata/sap/ZMM_EMP_SRV/",
          • Hi Ganesh Babu ,

             

            Thanks for the recommendation, it did work out as you suggested. Initially I had Error Code 500, then I realize something wrong with the GW Model, as I need to regenerate it.

             

            Best Regards

             

            Andre Julius

  • Hi Ludo Noens

    Thank a lot for a very detailed and comprehensive blog. We could achieve Offline CRUD on Mobile Sample services.

    To point out, I believe the following defining requests should be?

    "supplierset": "/Suppliers/?$expand=Products"  ->  "/Suppliers?$expand=Products" .

    Now I am trying out the same thing but on our ECC backend. I am trying to make a sample Work Order CRUD app with offline and have some questions on that.

    1. Why is sap.OData.applyHttpClient()used regardless of whether the device is offline or not? Is it not expected from the app to query the backend directly when a network connection is present?
    2. Will Offline oData CRUD queries work the same way even in custom ui5 applications?
    3. Am using the below code in defining requests. It is working as intended on GW Client, but when the app goes in offline mode it only fetches the WorkOrdersSet  i.e the list and not the items. I created Association and Navigation property as usual for both entities. It seems it cannot fetch Operations from the offline store.
    /WorkOrdersSet?$expand=Operations

     

    Thanks for your help.

    • Hi Ganesh,

      Thanks for point out that the defining request is actually wrong and should not have a slash at the end of the entity name. The app did still work fine though, so our solution is having some tolerance there 🙂 .

      As for your questions:

      1. The offline plugin will overload the relevant functions and divert the calls to the on-device offline store. As an app developer, you don’t need to change a single line of code for this in your UI5 app.
      2. Yes, it will work the same. The only reason for choosing the CRUD template as a starting point here, is that it contains most of the CRUD code out-of-the-box. In other templates (or when working from scratch) you’ll have to implement it yourself.
      3. Please use the logs and network trace features in Mobile Services cockpit to find out why the Operations cannot be fetched. I suspect there is something fishy in your data model.

      Thanks,
      Ludo

      • Hi Ludo,

        Thanks for your reply.

        I guess it didn’t tolerate for me then since when I followed the same code it gave server error with “suppliersSet” due to which I had to fix the slash.

        Anyway,

        1. I did some changes where after the store is created, the Http Client is applied only if the device is offline. As long as there is a network connection app runs Online as usual and right as it loses connection the Http Client is applied and thereafter it runs offline.

        Is that not a preferred way?

        On the third point,

        As soon as the app runs online am getting the Details from ?$expand query as expected. Once the app runs offline, the Details screen is empty.

        How can I check logs and traces for this app since my Application is not there in Mobile services’ List of applications?

         

        Edit2: I have fixed the above issue. The OperationsSet Entityset had empty Orderid field. This won’t be a problem in the Online Query. In Offline though it searches for OperationsSet based on the OrderID from ListSet. So even if Operations exists in the store it will just not fetch. Hope it’s understandable, its hard to say in a few lines.

         

        Edit:

        Also is there an issue with downloading APK? Tried with different networks at different times, sometimes it downloads successfully but most of the times it just bottlenecks and stops at around ~10mb constantly. Having to do small changes and redownload every time only to face this stops the development process. I had expected a “Run on a device” feature(for Offline too) instead of Build and Download every time.

         

        Thanks,

        Ganesh

        • Hi Ganesh,

          Regarding the download issues… What is your location, and which landscape are you using ? Is it a Trial or production account?

          Thanks,
          Ludo

           

  • Hi Ludo

    Regarding this:

    “After the authentication screen and passcode screen, the screen will go blank for a while. We should actually show something here, so the end-user knows what is happening. This is an improvement to be added later. At this point, the offline store is being synchronised with the backend database. Once this is done, the UI will show up and display the data (this can take around 15 seconds).”

     

    Is this change imminent?

    Can you advise on a workaround until it becomes available?

    • Hi Adam,

      There are no plans to provide further improvements at this point. With all the code available in SAP Web IDE, I would assume that this is customisation that can be added by users.

      Regards,
      Ludo

      • Hi Ludo.

         

        It may be possible but in the Index.html this calls sap.hybrid.bootStrap() in sap-mobile-hybrid.js.

        We could wrap this in a promise etc but it would vastly overcomplicate the codebase as we’d need to combine the callbacks of the flush, refresh requests within a promise.

         

        E.g we could show a SAPUI5 Progress Indicator.

         

        call sap.hybrid.bootStrap();

         

        Then. (when all Promises have been fulfilled) hide the Progress Indicator.

         

        Wrapping all of the offline calls with Promises etc is a lot easier said than done though and would mean quite a lot of extra development.

         

        Hopefully, a progress indicator will be added as standard at some point.

  • Hi Ludo Noens

     

    I managed to simulate my case using service catalog until the flush part…however, the refresh callback does not seem to work for me. as per guide I do:

    Add in view controller

    onRefreshButton: function() {
    ....
    }

    Add in Hybrid.js as per guide also

    refreshStore: function() {
    ....
    },
    
    refreshStoreCallback: function() {
    ....
    },
    
    flushStore: function() {
    ....
    },
    
    flushStoreCallback: function() {
    ....
    },
    
    errorCallback: function(error) {
    ....
    },
    
    progressCallback: function(progressStatus) {
    ....
    },

    But apparently, the “Refresh” did not seem to detect the record that I already deleted from Online UI5 on the web. It did detect that I have additional.

     

    Am I missing something?

     

    Best Regards

     

    Andre Julius

    • Hi Andre,

      After the refresh callback is triggered, we should actually refresh the list displayed. This is currently missing in the example. If you use pull-to-refresh (after the refresh is finished, which takes a bit of time) it should reflect the changes.

      Cheers,
      Ludo

       

      • Hi Ludo Noens

         

        Thanks, it does work…BTW, does it make any difference when I put these functions in Master.js (View Controller) instead of in sap-mobile-hybrid.js?

         

        Best Regards

         

        Andre Julius

        • Hi Andre,

          It doesn’t really matter. You can put this anywhere. I would keep the hybrid app code as much as possible in the mobile folder; just to keep your web app code as clean as possible.

          Cheers,
          Ludo

           

  • Hi Ludo Noens

    I have issue with using cordova geolocation plugin for iOS11. I am using SAP Web IDE Full Stack, it seems the Web IDE didn’t add the NSLocationWhenInUseUsageDescription into  info.plist.

    I am using this plugin: https://github.com/slkerndnme/cordova-plugin-geolocation-ios-fixed

    What’s the setting in Web IDE to ensure this parameter is included so the location service is working properly in iOS11 ?

    Thanks.

     

    • Hi Ferry,

      In the plugin selection dialog, you can add a usage description for this plugin. Did you provide an entry there?  (see screenshot)

       

      Thanks,
      Ludo

      • Hi Ludo,

        I have done that as well. But the Web IDE console gives me an error message

        (hat) There were errors (see browser console for details) when setting the selected plugins

        From the browser’ console:

        HTTP/1.1 500 Internal Server Error
        Content-Type: application/json

        {“error”:{“code”:”0″,”message”:”com.sap.xscript.json.JsonException”}}

         

        This is also happens with all other plugins with usage description. I am wondering why.

        Cheers,

        Ferry

         

  • Hi Ludo Noens,

     

    I want to thank you for this blog, it’s really helpful.

     

    I was just wondering, Is it possible to create the Crud operations with Hat but with online mode ( like a simple sapui5 application but with android version) ?

     

    Should I do same steps you’ve mentioned but without creating a store in manifest.json?

     

    Thanks in advance,

    Ramzi

    • Hi Ramzi,

      If you create a new project from CRUD template in SAP Web IDE, it will be an online app out-of-the-box. You can build that into a hybrid app using HAT, simply by hitting the build. No code changes required.

      This blog is specifically describing the offline scenario, which does require some coding.

      Hope this answers your question.

      Cheers,
      Ludo

       

  • Hello Ludo –

    Thanks for the blog.

    One Question : Why does the build fail (Build Packaged App) with Error: Build Failed as the CBS build job id was not found for this Application.

    ~ Rakesh Narayan.

    • Hi Rakesh,

      Is this issue persistent ? Or does it go away when you trigger the build again ?

      Also, can you tell us which landscape you are using ? Is this on trial or a production landscape?

      Thanks,
      Ludo

       

      • Hello Ludo –

        Yesterday, it worked fine for me and I was able to build the project and generate apk.

        Today, I have tried several times (recreating, rebuilding) but the build is not going through and I get the same error.

        Regarding Landscape – I am using Trail Account for now.

        Regards,

        Rakesh Narayan.

      • ++ build error in WebIDE

        The mobile build failed at step “POST/ startBuild” (scpms_api)

        (The error is coming for every project, even an empty random project  shows this error when I try to build)

        Regards,

        Rakesh Narayan.

        • Hi Rakesh,

          We are currently facing issues on the trial landscape. Our engineering team is looking into this. The issue is only affecting trial users.

          Thanks,
          Ludo

          • Thanks a lot Ludo. I have tried and it looks all fine now.

            Besides, I would like to ask about the size of the file (apk); its 90-100 MB files in most of the cases.

            Do we have any compression in place to reduce the size?

            Regards,

            Rakesh Narayan.

          • Hi Rakesh,

            The reason for the large footprint is that we include a relatively large set of UI5 libraries. Our current Cloud Build Service is not able to strip down this set to the bare minimum for your app.

            It might be possible to optimise this using UI5 Evolution. However, we don’t have any plans to support this with Cloud Build Service.

            Thanks,
            Ludo

  • Hello! Great post thank you!

    I am currently facing an issue when trying to build packaged App, it says (hat) the CSFR token has expired.

    I am not using a trial account.

    Maybe is an easy fix but i have no experience in this topic. Do you have any suggestion? thank you!

    Ivan

  • Hi Ludo,

     

    Thanks for your informative blog. I am currently attempting to implement downloading of offline attachments with my app.

    I have configured a defining request pointing to my attachments entity with retrieveStreams = true

    "Attachments" : {"url" : "/zdod_i_attachments", "retrieveStreams" : "true"}

    However, on initial opening of the store I receive a sync error. Checking mobile services, I can see that the app attempted to call:

    <service_root> + ZDOD_DEF_APP_SRV/file_name
    

    The app appears to be attempting to download all attachments on store open. I assume I need to use the function registerStreamRequest, however I am unsure where in the application lifecycle this needs to be called and if I need to make the function call for each individual attachment

     

    Below is a sample call:

     

    sap.hybrid.store.registerStreamRequest("stream",
    "/zdod_i_attachments(incidentId=guid'" + incidentId + "',attachmentId=guid'" +attachmentId + "')", this._onRegisterStreamSuccess.bind(this), this._onRegisterStreamError.bind(this));

     

    Thanks,

    William

     

  • Hi Ludo Noens

     

    I find that recently there is a change in behaviour? With the code in this blog now even when I am online, I need to flush in order to get the result pushed to the back. Is it just my imagination? I’m pretty sure last time when I am online I don’t have to flush.

     

     

    Best Regards

     

    Andre Julius

    • Hi Andre,

      Once you make use of an offline store, your app will be working against the local store only. You’ll need to flush in order to update the online database. I don’t think anything changed recently regarding this behaviour.

      When using the web app (deployed to SAP Cloud Platform), you will be working online, with the online database.

      Thanks,
      Ludo

  • Hi Ludo.

    Could you help me, please?.

    I have a problem in defining requests, because i need filter data before download to local storage offline. I have used $filter, but it is not work.

    regards.

    Angel

    • Hi Angel,

      Looking at the strings used, I am seeing:

      • UserStatuSet             (you probably meant UserStatusSet)
      • WOSystemStatuss    (you probably meant WOSystemStatus)
      • SystemStatus   (you are trying to filter based on a substring of this)

      Please review and adjust accordingly.

      Thanks,
      Ludo

  • Hi Ludo, thank you for your great blog.
    Nowadays, I am realy focusing on offline topic and when I saw your blog I immediately tried to implement offline application.
    When my application run as a web application on browser, it works fine on pc without any errors (but I am not sure about of offline part is ok or not). Also, the apk file works fine on phone when online.
    But I need your support for mobile offline scenerio. I try to test applicaiton on phone via apk file when switch off internet, it gives error for every process. It shows just error thus, I couldn’t try offline scenerio.
    Although, I tried different many kind of path for solving error. it unfourtunetly did not work on phone.
    Colud you tell me, where and how should I check in the project?

    Also, I couldn’t open Android Studio Project via Android Studio. The project has so different structure than native Android applications.
    How can I open and modify it?

    Could you help me, please?

    • Hi Mehmet,

      If the app works as online app, then the issue is most likely related to the offline store initialisation. I have recently added a troubleshooting section to this blog. Please ensure the offline store get initialised.

      Loading the Android Studio project is detailed in this blog: https://blogs.sap.com/2018/07/02/whats-new-in-hybrid-app-toolkit-release-1807-custom-fiori-client/

      Hope this helps.

      Regards,
      Ludo

      • Thank you for your supporting.

        Now, I can open custom fiori client project via Android studio and I understand the concept.

        I have one more question, can I use on-premise SAP Mobile Platform in this offline architecture and how?

         

        • Hi Mehmet,

          On-premise SAP Mobile Platform is not supported in the scenario described. This only works with Mobile Services, available on SAP Cloud Platform.

          Using SAP Cloud Connector, you could expose your OData sources to SAP Cloud Platform.

          Thanks,
          Ludo

      • Hello Ludo,

        Thanks for this information. I have unchecked the Push notification check box and i have generated the QR code.

        But my question is why that error was coming when i was using Push notification ?

        and another question is how i scan qr code from mobile device?

         

        Thanks

        Deborshi

        • Hi Deborshi,

          There is a known issue with Push notifications that will be fixed in a patch we have planned to release by end of this week.

          Scanning QR codes is standard built into the iOS camera function. For Android, there should be a large amount of options out there (apps, built in).

          Cheers,
          Ludo

          • If you’ve managed to build the app using cloud build service and the result is a QR code, then you have Mobile Services in your subscription.

             

  • Hi Ludo.

     

    Is possible filter data from a entity before what data is to download in local storage. I use $filter in defining requests but this action no function.
    Have you got any idea?.

     

  • Hi Ludo,

    Thanks for the blog.

    I am able to create an offline app and it works perfectly.

    I still have a few questions which are not clear for me. Would be really great if you can help.

    1. Whenever we do changes in our app, we have to build it again which leads to reinstalling the app on our devices again. How can we use AppUpdate plugin with cloud build?
    2. How to customize the login screen similar to what we can do using HAT?
    3. Can we remove the unwanted Kapsel plugins from the app as it increases the application size?

    Regards,

    Vikas

     

    • Hi Vikas,

      1. AppUpdate is not supported from SAP Web IDE Full-Stack.
      2. This will be some manual coding work. In the file mobile/hybrid/sap-mobile-hybrid.js , we pass a context to the Kapsel logon plugin. You can modify the code as described in the Kapsel logon documentation
      3. Currently, the only way to do this is by downloading the complete Xcode / Android Studio project from the cloud build service and manually stripping out the plugins not required. We are working on an update planned for end of April 2019, where you can select/deselect plugins from within SAP Web IDE.

      Hope this helps,
      Ludo

  • Hello Ludo,

    Hope you are doing good!

    • I have followed, all the steps, given above to generate/package the application.
    • However,I am getting, error as mentioned below(unable to attach an image/screenshot here.), while trying to access the app, from android mobile.
    • I am able to ping, the destination successfully from destinations tab, in SCPMS.

     

    • The error is “Retrieve metadata failed because the OData server returned HTTP code, 404, with message: null”.

    Can you please, help me out, on this?

     

    BR,

    Sushant

     

     

     

    • You are able to ping the destination in Mobile Services, but are you able to perform the OData application destination test (the icon on the left side of Ping) ?

      Checking the logs and traces in Mobile Services will provide you more details on this 404.

      Which OData source are you using ?

      Thanks,
      Ludo

  • Hello Ludo,

    Thanks for looking into,this issue.

    I am using northwind odata services.

    Yes, am able to perform Odata application destination test, after setting the relative path to “/v2/northwind/northwind.svc”.

     

    BR,

    Sushant

  • Hey!

    I could recreate your sample with no problems, but if I try to do it with my own Odata Service it doesn’t work.

    The Odata does work, as long as the store function isn’t implemented.

    I did use the Odata from the Service Catalog:

     

    with this Destination:

     

    I tried it with this 3 methods for the serviceRoot, getting either 401 or 403 errors.

     

     

    With the first Method I get: As I tried to recreate it, I did just get a blank screen where nothing happens. Not even the login Prompt for SAP.

     

    With the second Method I get: [-100010] Retrieve metadata failed because the OData server returned HTTP code, 401, with message: null.

     

    With the third Method I get: [-100010] Retrieve metadata failed because the OData server returned HTTP code, 403, with message: Backend connection sap is not mapped for this application configuration.

     

    Manifest is just :

    	"sap.mobile": {
    		"definingRequests": {},
    		"stores": []
    	}

     

    If you could help me, that would be awesome!

    • Hi Dominik,

      The manifest part is correct. This is can be left empty is shown, because this structure is only needed to trigger the cloud build service to add the Kapsel offline plugin. The contents are ignored.

      Unfortunately, I have not created an example that involves on-premise OData sources.

      Please check in the Mobile Services admin Cockpit which (mobile) destination is used for the mobile app and see whether you can Ping this destination. Use the OData application destination test (the icon on the left side of Ping). Specify the relative path as used by your app and click next. You should be able to view data available in the service.

      You might want to experiment with the URI in the manifest file. There are other users who reported fixing issues by changing this. Please check previous comments on this. Given the large amount of comments on this blog, you might have to click on the “Older Comments” button to see all of them.

       

      Thanks,
      Ludo

    • Hi Dominik,

      Try to use 2nd scenario. In your frontend system, open the odata service in SICF. Under the logon data tab, mark the checkbox – Use all logon procedures. Clear data of your app on device & check again. You should be able to resolve the error.

      I used this way to solve mine.

      Vineet

  • Hi Ludo,

    Are there any issues with iOS Cloud Build. I am getting below error fir iOS version. It was working before.

    [2019-03-11 03:02:58.13739] [IT] [LogToken] [Command Return Value: 0] [] [CBS\Utils\Utility::execCommand]

    [2019-03-11 03:02:58.13763] [IT] [LogToken] [Finished Executing Command: prepare_sign.sh] [] [CBS\Utils\Utility::execCommand]

    [2019-03-11 03:02:58.14033] [ET] [LogToken] [[Build Failed For [ios][ErrorCode :PREPARING]][[ErrorStatus:DEPLOY_STATE_FAILED][Invalid appId – less than 3 segments: .x9fda02d1cd9a403b81a90535cbeb0a99][CBS\BuildEntities\CordovaIosBuildEntity::adjustIosBuildFile]] [] [CBS\BuildEntities\CordovaIosBuildEntity::adjustIosBuildFile]

    [2019-03-11 03:02:58.14070] [ET] [LogToken] [Exception occurred at Build Phase: 1  Exception Message:

    Error Message:: Invalid appId – less than 3 segments: .x9fda02d1cd9a403b81a90535cbeb0a99

    ErrorCode::PREPARIN0

    ErrorState::2] [] [BUILD]

    This is both on Trial and regular SCP Mobile services. Please suggest.

    Thanks
    Sumanth

    • Hi Sumanth,

      This is related to a change we did in November last year. You should update your signing profile to the new appId, which is now based on 3 segments   (e.g. com.sap.x9fda02d1cd9a403b81a90535cbeb0a99).

      Regards,
      Ludo

      • Hi Ludo,

        Thanks for info and reply. I will try change my certificate to include app id as com.sap.*

        Is there an option to use customer name space in to app Id instead of com.sap

        I did not find any option to enter different id while cloud build. All apps are being created as com.sap.webide.xxxxxxx

        Thanks

        Sumanth

         

        • Actually, yes, you can use other combinations as well.

          Take note that we used to combine the AppId (as used on Mobile Services), with the Bundle ID used for the signing profile. However, these can now be defined independently.

          So, your Bundle Id used for the signing profile can be for example com.yourcompany.myapp

          Cheers,
          Ludo

           

          • Hi Ludo,

            Thanks for the help. That worked after adding a Bundle ID with three segments. Is oAuth Security supported for Hybrid Offline Applications?

            I tried to enable oAuth at app level in mobile services cockpit and build the app. Got 403 Error at ODATA Service call as there was no SAML Token passed to backend service. Will look further in the documentation. Any pointers in using oAuth would be helpful.

            Thanks
            Sumanth

             

          • Hi Sumanth,

            Could you please describe how you have changed your Bundle ID? Do we have to change it in the config.xml file?

            Thanks for your help.

            Dominic

  • Hi Ludo.

    By default, requests are ‘batched’ which is causing memory errors on the Samsung Galaxy J5 (and J3) Android phones.

    Turning off batching (“useBatch”: false in Manifest.json) causes other issues with speed and oData call execution, so this isn’t an option.

    End result is we really need to get this working using batching.  Can you recommend any optimisation? I have setup the Client Indexes.

  • Hi Ludo,

     

    After building the app, why it is having file size around 100 MP. iIt’s just the template I’m having in the project(I don’t have any additional code)?

        • Hi Jithin,

          Unfortunately, we don’t provide a way to limit the amount of libraries included in the cloud build service. What is included is already a subset tailored for mobile.

          You could manually strip out the libraries you deem not required by downloading the Xcode/Android Project locally. But this is tricky, because you might not know the dependencies. If you leave out too much, the mobile app will fail at runtime (and this can be very hard to debug).

          Regards,
          Ludo

  • Hi Ludo,

    Nice blog.  I went though this and did the build for Android.

    However, for our client, we are trying to build offline Hybrid applications for Windows platform.  I am able to get some of the offline examples working for Windows and debug them through Visual Studio 2017.  I am working on the offline example – Getting Started with Kapsel – Part 10 — Offline OData(SP13+)

    From your example, since we do not have the Windows build service available through cloud build, do you have the steps on how I can bring this project into a Cordova windows project and run this.  I am able to create the Cordova windows project, add Cordova and Kapsel plugins, and debug.  In Daniel’s blog, i just need to add the corresponding plug-ins and then replace the default Cordova generated index.html with the one he had written.

    With your example, if I just export the project from WebIDE and then bring this folders and files into the Cordova Windows project, I am not sure exactly how this will work.  Do I keep the mobile/hybrid folders as you have in the project or do I need to blend them with the web app folder?

    In your article, you state:

    Take note that during the cloud build process, the contents of the webapp folder and the mobile folder will be merged into the www folder of your Cordova project. The index.html file in the mobile folder will replace the one in your webapp project (if your project has one).

    Can you please provide some guidance on the steps to go from your example to doing a build on Visual Studio 2017 for Windows?

    Thanks,

    Jay

     

     

     

     

    • Hi Jay,

      We will basically merge the mobile folder into the webapp folder during the build process. This will obviously not happen when you export the project from SAP Web IDE. If you want to do this manually:

      1. copy webapp folder contents into Cordova www folder.
      2. copy mobile folder contents into Cordova www folder, overwriting existing files from step 1.

      I think the easiest way to get what you need, is to perform a cloud build for Android, with the build option “Save Xcode/Android Studio project”. Once this is done, you will be able to download the complete project onto your windows machine. This project will contain the merged folders.

      I am not sure whether you could add the Windows platform directly in the Cordova project by using the Cordova CLI tools, but it is worth a try.

      You might need to adapt the index.html and other files for the Windows target. I don’t have instructions for that.

      Hope this helps,
      Ludo

      • Hi Ludo – I just saw your comment after I posted a comment below.  I will try the steps you have mentioned.  I will take the Android studio project and then download that and then see how that has been done.

        What I had done is merge the contents manually and then point the start to be the index.html from the mobile folder which now is under the www folder.  I also brought in the resources folder that has the SAP UI5 sap m and ui folders.

        I am not sure where fiori_client_appConfig is defined.  I do not have the appConfig.js and appRoutes.js in the exported WebIDE project.

        Thanks,

        Jay

         

        • Yes, that is another reason for advising you to download the complete project from our build service. Those missing files are generated and will be part of the final project.

          Cheers,
          Ludo

    • Hi Ludo,

      I downloaded the project from WebIDE and trying to bring the files into the Cordova project.

      But I am not sure where to get these files you have referenced – appConfig.js and appRoutes.js – since I am not using the Cloud Build serve.

       

      	<!-- initialize bootstrap -->
      	<script type="text/javascript" src="hybrid/sap-mobile-hybrid.js"></script>
      	<script type="text/javascript" src="hybrid/logon.js"></script>
      	
      	<!-- app configuration info files are added during cloud build -->
      	<script type="text/javascript" src="appConfig.js"></script>
      	<script type="text/javascript" src="appRoutes.js"></script>
      	
      	<script type="text/javascript" src="cordova.js" onload="sap.hybrid.setCordova();"></script>
      
      	<script type="text/javascript">
      	(function() {
      		var remoteBase = fiori_client_appConfig.fioriURL;	// not use fioriclient plugin but borrow some of its configuration format
      		if (remoteBase.charAt(remoteBase.length - 1) === '/') {
      			remoteBase = remoteBase.substring(0, remoteBase.length - 1);	// remove trailing slash
      			fiori_client_appConfig.fioriURL = remoteBase;
      		}
      

       

      I am getting the error:

      SCRIPT5009: Unhandled exception at line 42, column 3 in ms-appx-web://com.sap.webide.x30eab3620cc54629bd808de0ffd6e721/www/index.html 0x800a1391 – JavaScript runtime error: ‘fiori_client_appConfig’ is not defined

      Where does this variable get referenced?

       

      Thanks,

      Jay

       

       

       

      • Hi Ludo,

        I downloaded the Android build project and copied the files over.  What is strange is that I am now getting an error:

        SCRIPT5022: Unhandled exception at line 1360, column 9 in ms-appx-web://com.sap.webide.x30eab3620cc54629bd808de0ffd6e721/www/cordova.js 0x800a139e – JavaScript runtime error: Module cordova-plugin-network-information.network does not exist. cordova.js (1360,9)

         

        I had already added the cordova-plugin-network-information.network in the project using the cordova CLI:

        cordova plugin add cordova-plugin-network-information

        So I am not sure why it’s erroring out.  Should I just copy all of the plugins from the SAP Built project into my Cordova project or should I add them one by one with the CLI.

         

         

        I am not sure why the code is not finding this plugin.

        Regards,

        Jay

         

         

        • Hi Ludo,

          I copied the resources folder from platforms\android\app\src\main\assets\www\resources which has all of the sap ui5 libraries and also the plugins from platforms\android\app\src\main\assets\www\plugins so I am no longer getting the issues with missing js files and plugins.

          I can step through the call to sap.hybrid.bootStrap();  But the application just exits without going into the first page of the application.  I am not sure why.  I do see an error – “Can’t load the ActiveX plug-in that has the class ID ‘{D27CDB6E-AE6D-11CF-96B8-444553540000}’. Apps can’t load ActiveX controls.” that happens before.

          So the sap-mobile-hybrid.js never goes into the actual application.

           

          Regards,

          Jay

           

  • Hi Ludo,

    store.open() function control enters success callback function, but the store is not getting created, the app opens  fine, but the busy dialog keeps running with user interface opened  ( tried keeping it for more than 20 minutes, no help  ) . And major doubt is with “store” variable, you have not declared “store” variable, I declared it just as a local variable, does that have anything to do here? Because rest of the lines of code remain the same as yours.

     

    Thank you,

    Shree Krishna

    • Hi Shree,

      This sample code is not perfect, but I did validate this multiple times and various users have confirmed this was working fine.

      Please see the troubleshooting sections for directions on how to analyse potential issues. I suggest capturing a trace at Mobile Services cockpit to see why the store is not getting created.

      Thanks,
      Ludo

      • Hi Ludo,

        I figured out the problem, the problem is with the Regular Expressions within startApp() function, like you mentioned in the blog

        “In the file mobile/index.html there is some code to adjust your app’s XMLHttpRequests to use URLs that work locally. Please check whether the URL used matches with the serviceRoot you’ve defined. If the path doesn’t match, the app will not use the on-device store.”

        can you please help me out what is happening in the regular expressions out there in that function.

        Regular expression will not match my appId.

        My appId looks like this : com.sap.webide.x4b530a7020154b4ea11037a6c5416c69

         

        Thank you,

        Shree Krishna

  • Hi Ludo,

    Thanks for the wonderful blog.I was able to successfully build an offline application. However, what I have noticed is that some entities in the metadata are not loaded when opening the app first time.As a result, create and read are not working for those missing entities while it works fine for the ones which gets loaded. The application works fine on web browser however not working on mobile both in online and offline mode.

    Could you please help and suggest what could be the issue possibly.Have a demo lined up this week.

  • Dear Ludo

    thanks for the great post!

    We got everything working, but when trying to connect to an OnPremise ABAP System we get an error:

    Failed to load resource: net::ERR_FILE_NOT_FOUND

    logger.js:775 error sending ping request{“errorCode”:-121,”description”:”ERROR whitelist rejection: url=’https://mobile-xxx.hana.ondemand.com:443/odata/applications/v1/com.sap.webide.xxxxxxyyyyyy”}

     

    We also tried to change the projects config.xml

    <access origin=”*”/> to the SCPms URL.

     

    Thanks fpr your help!

    BR,

    Martin

    • Hi Martin,

      I suspect a wrong configuration somewhere…

      Are you able to access your on-premise data in Mobile Services admin cockpit?

      First of all, try to ping the destination. If that works, try testing the OData source to see whether you can pull information.

      Thanks,
      Ludo

  • Dear Ludo,

    I followed your tutorial exactly. But when I tried to change the sap-mobile-hybrid.js I got problems with already existing variables….

    For example fiori_client_appConfig and console are not defined. Do I have to define them or was there an error with generation of the file?

    Greetings Nicole

  • Hi Ludo!

    Great blog, your app works fine, but I have a question.

    In your app you also get an error called “[ODataMetadata] initial load of metadata failed -“. Why does this error occur and why are we able to work with the app, if the metadata couldn’t be loaded?

    Regards,

    Daniel

  • Hi Ludo,

    Nice blog.

    I was also able to replicate the example given by you. But while i am trying to use my own oData service, i am facing issue like my destination with own oData is not displaying in the Service URL list.

    Can you help me on this how you created destination for your own oData ? This will be very helpful to me.

    Thank you,

    Satya