I’ve been working with in-app purchases, and would like to share a little of what I’ve found. Today I present a simple view controller that displays the contents of an in-app store. There’s a lot missing from it (e.g., you can’t see detailed descriptions of items, or, ahem, buy anything) but it does demonstrate how you might present a storefront to a user.
Code
Here’s the view controller’s header:
#import <UIKit/UIKit.h>
#import <StoreKit/StoreKit.h>
@interface Store : UIViewController <UITableViewDataSource, UITableViewDelegate, SKProductsRequestDelegate>
{
SKRequest* request;
NSArray* products;
NSNumberFormatter* priceFormatter;
UITableView* tableView;
UIView* loadingView;
}
@property (nonatomic, retain) IBOutlet UITableView* tableView;
@property (nonatomic, retain) IBOutlet UIView* loadingView;
@end
… and its implementation file:
#import "Store.h"
@interface Store ()
@property (nonatomic, retain) SKRequest* request;
@property (nonatomic, retain) NSArray* products;
@property (nonatomic, retain, readonly) NSNumberFormatter* priceFormatter;
- (void)dismiss;
@end
@implementation Store
@synthesize request;
@synthesize products;
@synthesize tableView;
@synthesize loadingView;
- (NSNumberFormatter*)priceFormatter
{
if (!priceFormatter)
{
priceFormatter = [[NSNumberFormatter alloc] init];
priceFormatter.formatterBehavior = NSNumberFormatterBehavior10_4;
priceFormatter.numberStyle = NSNumberFormatterCurrencyStyle;
}
return priceFormatter;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.navigationItem.leftBarButtonItem = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(dismiss)] autorelease];
self.title = @"Store";
NSArray* a = [NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Products" ofType:@"plist"]];
self.request = [[[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithArray:a]] autorelease];
self.request.delegate = self;
[self.request start];
}
- (void)dealloc
{
[request cancel];
[request release];
[products release];
[priceFormatter release];
[tableView release];
[loadingView release];
[super dealloc];
}
#pragma mark Table view data source methods
- (NSInteger)numberOfSectionsInTableView:(UITableView*)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section
{
return [products count];
}
- (UITableViewCell*)tableView:(UITableView*)aTableView cellForRowAtIndexPath:(NSIndexPath*)indexPath
{
static NSString* CellIdentifier = @"Cell";
UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
}
SKProduct* product = [products objectAtIndex:indexPath.row];
NSNumberFormatter* pf = self.priceFormatter;
pf.locale = product.priceLocale;
cell.textLabel.text = product.localizedTitle;
cell.detailTextLabel.text = [pf stringFromNumber:product.price];
return cell;
}
#pragma mark Table view delegate methods
- (NSIndexPath*)tableView:(UITableView*)tableView willSelectRowAtIndexPath:(NSIndexPath*)indexPath
{
return nil;
}
#pragma mark Products request delegate methods
- (void)productsRequest:(SKProductsRequest*)aRequest didReceiveResponse:(SKProductsResponse*)response
{
self.request = nil;
self.products = response.products;
[self.tableView reloadData];
self.loadingView.hidden = YES;
}
#pragma mark Extension methods
- (void)dismiss
{
[self.navigationController.parentViewController dismissModalViewControllerAnimated:YES];
}
@end
Naturally, you’ll also need a NIB. Note that this code assumes that your project includes a Products.plist
file, which encodes an NSArray
of product IDs as NSStrings
of the form com.yourcompany.yourapp.someproductid
.
Finally, the code assumes that it’s running inside a modal navigation controller; this is relevant to the implementation of dismiss
.
Resources
If you’re working with in-app purchases, you should read the “In App Purchase Programming Guide“, particularly the sections on “Adding a Store to Your Application” and “Testing a Store“. You should should also check the relevant sections of the “iTunes Connect Developer Guide“.