My First SAP iPhone app
h1. My first SAP iPhone app Hi everyone, You just pulled your shiny new iPhone out of the packaging. It is amazing how quickly you get comfortable with the intuitive user interface and all the apps that are available. After a while, you wonder if it is possible to use this wonderful device to access business data from SAP. Well, at least, that is what happened to me. If you search for ‘iPhone’ on SDN, you will find {code:html}this Wiki page{code}. Though you can find some basic information you need to build apps, you still have to connect a lot of dots before you have an iPhone app. That is where this blog comes in; it contains a step-by-step manual to create your first SAP iPhone app. You *don’t* need to have any experience in developing for Apple; only basic familiarity with programming concepts is assumed. We are going to develop a very simple app which has the same functionality as transaction SM04: it shows which users are logged in. We will be using standard iPhone controls and the result will be something like:
—- h2. Preparation iPhone apps (and iPad apps as well) are written in Objective-C, which is a variation of C widely used in Apple development. It is an object-oriented language. Those of you with experience in Java (or perhaps C++ or C#) will certainly recognize elements of the language. If you only know ABAP, you are at a slight disadvantage, but fortunately the language is quite easy to read. You develop iPhone apps with Xcode, the standard development environment of Apple. There are a few steps you need to take before you can start developing: * Xcode runs only on Mac OS X, so you need either a Mac computer or a virtualized environment running Mac OS X. * * You can only download Xcode if you are registered as an Apple Developer. You can do this here (http://developer.apple.com/programs/register/). Registration is free, but you can only run your apps in an iPhone simulator on your Mac. If you want to test on a real device, you need to enter the iOS Developer Program, which costs $99 a year. This is also a prerequisite for publishing your apps in the App Store to make them available for the rest of the world.0.1. 0.2. Now, you can download Xcode here (http://developer.apple.com/devcenter/ios/index.action#downloads) (warning, it is 3.5 GB large)0.1. 0.2. Perform a standard installation of Xcode, including the iOS SDK. 0.3. —- h2. Introduction to Xcode When you launch Xcode, you will see the following screen:
Choose the first option, ‘Create a new Xcode project’. In the next screen you choose a template for the app.
In the left column, select the sheet with iOS Application templates, and double-click there on the option ‘Navigation-based Application’. A window appears where you can choose a name for your project (UserList) and a location to save it. After you click the ‘Save’ button, Xcode will create the project and generate some template coding. The next screen that appears is similar to the ABAP workbench (transaction SE80). You can resize the screen with the green button in the top left corner, or the resizing area in the bottom right corner.
You see four areas that are important to you: 1. 2. The *toolbar* (on top) provides quick access to basic functions, like running the program.0.1. 0.2. The *tree structure* (the left column) contains all files in the project (organized in groups), as well as some other information.0.1. 0.2. The *detail view* (on the right) is a flat list of all the items in the currently selected group in the tree structure.0.1. 0.2. The area on the bottom right is the *editor*, where you can edit the Objective-C source code. Xcode uses an external program (Interface Builder) as ‘screen painter’; we do not need it in this tutorial. Because Xcode has already created some code for you, you can already try to run the app. If you click the ‘Build and Run’ button in the toolbar, a separate program with an iPhone simulator will start. In a few moments, your app will be launched, showing a blue navigation bar with an empty table that is reminiscent of the Mail app. Our objective will be to populate this table with a list of users from SAP.
Take a few minutes to browse through the various files in the project. The Objective-C source code can be found in files with extensions .h and .m. A .h file contains a class definition; the corresponding .m file contains the implementation of that class. You can see the source code in the editor area. The .xib files contain the screens; they don’t show in the editor, you need to double-click them to open them in another program. The template contains two classes. Class UserListAppDelegate contains a number of methods that are called during the launch of the app and when it closes. Class RootViewController controls the content and the appearance of the table. —- h2. Configuring SAP To get the user list from SAP, we use one of the standard webservices of SAP NetWeaver. The service soap/rfc allows us to call all remote-enabled function modules in SAP. The iPhone app will send an XML message to this service containing the function module name and the parameter. The service will return another XML message with the returning parameters. To check if the soap/rfc service is active, start transaction SICF.
Enter the service name ‘RFC’ and choose Program → Execute (F8). The next screen will show all services named RFC.
Active services, like the selected soap/rfc service, have a black color; inactive services like AIN are greyed out. You can activate a service by selecting it and choosing Service/Host → Activate Service (Shift + F11), or from the context menu of the node. To determine the URL of this service, choose Test Service from the context menu.
Your default internet browser will pop up and load the URL in the address bar. You are also asked for credentials; to use the service, you need to login to SAP with your user and password. If you do, a short error message will be displayed:
Please use either Firefox, Chrome or Safari; Internet Explorer will show a generic error page (500 – Internal Server Error) which is not related to SAP or webservices in general. Don’t worry about this error message; you just sent an empty message to the service and it is not designed to handle that. You can see that the service URL is constructed from the network name of the application server (mtcnasap05.magnus.nl), the port number (8000), the relative address of the service (/sap/bc/soap/rfc) and a parameter indicating the client. —- h2. Calling the service Now it is time to build the app itself. We will do this step by step, so you will have a basic understanding of what is going on. If you are not (yet) interested in learning Objective-C, you can download the source code here (http://www.magnus.nl/documents/UserList.zip) and paste it into your project. For more details, go to the end of the blog (#download).”; // Create SOAP request NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:urlString]]; NSString *msgLength = [NSString stringWithFormat:@”%d”, (soapMessage length)]; [request addValue:@”text/xml; charset=UTF-8″ forHTTPHeaderField:@”Content-Type”]; [request addValue:urlString forHTTPHeaderField:@”SOAPAction”]; [request addValue:msgLength forHTTPHeaderField:@”Content-Length”]; [request setHTTPMethod:@”POST”]; [request setHTTPBody:[soapMessage dataUsingEncoding:NSUTF8StringEncoding]]; // Start connection NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
This code creates an XML message containing the RFC we’re going to call (THUSRINFO, look it up in transaction SE37 if you want) and the table parameter USR_TABL we’re interested in. It then creates a HTTP request with a few parameters that will be sent to the SAP service. The last line of code creates a connection, which sends the request and waits for a response. If the connection has anything to report (like “I need credentials” or “I received some data”), it will call a specific method of its +delegate+. In this case, the delegate is set to self, which is the current object of type UserListAppDelegate. In object-oriented ABAP, this would be the variable ME. You can check that the code contains no errors by choosing Build → Build (Cmd + B). If you have any unsaved files, a dialog will remind you; choose Save All.
A warning will appear in the editor that the variable connection is not used but that is not important (and in fact it isn’t even true). The first problem we face is that the SAP service requires a user and password; we saw this while we were testing the service in transaction SICF. Now, if we run the app, the connection will ask the UserListAppDelegate for credentials, but since it won’t supply any, the connection will be cancelled. To solve this, enter the following lines of code after the method applicationDidBecomeActive: you just changed. This will become a new method, so the code must be put outside the curly brackets. Replace the user (IPHONE) and password (iphone) with your own credentials. – (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge { if ( (challenge previousFailureCount) == 0) { // First time this method is called, supply credentials for request NSURLCredential *credential = [NSURLCredential credentialWithUser:@”IPHONE” password:@”iphone” persistence:NSURLCredentialPersistenceNone]; [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge]; } else { NSLog(@”Wrong user/password for RFC user”); } }
The next task is to collect the data that the connection returns. For this, we need to define instance variables for the data buffer and for the list of user names. Select the file UserListAppDelegate.h in the detail view, and add the lines NSMutableData *webData; NSMutableArray *users; right after the first curly bracket. The list of users must be accessible for the table, so we need to define it as a +property+. After the first closing curly bracket, add the line @property (nonatomic, retain) NSMutableArray *users; The code should now look like this:
Go back to the file UserListAppDelegate.m, and insert the line @synthesize users; just below the other @synthesize statements; this is the counterpart of the @property statement and it will generate getter and setter methods for the property. Also add users = [[NSMutableArray arrayWithCapacity:10] retain]; as the first line of method application:didFinishLaunchingWithOptions:; the code should now look like:
Add the following lines of code after the connection:didReceiveAuthenticationChallenge: method: – (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { webData = [[NSMutableData data] retain]; } – (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { (webData appendData:data); } – (void)connectionDidFinishLoading:(NSURLConnection *)connection { NSString *response = [[NSString alloc] initWithBytes:webData.mutableBytes length:webData.length encoding:NSUTF8StringEncoding]; NSLog(@”%@”, response); } (users removeAllObjects); NSMutableArray *components = [NSMutableArray arrayWithArray:[response componentsSeparatedByString:@””]]; (components removeObjectAtIndex:0); for (NSString *component in components) [users addObject:[[component componentsSeparatedByString:@””] objectAtIndex:0]]; // Refresh the table (((UITableViewController *)navigationController.topViewController).tableView reloadData); h2. Displaying the data The final step is to load the list of users, which is now in the UserListAppDelegate, into the table. In the detail view, select the RootViewController.h file and add the following line NSArray *users; between the curly brackets. This will hold a reference to the same user list as in the UserListAppDelegate class.
Go to the RootViewController.m file and add the line #import “UserListAppDelegate.h” below the other #import statement. Uncomment the viewDidLoad method by deleting the /* before and the
*/after the method, and add the following line after the statement [super viewDidLoad]: users = ((UserListAppDelegate *)[[UIApplication sharedApplication] delegate]).users;
Now, scroll down until you see the method tableView:numberOfRowsInSection:. The number of rows is equal to the number of users, so replace the statement return 0; with return users.count; In the next method, tableView:cellForRowAtIndexPath:, you can define which text should appear in the table. Just after the comment // Configure the cell., insert the following line: cell.textLabel.text = (users objectAtIndex:indexPath.row);
---- h2. Congratulations! Believe it or not, you just made your first working SAP iPhone app! If you run the app now, you will see a list of users, starting with the user you specified in the credentials. You can scroll the list up and down, just as you would expect from the behaviour of other apps.
If you want to refresh the list, just click the Home button and tap on the white glossy icon to activate the app again. Of course, there are a lot of things that can be improved, and some of them are rather easy: 0.1. 0.2. Create a custom icon (57 by 57 pixels) in PNG format. Name it Icon.png, and drag it to the project. If you run the app again, the icon will appear (with rounded corners and glossy effects) on the home screen of your iPhone simulator 0.3. 0.4. In a similar way, you can add a (320 by 480 pixels) PNG image named Default.png to the project. This image will appear during startup of the app, instead of the black screen that appears now. 0.5. 0.6. Displaying a title in the navigation bar; this can be done by including the code self.navigationItem.title = @"User list"; in the method viewDidLoad: in the file RootViewController.m. 0.7. As said before, if you want to run the app on your own iPhone, or even publish it to the App Store, you need to become a member of the iOS Developer program here (http://developer.apple.com/programs/start/standard/). The iOS Development center contains more tutorials about developing iPhone apps, for example this one (http://developer.apple.com/library/ios/#documentation/iPhone/Conceptual/iPhone101/Articles/00_Introduction.html). If you want to see what you can build with the techniques used in this blog, download the free Easy Maintenance app {code:html}here{code}. It allows users to view and create Service Notifications within SAP PM. ---- h2. Using the downloaded source code You can download the source code for this app here (http://www.magnus.nl/documents/UserList.zip). Drag the 4 files from the archive to the Classes folder in the UserList folder, and confirm that you want to replace all of them.
You still have to provide the URL of the service and the credentials. Return to the Xcode window; in the tree structure, select the group Classes; in the detail view, select the file UserListAppDelegate.m and scroll down to line 59. Replace the URL with the one obtained from testing the SAP service.
Scroll further down to line 86, and replace the user (IPHONE) and password (iphone) with your own credentials. ![]()
Working in one of the big consulting companies and seeing the demand for mobile, I start to wonder just how the iOS world works with regards to custom building application for our customers and distributing it. There is some enterprise developer licence option but that seems to be limited only to inhouse developers, creating apps for their own company use. Does anyone know what would be the process of selling custom made enterprise apps that are specific for a particular customer? I still strongly believe that iOS will never be big in the enterprise space (with regards to apps) but if they do allow freedom with distribution that I am not aware of then of course they do have a chance.
Regarding the question that Bjorn has posted that's indeed a challenge for software vendors and system integrators. The way I see it there are three options:
(1) Inhouse / product-based
You develop a iOS app and distribute it as a product to your customers via the Apple App Store. Enterprise Apps on the App Store can often be downloaded for free and license or implementation fees are charged for the backend components without which the App won't work. All the customer specific customizing needs to take place on the backend so that the app can dynamically adapt. In this case the software vendor (more likely) or SI needs to sign up to the "iOS Developer Program".
(2) Inhouse / project-based
You develop an iOS app for a specific customer and distribute it inhouse. In this case the customer (not the SI!) needs to sign up to the "iOS Enterprise Program".
(3) External facing / project-based
You develop an iOS app for a specific customer that they want to make available externally (e.g. to their customers) via the App Store. In this case the customer (not the SI) needs to sign up to the "iOS Developer Program".
Anybody else got any experience around this?
Regards,
Steffen
Also, as far as I know, you can only call one function module via /soap/rfc; then the session is lost. So you can't call a BAPI to create a sales order and have a second call commit it, at least not via /soap/rfc. You have to create a (stateful) webservice yourself or create a custom BAPI.
So there is a lot more to come ...
Hi Gerwin,
Thanks for presentation.
The link for the source code no longer works. Can you send to my email address if you still have them ?
jonathan.keogh@sap.com
Thank you,
Johnny