Edit 28th Feb: The URL to access the OData service is incorrect below, this bypasses the SMP server and goes directly to the OData service. The correct URL to use after registration is http[s]://<smpServer>:<port>/application.reverse.domain so in the case of this app the URL should behttp://smpServer:8080/com.bluefinsolutions.poc.smp3.101 – you can also use the connection name in place of the app ID depending on the configuration which in this case would be http://smpServer:8080/SampleNorthwinds
When accessing the OData URL for the SMP server you must have a header value for X-SMP-APPCID equal to the registered appID in order to successfully access data.
This post aims to cover the minimum steps required to get a native iOS application functioning correctly through the SAP Mobility platform version 3.0 + and retrieving data from OData services. This document will focus on six main topics:
- Setting up your application on the SAP Mobility Platform Server
- Setting up an iOS application with the SMP libraries
- The code behind registering a device
- The code behind making a series of requests to retrieve data
- A basic UI to visualise it
- Running the app
SMP3 at time of writing is in ramp-up only. For more information on getting involved in the ramp-up please see this post Get your hands on SAP Mobile Platform 3.0.The complete source code (without SMP3 libraries or header files) can be found on my github page at bocallaghan/SMP3-101 · GitHub
Section 1 – Configuring SMP
Before you can connect any application to your SMP server you need to configure it to allow access. This is done covering 3 components:
- Re-using or creating a Security profile
- Defining your “endpoint” AKA the data source (in our case OData)
- Linking the two previous under a unique name called an “Application”
For the purposes of this document I won’t cover any of the SMP configuration in detail as that is more of a topic in itself however i will show enough to get you started. To logon to the administration centre of your SMP server go tohttps://<smpServerHostname>:8083/Admin using the admin passwords to logon (the user is usually smpAdmin).
Go to the settings section and under “security profiles” add a new profile. When you have created the profile (and this should only be completed for DEMO’s or POC’s ONLY) add a hard coded username and password of the type “System Logon” specifying a username and password before saving.
Define your endpoint
Your endpoint is the data source your application will be able to access. In the same area as in the previous step go to the “Connections” tab. Here you can add a new “Back-end connection” by specifying a connection name, endpoint URL and a number of other settings which we will be leaving blank. For this example we will be using the Odata.org sample OData services found at http://services.odata.org/Northwind/Northwind.svc/
Create the application
Under the Applications area you can add a new application quite easily filling in an ID a name and the app type. So in my example the ID is com.bluefinsolutions.poc.smp3.101 (reverse domain name) and the name is “POC for SMP3”. Of course our type of app is native.
Next you need to link the app to the endpoint and the security profile. Under “Back-End” enter your connection details or select them from the list and then under “Authentication” choose the existing profile you created earlier.
And that is it – your server is now configured for your SMP3 application.
Section 2 – Setting up an iOS application with the SMP libraries
The first step of writing the app is to setup your Xcode project. For the purposes of this document a certain level of iOS development knowledge is required. However if there are any questions on steps I may have left out please do add a comment to this document and I will answer as soon as I can.
First open Xcode and create a new iOS project of the type “Empty Application”
Give the project a name – in my case it was SMP3-101
Once the project is created the first thing to do is to change the deployment target setting on the project to iOS 6.1
Next – select your target – in my case names SMP3-101 and under the build settings and under the architectures change the architectures to “Standard Architectures (armv7, armv7s)” note – not 64-bit. Also remove the 64-bit entry under the “valid architectures” entry.
Next we want to add our SMP3 library header files – these are the .h files that will have come with your SMP3 SDK installation. Create a folder in your project called “SMP3_Libraries”, right click and “Add Files”.
Now you need to add the “includes” folder from the iOS native SDK resources that came with the SMP SDK. The resources are found in the SDK install directory at “MobileSDK3NativeSDKODataFrameworkiOS”.
Once these are in the next step is to add a number of pre-compiled libraries or .a files to your project. These files can be found in the libraries folder of the iOS native SDK resources that came with the SMP SDK. You will want all of the libraries in the folder “Debug-Universal” except for the libAfariaSLL.a file which has its functionality duplicated by the file “libcrypto.a”. You add these files by going back to the project level, click on your target “SMP3-101” and under “Build Phases” and “Link Binary with Libraries”. You also need to add a number of standard libraries from this list:
Once all libs are in you should see a list like this:
There is one final step in preparing your project to run and that is to tell Xcode where those header files for the libraries you just added are. They are in the project but still need to be pointed to. Going back to our target “SMP3-101” and under “Build Settings” and under the section “Search Paths” add the following path to the entry “Header Search Paths” – “$SRCROOT/SMP3-101/includes/public” which is recursive. Now you still need to make sure this path matches YOUR project but this is what has worked for me:
Now the fun starts – build your project and it should all be fine – if it is not then you have missed a step and please don’t continue until you fix it – these problems only get worse – not better!
Section 3 – The code behind registering a device
Now we need to add a new file to our project – and for the purposes of this POC we will call it the SMPController as a subclass of NSObject.
As you amy have guessed from the name this will be our controller for all comms with the SMP server. For anybody who is interested, the design pattern I will use here for convenience is to have this class do all the communications with the server and any front-end UI will simply register as a delegate for any high-level callbacks we will define.
Which brings us to the header of the file – SMPController.h This file has a number of variables such as server hostname, username and password (never normally hardcoded) and the name of the OData collection we are after. It will also define the methods that our UI can call to control the controller at a high level:
As i have deliberately commented the code in a very verbose way I will not go line for line but the highlights here are the two methods to be called from the UI – “initialiseSMP” to register our users and the second method is “beginDataRetrieval” which starts to get us data. There is also a “delegate” object which will be our reference to our UI class that is calling us so we can tell them our response to their queries.
(Again if this is seeming confusing I encourage you to download the code from bocallaghan/SMP3-101 · GitHub to read the comments better).
The implementation of the initialiseSMP method is one I will cover in detail:
Once the variables have been setup (username, password etc.) we create a connection object to represent our connection to SMP. For this single use application this is fine but in the future there is a connectionID created during every first connection that will need to be stored so the server can recognise you when you reconnect.
In this case we simple register our class as a delegate to be told if the registration is a success or failure and call the method “registerUser”.
Once the callbacks are triggered to give us the result we can tell the UI that it is safe to retrieve data:
You will see above there is a call to an “EncryptionManager” class to “resetEncryptionKey” – this works for a POC on a single connect basis but should be handled differently when dealing with a proper use-case (connect and reconnect rather than a new connection every time). Please see the documentation referenced at the end of this document for more details.
Section 4 – Making a series of requests to retrieve data
Now we have successfully registered our app we can request data from our OData service. There are three parts to our data request. First we need to retrieve what is called the “ServiceDocument” which tells us what is available. Once we have that we retrieve the “Metadata” which tells us the structure to expect our data in and then finally once we have that we can get our actual data.
The act of making a request is quite simple (especially when we are only getting data). The only thing that changes between the three calls is the URL and also what is known as a request tag. When you tag a request with a number (int) it allows you to identify which request it was when you receive the response. So for us tag 1 will be the serviceDocument , 2 the MetaData and 3 the data itself. So with that in mind the generic code for all the requests would be formed like this:
Note i have put this in a method that takes a different URL and tag for each call – nice and reusable.
For the three calls they are structured as follows:
The sequence in which these are executed is quite simple. Once one request returns successfully it triggers the next in the series. Our class is setup to receive callbacks for when requests succeed or fail. In our case, when a request succeeds, we pass the parsing of the response to a specific method and then call the next request down the chain. As follows:
Each request type has its only custom parsing method to extract and store the data we need. E.g. for the metadata we extract certain info which is different to the ServiceDoc etc.
Note that the parsing method of the actual data doesn’t trigger another request – instead it calls back to the UI passing the data received.
There is more to the controller class than I have mentioned here however please see the comments in-line for more information.
Section 5 – A basic UI to visualise it
The UI for this app will be very simple with only two buttons and a table of result data being shown.
First, create a new class with a XIB as a subclass of UIViewController implementing the UITableViewDataSource protocol:
The protocol “smpDelegate” has been defined in this project to map out the methods the SMPController class can callback to the UI and is structured as follows:
The two buttons on the UI (registration and Data download) should be hooked up to action methods and should call methods on the SMPController as shown below. In this class the variable self.controller is of the type SMPController and is created during the initialisation of the UI Class.
The protocol methods you will implement will control how the UI reacts to the SMP events – for example if the registration failed you may want to popup a message telling the user, or when the data download is complete you will want to refresh the results table. For this example I have followed this simple structure and it should be formed as follows:
And now the missing piece of the puzzle – how do we populate the table with data. As our view class is the data source of the table (Don’t forget to hook up the table to the class as its DataSource in the UI editor – control click on the table and drag to the orange icon marked “Files Owner” and select “DataSource”) we will need to structure the cells to be displayed as well as indicating how many cells there are in the table (a count of the number of results).
We do this as follows using the UITableViewDataSource protocol methods:
Now we are almost ready to run our app – the last piece of coding we need to do is to tell our app to load our UI – this is done in the AppDelegate file and just requires one extra line to add our UI to the window:
Section 6 – Run the app
Now we are ready to run the app. So launch the app and if you have no errors you should see a screen with our two buttons and an empty table as we have no data yet. I have coded my “Begin Data Download” button to not function until we have successfully registered.
Tap the “Register user” button and your console in Xcode should show you a log of everything that is happening on the SMP side. Eventually (assuming you have configured the server and app right” you should see “Successfully Registered User”. In that case my second button becomes ready for me to use.
Now I tap “Begin Data Download” and my console should once again start telling me what is happening and then assuming everything is configured right – I should see my table automatically update with data
And that is it – if you have come this far you have successfully created your first SMP3 app. As a quite simple POC this would be too simplistic for any real productive app however as a starting point it should be quite useful.
For more information about SMP 3 and the available APIs including how to use them please see the Sybase Infocenter at http://infocenter.sybase.com/
For more information on iOS coding I recommend using the website stackoverflow.com or searching for the Stanford lecture course CS193P which is a great starter on this topic.