Skip to Content
SAP Mobile Platform

SAP Precision Marketing iOS SDK

Prerequisites

The following are prerequisites for getting the SDK and Setting Up an SPM Account:
  1. Sign up for a Free Trial account on SDN: http://scn.sap.com/docs/DOC-35829
  2. Once you have accepted the EULA, you will receive your SPM account, developer and consumer id, your private key, and a link from where you can download the SDK.

Getting Started

  1. Setting up your environment.
    1. Download and install XCode 5 from the Mac App store (or via their developer portal)
    2. Download the SPM iOS SDK from the link you received by email
    3. The source includes a .xcodeproj file that you will click to open once you have installed XCode.
    4. Update the developer key/secret in the SDK (in the file classes\Constants.h) to use the ones you received in the previous step.
  2. Running the demos.
    1. Open the XCode project and click the run/arrow button in the top left. This should launch the examples, if not you may have to select the 'iOS-SDK' target and then choose which simulator device you want to run.
  3. Running the unit tests.
    1. XCode 5 has a feature in the left panel to run the tests directly, look for a little diamond icon with a slash in it.

How to Get Offers Using the SPM iOS SDK

Setting up the XCode Project

  1. Create new project with a single view. In the XCode menu, choose File > New > Project.
  2. Provide an appropriate name.
  3. Once the project is created, import the SDK class files (a sub-set is supplied for this example). If you are not running the examples but creating your own app, then perform the following steps and import:
    All of the classes in the Model folder.
    - This folder is the core SDK -- it contains data access objects that are wrappers on the REST services and a simple REST framework that is purpose-built for the SPM backend.
    The Constants.h file.
    - This is optional, you may choose to organize your project in a different way, but it is a useful place to store constants such as the server name, path, key, and secret.
If you would also like to run the UI examples, import the View folder as well. This contains a number of very basic example screens and controllers to get you started.
  1. To import the files, right-click on the Project and select Add Files from the menu.
  2. In the dialog box, select the Model folder from the SPM iOS SDK download, and the Constants.h file. We recommend that you copy these into the project's destination folder.
  3. Your project should look similar to the screenshot below:

Initializing, Registering, and Getting a Session
We recommend initializing in the ViewController to make the example code simpler. However, for a production app you may want to do it asynchronously in the MainAppDelegate and have an activity spinner show on the first screen until the login process is complete. This depends largely up on the user experience of your application. If there is nothing the user can do with the app until login is complete, then you should block the user input until the process is complete. But if the users can continue interacting with the app during the login process, then performing it in the background is sufficient. However, you may need to have child screens react to state changes in the login process.
For Example:

To indicate success, begin the offer loading process. To indicate failure, notify the user by prompting them for credentials.
1. First set up the imports in the view controller implementation that will be needed for this tutorial:

#import "RestClient.h"

#import "Constants.h"

#import "ConsumerContext.h"

#import "RegistrationDao.h"

#import "DeviceProfileParameters.h"

#import "SessionDao.h"

 
2. Next, set up the RestClient and ConsumerContext with the right parameters. Create this method, add it anywhere in the ViewController.m implementationfile and call it from the viewDidLoad method:
@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    [self setupRestClient];
}
... other methods
-(void) setupRestClient {
    ConsumerContext *context = [ConsumerContext sharedInstance];
    context.locale = @"en_US"; // needed by session dao
    [RestClient setDeviceApiHost:@"https://sprdeviceapisstaging.hana.ondemand.com"basePath:@"/deviceapi/v1/rest"];
  [RestClient setApiKey:@"REPLACE_WITH_YOUR_API_KEY" secret:@"REPLACE_WITH_YOUR_API_SECRET"];
}
3. To register and get the session, add the following method to the ViewController.m implementation and call it from the viewDidLoad method:
@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    [self setupRestClient];
    [self registerAnonymousUserAndCreateSession];
}
... other methods
-(void) registerAnonymousUserAndCreateSession {
    ConsumerContext *context = [ConsumerContext sharedInstance];
    [RegistrationDao registerAnonymousConsumerWithParameters:[DeviceProfileParameters constructDefaultProfileDictionaryWithLocation:nil] handler:^(Response *response, NSString *deviceId, NSError *error) {
        context.deviceId = deviceId; // the SessionDao will get this value from the context in the next step
// If you want to avoid registering again the next time the app is launched, save the deviceId to NSUserDefaults and retrieve it upon launch.
         NSLog(@"Registration DAO returned: %@", response.returnCode);
         if([response.returnCode isEqualToString:@"OK"]) {
            SessionDao *sessionDao = [SessionDao anonymousSessionDao];
            NSString *consumerId = [sessionDao createSession];
            context.consumerId = consumerId;// many of the REST services need the consumerId, so store this in the context for later use
            NSLog(@"Called createSession, got back consumerId: %@", consumerId);
     }
  }];
}
@end
4. Getting the session sets up the ConsumerContext object with a valid consumer Id. This will be used on subsequent calls.
5. Ensure the ViewController is set as the initial view of the main app delegate (this should already be done if you used the wizard to create the app).
6. Next, launch the app and test it. You should see the registration and session calls in the console log:
2013-10-07 11:04:25.332 GetOffersTestApp[41801:a0b] POST url [https://sprdeviceapisstaging.hana.ondemand.com/deviceapi/v1/rest/registration/device/anonymous|
https://sprdeviceapisstaging.hana.ondemand.com/deviceapi/v1/rest/registration/device/anonymous]
2013-10-07 11:04:25.334 GetOffersTestApp[41801:a0b] Making async HTTP request...
2013-10-07 11:04:28.672 GetOffersTestApp[41801:a0b] Response: OK
2013-10-07 11:04:28.674 GetOffersTestApp[41801:a0b] Registration DAO returned: OK
2013-10-07 11:04:28.675 GetOffersTestApp[41801:a0b] POST url [
https://sprdeviceapisstaging.hana.ondemand.com/deviceapi/v1/rest/sessions/limited|
https://sprdeviceapisstaging.hana.ondemand.com/deviceapi/v1/rest/sessions/limited]
2013-10-07 11:04:28.675 GetOffersTestApp[41801:a0b] Making async HTTP request...
2013-10-07 11:04:29.181 GetOffersTestApp\[41801:a0b\] Response: OK
2013-10-07 11:04:29.190 GetOffersTestApp[41801:a0b] Called createSession, got back consumerId: ff722f0f-FFFF-AAAA-DDDD-6f0bd2bac075


Getting Offers and Displaying in a Table
To get offers and display them in  a table, perform the following steps:
1. Call the REST service to fetch offers and store them in a local array.
2. Add a table object to the screen in the XCode designer.
3. Implement the appropriate UITableView delegate and datasource methods to use the data in this array.
4. Declare a property in the ViewController interface to store the offers array.
This can be done either in the .h file or .m file. We are doing it in the .m file since it is a private property to this view controller.
5. You will also need a UITableView IBOutlet to wire up in the later steps.
@interface ViewController ()

@property (nonatomic, strong) NSArray *offers;
@property (nonatomic, strong) IBOutlet UITableView *tableView;

@end

6. Add a method -fetchOffersAndRefresh to the view controller and call it after the registration and session have been established.
-(void) fetchOffersAndRefresh {
  ConsumerContext *context = [ConsumerContext sharedInstance];
  OfferDao *dao = [OfferDao offerDaoWithConsumer:context.consumerId];
  dao.radius = 20;
  dao.location = [[CLLocation alloc] initWithLatitude:40.82 longitude:-73.96].coordinate; // New York
  [dao getOffersWithHandler:^(Response *response, NSArray *offers, NSError *error) {
    if ([response.returnCode isEqualToString:@"OK"]) {
      self.offers = offers;
      [self.tableView reloadData]; // only do this if you know the block will be running on the main thread
    } else {
     // handle the error case e.g. pop-up an alert window
    }
  }];
}
7. Since the registration is done asynchronously, we should do this in the completion block after we get the session. Modify the method to make this call:
-(void) registerAnonymousUserAndCreateSession {
   ConsumerContext *context = [ConsumerContext sharedInstance];
   [RegistrationDao registerAnonymousConsumerWithParameters:[DeviceProfileParameters constructDefaultProfileDictionaryWithLocation:nil] handler:^(Response *response, NSString *deviceId, NSError *error) { context.deviceId = deviceId; // the SessionDao will get this value from the context in the next step
  // If you want to avoid registering again the next time the app is launched, save the deviceId to NSUserDefaults and retrieve it upon launch.
  NSLog(@"Registration DAO returned: %@", response.returnCode);
if ([response.returnCode isEqualToString:@"OK"]) {
SessionDao *sessionDao = [SessionDao anonymousSessionDao];
NSString *consumerId = [sessionDao createSession];
context.consumerId = consumerId; // many of the REST services need the consumerId, so store this in the contextfor later use
  NSLog(@"Called createSession, got back consumerId: %@", consumerId);
[self fetchOffersAndRefresh];
} }];
}

8. The last step is to add a UITableView to the main screen and wire it up properly.
Modify the main ViewController so that it is a UITableViewDataSource. We will also set it as a delegate even though this tutorial does not specifically use the delegate methods. If you want to extend the tutorial to respond to clicks and swipes on the table cells, you would need to implement the appropriate methods.
@interface ViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
9. Choose the main storyboard for your application and select the main view. Add a UITableView to the main screen so it fills up the entire screen.
10. Right-click on the ViewController (you may need to expand the left tab). Left-click on the tableView IBOutlet and drag it to wire it to the table view, that you put on the screen.
11. Right-click on the table view and wire up its datasource and delegate back to the ViewController as displayed below:
12. Implement the two table datasource methods:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {

   return [self.offers count];

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {   static NSString *cellIdentifier = @"OfferCell";   UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];   

if (cell == nil) {    

cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];

   }   

Offer *offer = (Offer *)[self.offers objectAtIndex:indexPath.row];   cell.textLabel.text = offer.offerName;   

if (offer.pictureUrl) {    

// Quickie method to keep the example simple. For production code this should be done async or you will run into many    

// scrolling and loading problems. See Apple's LazyTableImages example or use a library like https://github.com/rs/SDWebImage    

// or https://github.com/AFNetworking/AFNetworking   

cell.imageView.image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:offer.pictureUrl]]];

  }   

return cell;

}

13. Compile and run.

Full Source Code

This example assumes the appropriate XIB with a tableView that has been setup and wired correctly.

#import "ViewController.h"

#import "RestClient.h"

#import "ConsumerContext.h"

#import "RegistrationDao.h"

#import "DeviceProfileParameters.h"

#import "OfferDao.h"

#import "Offer.h"

@interface ViewController ()

@property (nonatomic, strong) NSArray *offers;

@property (nonatomic, strong) IBOutlet UITableView *tableView;

@end

@implementation ViewController

- (void)viewDidLoad {    

     [super viewDidLoad];    

     [self setupRestClient];    

     [self registerAnonymousUserAndCreateSession];    

     [self fetchOffersAndRefresh];

}

-(void) setupRestClient {

     ConsumerContext *context = [ConsumerContext sharedInstance];

     context.locale = @"en_US"; // needed by session dao

    [RestClient setDeviceApiHost:@"https://sprdeviceapisstaging.hana.ondemand.com" basePath:@"/deviceapi/v1/rest"];

    [RestClient setApiKey:@"62fef3cf-a14b-4a34-9319-ca7439c1112b" secret:@"iOSsdktest1"];

}

-(void) registerAnonymousUserAndCreateSession {

     ConsumerContext *context = [ConsumerContext sharedInstance];

      [RegistrationDao registerAnonymousConsumerWithParameters:[DeviceProfileParameters constructDefaultProfileDictionaryWithLocation:nil] handler:^(Response *response, NSString *deviceId, NSError *error) {         context.deviceId = deviceId; // the SessionDao will get this value from the context in the next step

      

      // If you want to avoid registering again the next time the app is launched, save the deviceId to NSUserDefaults and retrieve it upon launch.         NSLog(@"Registration DAO returned: %@", response.returnCode);

         if ([response.returnCode isEqualToString:@"OK"]) {

             SessionDao *sessionDao = [SessionDao anonymousSessionDao];

             NSString *consumerId = [sessionDao createSession];

             context.consumerId = consumerId; // many of the REST services need the consumerId, so store this in the context for later use

            NSLog(@"Called createSession, got back consumerId: %@", consumerId);

             [self fetchOffersAndRefresh];

         }

     }];

}

  -(void) fetchOffersAndRefresh {

     ConsumerContext *context = [ConsumerContext sharedInstance];

      OfferDao *dao = [OfferDao offerDaoWithConsumer:context.consumerId];

     dao.radius = 20;

     dao.location = [[CLLocation alloc] initWithLatitude:40.82 longitude:-73.96].coordinate; // New York

    [dao getOffersWithHandler:^(Response *response, NSArray *offers, NSError *error) {

         if ([response.returnCode isEqualToString:@"OK"]) {

             self.offers = offers;

             [self.tableView reloadData]; // only do this if you know the block will be running on the main thread

        } else {

             // handle the error case e.g. pop-up an alert window

        }

     }];

}  

#pragma mark - UITableView delegate and datasource methods

   - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section

{     return [self.offers count];

}

  - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

     static NSString *cellIdentifier = @"OfferCell";

     UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];

      if (cell == nil) {

         cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];     }       Offer *offer = (Offer *)[self.offers objectAtIndex:indexPath.row];     cell.textLabel.text = offer.offerName;

     if (offer.pictureUrl) {

         // Quickie method to keep the example simple. For production code this should be done async or you will run into many

        // scrolling and loading problems. See Apple's LazyTableImages example or use a library like https://github.com/rs/SDWebImage

        // or https://github.com/AFNetworking/AFNetworking

        cell.imageView.image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:offer.pictureUrl]]];

     }     return cell;

}

@end

     
   

No comments