Getting Started with the xAPI iOS SDK, Part 1 of 2

Learn How to Integrate, Configure, and Retrieve Statements from the xAPI iOS SDK in Your Project

Experience API, Mobile Development Comments (8)

Note: Since this post was originally written, it has been updated to reflect the changes made in the SDK with the official 1.0.0 release of the xAPI specification.

We’ve been discussing the Experience API (xAPI) a lot recently. To say we’re excited about it would be an understatement. We’ve enjoyed working on it and implementing it within our own Tappestry application.

A few months ago, we released the first version of our xAPI iOS SDK following the 0.9 version of the specification. This week, we’re updating the SDK for the 0.95 version of the specification and we want to help get you started implementing the SDK into your apps.

The core of the Experience API is the reporting and reviewing of statements, so that is what we’re going to focus on. Although I’m only going to show you some basic ways to send and receive statements using the iOS SDK, the SDK supports all of the other xAPI features as well (including the Activity State, Activity Profile and Agent Profile APIs).

Starting Point

We’re going to build an app that allows a user to share a link to an LRS, as well as view the last 20 statements reported to the LRS.

First things first — we need to set up a new project. Create a new, tab-based project that uses automated reference counting and the iOS storyboard. Replace the view controller on the second tab with a UITableViewController and name it StatementTableViewController. On the view controller for the first tab, add two UITextField‘s and a UIButton. Create properties (urlField and emailAddressField) for the two text fields and an action (bookmarkAction) for the button.

I’ve already got the project started for you, so if you don’t want to make it yourself, you can download the starting point.

1. Integrate xAPIKit.framework into your project

The first step to using the xAPI iOS SDK in our app is to add the framework to our project. If you don’t already have the framework, you can download a trial version from here. (The trial version is completely functional, however it will expire a few months from now.)

Drag and drop the xAPIKit.framework folder into the Frameworks group of your Xcode project. I recommend enabling the Copy items into destination group’s folder checkbox when Xcode asks how you would like to add the file.

Screen-Shot-2013-07-19-at-1.52.43-PM

Next, we need to add the -ObjC linker flag to our build settings. Go to the Build Settings tab and search for Other Linker Flags (OTHER_LDFLAGS). Add -ObjC.

objcflag

Finally, we need to add the SystemConfiguration.framework and Security.framework libraries to the application. Go to the Build Phases tab, open the Link Binary With Libraries section, and click the add button. Find SystemConfiguration.framework and and Security.framework in the list and add it. Once added, verify that your Link Binary with Libraries section looks something like this:

Screen-Shot-2013-07-19-at-1.53.22-PM

2. Configure the xAPI iOS SDK

By default, the xAPI iOS SDK will only report to one LRS. We need to configure the URL and access information for the LRS. The best place to do this is within your application:didFinishLaunchingWithOptions: method of your application delegate file.

Open the AppDelegate.m file and import the xAPIKit headers by adding:

#import <xAPIKit/xAPIKit.h>

Now find the application:didFinishLaunchingWithOptions: method and at the top, add the following:

[EXPAPI configureDefaultAPIWithLRS:[NSURL URLWithString:@"https://cloud.scorm.com/ScormEngineInterface/TCAPI/public/"]
authorizationProvider:[[EXPBasicHTTPAuthentication alloc] initWithUsername:@"public" andPassword:@""]];

This will configure the SDK to use the public xAPI endpoint provided by Rustici. Feel free to use any endpoint you want. Just be sure to set the username and password.

We have successfully added and configured the SDK. Now we’re free to use it in our project!

3. Retrieving Statements from the LRS

We’ll start with the table view on the second tab of our project. We’re going to populate the table with statements from the LRS. We’ll start simple and just get the last 20 statements.

Just as with the application delegate, we need to import the xAPIKit headers. Let’s do this in the header file (StatementTableViewController.h). Let’s also declare that we’re implementing the protocolEXPAPIStatementRequestDelegate so that we can look at the statements we get back from the LRS.

Your header file will look something like this:

#import <xAPIKit/xAPIKit.h>
@interface StatementTableViewController : UITableViewController <EXPAPIStatementRequestDelegate>
@end

Now back to the implementation file (StatementTableViewController.m). Just before the view appears, we want to get the last 20 statements back from the LRS. Find the viewWillAppear: (or create it) method and add:

[[EXPAPI defaultAPI] getStatementWithQuery:[EXPStatementQuery statementQueryWithLimit:20] delegate:self];

This creates a query and sends it to the LRS. You can use EXPStatementQuery to specify a number of parameters when querying the LRS. For example, let’s say you only wanted statements for an actor with the email address test@example.com.

// Creates a new query for the LRS
EXPStatementQuery *query = [EXPStatementQuery new];
// Specifies that the query should only look for agents with the email address test@example.com
query.actor = [EXPAgent agentWithName:nil andMbox:@"test@example.com"];
// Sends the query to the LRS
[[EXPAPI defaultAPI] getStatementWithQuery:query delegate:self];

This will immediately send the request to the LRS. This is an “asynchronous” operation, meaning that your application will continue to run while the SDK works in the background to handle the response from the LRS. However, we want the view controller to know when the statements are ready. When we issued the request, we specified that self (the view controller) would be the delegate of the request. In order to handle the response, we need to implement a few methods defined in the EXPAPIStatementRequestDelegate protocol. The two main ones to implement are:

  • -request:didFailWithError: (in case something goes wrong), and
  • -statementsReceived: (for when the statements are ready for us to look at).

Inside our -request:didFailWithError: method, let’s simply pop open an alert with the error message.

- (void) request:(EXPAPIRequest *)request didFailWithError:(NSError *)error
{
[[[UIAlertView alloc] initWithTitle:error.localizedDescription message:nil delegate:self cancelButtonTitle:@"OK" otherButtonTitles: nil] show];
}

Next, inside our -statementsReceived: method, let’s (for now) just print a log statement of how many statements we got back.

- (void) statementsReceived:(EXPStatementsResult *)result
{
NSLog(@"Number of statements: %d", result.numberOfStatements);
}

Let’s run the app, go to the second tab, and check the console. Hopefully, we’ll see something like this: Number of statements: 20. Since we asked for 20 statements, it makes sense that we would get 20 statements in return.

Now, let’s look at how to populate the table view with these statements.

In our -statementsReceived: method, let’s store the EXPStatementsResult object in a property on our view controller so we can access it in other methods. And let’s also tell the table view to reload its data.

- (void) statementsReceived:(EXPStatementsResult *)result
{
self.result = result;
[self.tableView reloadData];
}

Now, let’s implement the methods of the table view. For number of sections, let’s just return 1. For number of rows, let’s return the value of self.result.numberOfStatements. Then for each cell, let’s find the statement for that row, and set the cell’s text to the description:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// There is only 1 section in our table.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// We want one row for every statement we get back from the LRS.
return self.result.numberOfStatements;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];

// Find the statement for this row
EXPStatement *statement = [self.result.statements objectAtIndex:indexPath.row];
// And set the cell's content to the statement's description
cell.textLabel.text = statement.description;

return cell;
}

Now run the application and after a few moments, you’ll see the first 20 statements come back and appear in the table. Hooray!

In my next post, we’ll look at creating statements. Until then, check out the xAPI Statement Viewer on the iOS App Store to see another small example of what the xAPI iOS SDK can do. Better yet, go download the demo version of the SDK and try it out for yourself.




If you have liked this tutorial to this point or want more examples, let us know in the comments. If you’re using the SDK, let us know what kind of statements you’re creating with the xAPI iOS SDK and how we can make the SDK better.

Follow Float
The following two tabs change content below.

» Experience API, Mobile Development » Getting Started with the xAPI...
On December 5, 2012
By
,

8 Responses to Getting Started with the xAPI iOS SDK, Part 1 of 2

  1. Steve says:

    Loving this walk through, but stumbling in my implementation. Have built as far as logging the number of results. Code builds find and launches in the simulator. But when I select the statement tab I get an exception.

    2013-02-15 20:23:28.993 Tin Can Bookmarker[22023:c07] -[NSURL URLByAppendingQueryWithDictionary:]: unrecognized selector sent to instance 0x719c760
    2013-02-15 20:23:28.996 Tin Can Bookmarker[22023:c07] *** Terminating app due to uncaught exception ‘NSInvalidArgumentException’, reason: ‘-[NSURL URLByAppendingQueryWithDictionary:]: unrecognized selector sent to instance 0x719c760’
    *** First throw call stack:
    (0x1355012 0x117ae7e 0x13e04bd 0x1344bbc 0x134494e 0xd8c8 0x8988 0x8903 0x2c51 0x1a2103 0x1a242b 0x1aff80 0x1c194a 0x1c1704 0x1bfbda 0x1bfa5c 0x1c1647 0x118e705 0xc22c0 0xc2258 0x2e4ff4 0x118e705 0xc22c0 0xc2258 0x183021 0x18357f 0x183056 0x2e8af9 0x118e705 0xc22c0 0xc2258 0x183021 0x18357f 0x1826e8 0xf1cef 0xf1f02 0xcfd4a 0xc1698 0x2298df9 0x2298ad0 0x12cabf5 0x12ca962 0x12fbbb6 0x12faf44 0x12fae1b 0x22977e3 0x2297668 0xbeffc 0x248d 0x23b5)
    libc++abi.dylib: terminate called throwing an exception
    (lldb)

    Originally trying with my own tin can key. Changed to the standard/public one but still getting the same error.

    What step did I miss?

    • Daniel Pfeiffer says:

      Hi Steve,

      I’m guessing that you’re missing -ObjC in your Build Settings.
      Go to your target settings, then to the Build Settings tab. Search for “Other Linker Flags” and make sure that you have -ObjC added.

      I hope that helps!
      Thanks,
      –Dan

      • Steve says:

        Daniel.

        Thanks. You nailed it.

        I’d added the setting but typed as -objC. Changed to -ObjC and worked fine.

        Onto part 2!!

  2. Mike says:

    Does your SDK deal with content running whilst offline: the ability to store API calls and resend to the LRS when the device next connects?

    • Daniel Pfeiffer says:

      Hi Mike,

      Yes, the SDK does have an offline queue that will persist the statements locally on the device (even across application launches) and attempt to persist them to the LRS whenever it becomes available. If you download the Tin Can Statement Viewer app from the app store (which is built on the SDK), you can preview this feature by using the app while the device is in Airplane mode. You’ll see that any created statements are stored in a queue. Then, switch to online mode and the statements will be sent to the LRS.

      Thanks!
      –Dan

  3. Jawad says:

    Is there any version of xAPI available for android too?

Leave a Reply

Your email address will not be published. Required fields are marked *

« »