Development of iPhone client application for SharePoint 2013

I welcome all. In this article I will discuss how to develop an iPhone client for Microsoft SharePoint 2013.
Our application will authenticate to SharePoint and read the contents of a list provided by the SharePoint REST API.
Let’s proceed.

Download source code

Preparing the environment

Regarding the deployment environment SharePoint, you can use any version that is comfortable to you deploy SharePoint 2013 to its own server, SharePoint as a virtual machine deployed in Windows Azure, the cloud or in another (eg http://cloudshare.com/).
I have a test environment using SharePoint Online from Office 365.
Our mobile app will display a list of photos, so add the test data for this list.
Point your browser to one of the sites of site collection, which will include a list of photos. In my case it https://dmitrykomin-public.sharepoint.com/
In the administration panel, click Site Settings.
A10_1-01
Then, in the right pane, select the Site Contents.
A10_1-02
Site Contents page opens showing among other things a lists of the site. Select Photos list.
A10_1-03
Add to the list a few photos.
A10_1-04

Authentication

SharePoint 2013 supports Claims-based authentication, which means that you can configure SharePoint 2013, so that the user can authenticate through diversity of Identity Providers: Facebook, Google, Windows Live ID, Yahoo, etc.
The mechanism of Claims-based authentication is based on the fact that actually all authentication-related work is performed by Identity Provider. After successful authentication, the user in exchange for their certificates receives specific security token from Security Token Service. This token is then used to access the application that checks the token and receives based on it claims, that is, information about a particular user is specific to each Identity Provider.
More on Claims-based authentication is here: http://social.technet.microsoft.com/wiki/contents/articles/14214.sharepoint-2013-claims-based-authentication.aspx
The feature of this authentication mechanism in SharePoint is that all these actions to get security token are made automatically based on HTTP redirects, provided that the client application – a Web browser. Security token is stored in browser cookies.
But what can we do if we want to use the iPhone as a mobile app client for SharePoint?
It’s simple – we use the UIWebView class to create a view in the iPhone browser application, and to authenticate the browser get the security token, will continue to communicate with SharePoint REST API passing the security token stored in cookies HTTP-request.
(It is technically possible to write an authentication code without using UIWebView fully emulating the behavior of the browser, handling HTTP-redirect yourself, create your own views for entering user credentials, etc. Compared with the decision based on the browser, this approach is very difficult. If you for some reasons need this authentication method, let me know and I will discuss this approach in a future article.)
Now let’s move on to the development of mobile applications.
Start the development environment Xcode. Select Create a new Xcode project. As a template of a new project, select Single View Application.
A10_1-05
Specify the name of the project, for example SPConnectTest.
Create a controller for authentication. Run the command File->New->File… As a new template file, select Objective-C class.
A10_1-06
Specify the name of the new class LoginViewController, in the Subclass of select UIViewController.
Open the file LoginViewController.h and enter the following code:

@interface LoginViewController : UIViewController 
{
    IBOutlet UIWebView * webView;
}
@property (nonatomic, retain) IBOutlet UIWebView *webView;
- (void)loadSharePointList : (NSHTTPCookie *) rtFaCookie : (NSHTTPCookie *) fedAuthCookie;
- (void)verifyCookies;
@end

Now open MainStoryboard_iPhone.storyboard.
Storyboard editor opens. In the right pane, locate Web View component in Objects section and drag it to an existing (it is displayed as iPhone screen).
A10_1-07
In View Controller Scene select View Controller. In the right pane in the Class box, select LoginViewController.
A10_1-08
Now right-click on the View Controller, find our variable webView there and drag link from it to the Web view in the workspace of Storyboard editor.
A10_1-09
Open LoginViewController.m file. Add the following code:

@implementation LoginViewController
@synthesize webView;
- (void)viewDidLoad
{
    [super viewDidLoad];
    self.webView.delegate = self;
    NSString* authUrl = @"https://dmitrykomin-public.sharepoint.com/_layouts/15/authenticate.aspx?Source=/";
    [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString: authUrl]]];
}
-(void)webViewDidStartLoad:(UIWebView *)webView {
    [self verifyCookies];
}
-(void)webViewDidFinishLoad:(UIWebView *)webView {
    [self verifyCookies];
}
- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
}
- (void)verifyCookies
{
    __weak NSHTTPCookie * rtFaCookie = nil;
    __weak NSHTTPCookie * fedAuthCookie = nil;
    NSHTTPCookieStorage *storage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
    NSArray *cookiesArray = [storage cookies];
    for (NSHTTPCookie *cookie in cookiesArray) {
        if ([[cookie name] isEqualToString:@"FedAuth"]) {
            fedAuthCookie = cookie;
            continue;
        }
        if ([[cookie name] isEqualToString:@"rtFa"]) {
            rtFaCookie = cookie;
            continue;
        }
    }
    if(rtFaCookie != nil && fedAuthCookie != nil){
        [self loadSharePointList : rtFaCookie : fedAuthCookie];
    }
}
- (void)loadSharePointList : (NSHTTPCookie *) rtFaCookie : (NSHTTPCookie *) fedAuthCookie
{
}
@end

Now look at what the code does. In the handler, viewDidLoad, which is called when loading the view, we perform a web request to the authentication URL of our website. After the user enters his credentials, a series of HTTP-redirects are performed, after each of HTTP-redirect webViewDidStartLoad webViewDidFinishLoad methods are invoked. In these methods, we call verifyCookies, that checks the security token in the cookies (“rtFa” and “FedAuth” cookies). If securityToken has obtained, we call loadSharePointList, that in the future will load the contents of our SharePoint list.
It’s time to run our application. Click Run. If all is done correctly, in the iOS Simulator you should see the following:
A10_1-10
Set breakpoint in loadSharePointList method, then switch to iOS Simulator window, enter the user’s credentials and then click on the Sign in link. After a while you will get into the method loadSharePointList. Thus, we have successfully implemented authentication in SharePoint.

Receiving data from REST API

Let’s emphasize main points of communication with the SharePoint 2013 REST API, since I can not bring all the code. You can see it by downloading a demo example for this article.
To communicate with the SharePoint 2013 REST API, I wrote a class SPRestClientRequest. Here’s the code:
SPRestClientRequest.h:

@interface SPRestClientRequest : NSObject
{
    __weak NSHTTPCookie * rtFaCookie;
    __weak NSHTTPCookie * fedAuthCookie;
}
- (id) initWithCookies : (NSHTTPCookie *) rtFa : (NSHTTPCookie *) fedAuth;
- (NSDictionary *) sendRequest : (NSString*) requestUrl;
@end

SPRestClientRequest.m:

@implementation SPRestClientRequest
- (id) initWithCookies : (NSHTTPCookie *) rtFa : (NSHTTPCookie *) fedAuth
{
    if(self = [super init])
    {
        rtFaCookie = rtFa;
        fedAuthCookie = fedAuth;
    }
    return self;
}
- (NSDictionary *) sendRequest : (NSString*) requestUrl
{
    NSURL *url = [NSURL URLWithString:requestUrl];
    NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:url];
    NSArray* cookieArray = [NSArray arrayWithObjects: rtFaCookie, fedAuthCookie, nil];
    NSDictionary * cookieHeaders = [NSHTTPCookie requestHeaderFieldsWithCookies:cookieArray];
    NSMutableDictionary * requestHeaders = [[NSMutableDictionary alloc] initWithDictionary: cookieHeaders];
    [requestHeaders setObject: @"application/json;odata=verbose" forKey: @"Accept"];
	[theRequest setHTTPMethod:@"GET"];
    [theRequest setAllHTTPHeaderFields:requestHeaders];
	NSURLResponse *response;
	NSError *error;
	NSData *data = [NSURLConnection sendSynchronousRequest:theRequest returningResponse:&response error:&error];
	if (data) {
		NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
		NSLog(@"%@", jsonString);
		return [jsonString JSONValue];
	}
    return nil;
}
@end

As you can see, sendRequest method generates HTTP-request, executes it and returns the result as JSON.
In addition to this class, I wrote a number of classes that create a simple object model to work with the API: SPListCollection, SPList, SPListItem.
For an example, here is the code of SPListCollection:
SPListCollection.h:

@interface SPListCollection : SPRestClientRequest
- (NSDictionary *) getAllItems;
- (NSDictionary *) getItemByEntityType : (NSString *) entityType;
@end

SPListCollection.m:

@implementation SPListCollection
- (NSDictionary *) getAllItems
{
    NSDictionary * jsonValue = [super sendRequest:@"https://dmitrykomin-public.sharepoint.com/_api/web/lists"];
    return [[jsonValue objectForKey:@"d"] objectForKey:@"results"];
}
- (NSDictionary *) getItemByEntityType : (NSString *) entityType
{
    NSDictionary *jsonResults = [self getAllItems];
    for (NSDictionary *jsonResult in jsonResults) {
        NSString *entityTypeName = [jsonResult objectForKey:@"EntityTypeName"];
        if([entityTypeName isEqualToString: entityType]){
            return jsonResult;
        }
    }	
    return nil;
}
@end

This class, like others, simply makes a request to a specific SharePoint REST endpoint and parses the result of the call.
Full documentation on SharePoint 2013 REST API, we can find it here: http://msdn.microsoft.com/en-us/library/jj860569.aspx#Reference

Loading the photos from SharePoint 2013 list

Now, having object model for the REST API, let’s load the data from the list of SharePoint 2013.
Add a new Objective-C class named PhotosListManager. Open PhotosListManager.h file and add the following code:

@interface PhotosListManager : NSObject
{
    __weak NSHTTPCookie * rtFaCookie;
    __weak NSHTTPCookie * fedAuthCookie;
}
- (id) initWithCookies : (NSHTTPCookie *) rtFa : (NSHTTPCookie *) fedAuth;
- (NSArray *) loadItems;
@end

Open PhotosListManager.m file and add the following code:

@implementation PhotosListManager

- (id) initWithCookies : (NSHTTPCookie *) rtFa : (NSHTTPCookie *) fedAuth
{
    if(self = [super init])
    {
        rtFaCookie = rtFa;
        fedAuthCookie = fedAuth;
    }
    return self;
}

- (NSArray *) loadItems
{
    NSMutableArray * loadedItems = [[NSMutableArray alloc] init];
    SPListCollection * listCollection = [[SPListCollection alloc] initWithCookies : rtFaCookie : fedAuthCookie];
    NSDictionary * listMeta = [listCollection getItemByEntityType : @"PhotosList"];
    if(listMeta != nil){
        NSDictionary * photosMetas = [[[SPList alloc] initWithMetadataAndCookies : listMeta : rtFaCookie : fedAuthCookie] getAllItems];
        for (NSDictionary *photoMeta in photosMetas) {
            NSDictionary * metadata = [photoMeta objectForKey : @"__metadata"];
            NSDictionary * fieldValues = [[[SPListItem alloc] initWithMetadataAndCookies : photoMeta : rtFaCookie : fedAuthCookie] fieldValuesAsText];
            if(metadata != nil && fieldValues != nil) {
                ListItemDto * listItem = [[ListItemDto alloc] init];
                
                listItem.id = [metadata objectForKey : @"id"];
                listItem.uri = [metadata objectForKey : @"uri"];
                listItem.type = [metadata objectForKey : @"type"];
                
                listItem.title = [fieldValues objectForKey : @"Title"];
                if(listItem.title == nil || [listItem.title isEqualToString : @""]){
                    listItem.title = [fieldValues objectForKey : @"FileLeafRef"];
                }
                
                listItem.created = [photoMeta objectForKey : @"Created"];
                
                NSMutableDictionary * attributes = [[NSMutableDictionary alloc] init];
                [attributes setObject: [fieldValues objectForKey : @"FileLeafRef"] forKey: @"FileLeafRef"];
                [attributes setObject: [fieldValues objectForKey : @"FileRef"] forKey: @"FileRef"];
                
                NSString * fileUrl = [[AppSettings SiteUrl] stringByAppendingString : [fieldValues objectForKey : @"FileRef"]];
                [attributes setObject: fileUrl forKey: @"FileUrl"];
                
                listItem.attributes = attributes;
                
                [loadedItems addObject: listItem];
            }
        }
    }
    return loadedItems;
}
@end

Our manager-class loads the information about the photos and returns a list of ListItemDto (serves as kinda of View Model).

Displaying information in UITableView

Now that we’ve loaded our pictures let’s display them in the list. For this we will use UITableView class, more precisely it would be the controller based on UITableView (UITableViewController).
Add a new Objective-C class named SPListViewController. Specify ‘UITableViewController’ class in Subclass of box.
Open SPListViewController.h file and add the following code:

@interface SPListViewController : UITableViewController
{
    __weak NSHTTPCookie * rtFaCookie;
    __weak NSHTTPCookie * fedAuthCookie;
    NSArray * tableData;
}
- (id) initWithCookies : (NSHTTPCookie *) rtFa : (NSHTTPCookie *) fedAuth;
@end

Open SPListViewController.m file and add the following code:

@implementation SPListViewController

- (id) initWithCookies : (NSHTTPCookie *) rtFa : (NSHTTPCookie *) fedAuth
{
    self = [super initWithNibName: nil bundle: nil];
    if (self) {
        rtFaCookie = rtFa;
        fedAuthCookie = fedAuth;
    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    PhotosListManager * photosListMgr = [[PhotosListManager alloc] initWithCookies: rtFaCookie : fedAuthCookie];
    tableData = [photosListMgr loadItems];
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
}

#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return [tableData count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[PhotoItemCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier];
    }
    ListItemDto * listItem = [tableData objectAtIndex:indexPath.row];
    NSString* imageUrl = [listItem.attributes objectForKey : @"FileUrl"];

    cell.textLabel.text = listItem.title;
    cell.imageView.image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:imageUrl]]];
    return cell;
}
@end

In the viewDidLoad method, we just say our manager to load photos. In numberOfRowsInSection method we return the number of elements in the section (for us it would be number of photos). In CellForRowAtIndexPath method we create a list item. Here, we simply assign the photo title and image data to corresponding properties of UITableViewCell item.
Almost done. It remains only to perform switching to SPListViewController after successfull authentication in SharePoint 2013. Open LoginViewController.m file and add the following code to the loadSharePointList method:

- (void)loadSharePointList : (NSHTTPCookie *) rtFaCookie : (NSHTTPCookie *) fedAuthCookie
{
    [[self webView] setHidden:YES];
    SPListViewController * listView = [[SPListViewController alloc] initWithCookies: rtFaCookie : fedAuthCookie];
    listView.title = @"List Content";
    
    UINavigationController * navigationController = [[UINavigationController alloc] initWithRootViewController:listView];
    [self presentViewController : navigationController animated:YES completion: nil];
}

That’s it! Run the application. After you enter the user’s credentials and push Sign in button, you should get the following:
A10_1-11

Thank you for reading. Any comments and suggestions would be really appreciated.

Download source code

3 comments

  1. Thanks for your valuable infomrations, It would be really helpful about mobile Applications development. Am working in Mobile applications developmentcompany bangalore, Thanks for your blog informations, keep posting informations always.

    1. Thank you. Glad to hear that article is helpfull for you.

  2. Prashanth · · Reply

    Hi.. Do you have an update source code please. I am trying.. It opens a blank page in the simulator. I am new to mobile development

Leave a comment