Click here to Skip to main content
15,867,488 members
Articles / Mobile Apps / iPhone

Development of iPhone client application for SharePoint 2013

Rate me:
Please Sign up or sign in to vote.
5.00/5 (7 votes)
3 Apr 2013CPOL6 min read 58.3K   1K   11   9
How to write iPhone application to authenticate to SharePoint and read the contents of a list provided by the SharePoint REST API.

Introduction

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.

Preparing the environment 

Regarding the deployment of SharePoint environment, you can use any way that is comfortable. You can deploy SharePoint 2013 on your own server, or SharePoint as a virtual machine deployed in Windows Azure, or in another cloud (e.g. 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. Open one of the sites of site collection in your browser, which will include a list of photos. In my case it is https://dmitrykomin-public.sharepoint.com/. In administration panel click Site Settings link.   

Image 1

Then, in the right pane, click Site Contents link.

Image 2

Site Contents page opens showing site lists among other things. Click Photos list.

Image 3

Add a few photos to the list .

Image 4

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 his credentials receives specific security token from Security Token Service. This token is then used to access the application that checks the token and obtains claims based on it, that is, information about a particular user is specific for 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, which are performed by web browser. Security token is stored in browser cookies. But what can we do if we want to use the iPhone as a mobile client application for SharePoint? It’s simple – we use the UIWebView class to create a browser view in the iPhone application, and to authenticate user in browser to get the security token, and then it allows to communicate directly with SharePoint REST API passing the security token obtained from cookies of HTTP-request. (It is technically possible to write an authentication code without using UIWebView fully emulating the behavior of the browser, handling HTTP-redirect by yourself, create your own views for entering user credentials, etc. Compared with the solution based on the browser, this approach is very difficult. If you for some reasons need this authentication method, please let me know and I will discuss this approach in a future article.) Now let’s move on to the development of mobile application. Start the development environment Xcode. Select Create a new Xcode project. As a template of a new project, select Single View Application.  


Image 5

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.

Image 6

Specify the name of the new class LoginViewController, in the Subclass of select UIViewController. Open the file LoginViewController.h and enter the following code:

C#
@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).

Image 7

In View Controller Scene select View Controller. In the right pane in the Class box, select LoginViewController.

Image 8

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.

Image 9

Open LoginViewController.m file. Add the following code:

C#
@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:

Image 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:

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

SPRestClientRequest.m:

C#
@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:

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

SPListCollection.m:

C#
@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:

C#
@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:

C#
@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:

C#
@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:

C#
@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:

C#
- (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:

Image 11

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

History

  • April 03 2013: Initial publication.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
Russian Federation Russian Federation
I’m software developer experienced with Microsoft technologies (preferably ASP.NET, Microsoft SQL Server, Microsoft SQL Server Reporting Services, Microsoft SharePoint). Overall IT experience is over 9 years.

LinkedIn: http://ru.linkedin.com/in/dmitriykomin
Email: dkomin85@gmail.com
Skype: dkomin85

Comments and Discussions

 
QuestionNSURLSession/NSURLConnection HTTP load failed (kCFSTreamErrorDomainSSL. -9802) Pin
Member 1257076212-Jul-16 5:17
Member 1257076212-Jul-16 5:17 
QuestionImplementation without using UIWebView Pin
Member 117496899-Jun-15 20:38
Member 117496899-Jun-15 20:38 
GeneralMy vote of 5 Pin
Tomas Malek18-Jan-15 17:26
Tomas Malek18-Jan-15 17:26 
QuestionThe million dollar question Pin
Member 1035294322-Oct-13 9:33
Member 1035294322-Oct-13 9:33 
AnswerRe: The million dollar question Pin
Member 1133031422-Jan-15 23:21
Member 1133031422-Jan-15 23:21 
QuestionHow to authenticate using Windows auth Pin
EfrenCA12-Sep-13 11:57
EfrenCA12-Sep-13 11:57 
QuestionXcode dependency Pin
Member 97004817-Aug-13 20:01
Member 97004817-Aug-13 20:01 
AnswerRe: Xcode dependency Pin
Komin Dmitry7-Aug-13 20:27
Komin Dmitry7-Aug-13 20:27 
GeneralMy vote of 5 Pin
Ștefan-Mihai MOGA10-May-13 18:34
professionalȘtefan-Mihai MOGA10-May-13 18:34 
This is a great inspiring article. I am pretty much pleased with your good work. You put really very helpful information. Keep it up once again.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.