Files
phonegap-plugins/iOS/InAppPurchaseManager/InAppPurchaseManager.m

262 lines
8.7 KiB
Objective-C

//
// InAppPurchaseManager.m
// beetight
//
// Created by Matt Kane on 20/02/2011.
// Copyright 2011 Matt Kane. All rights reserved.
//
#import "InAppPurchaseManager.h"
// Help create NSNull objects for nil items (since neither NSArray nor NSDictionary can store nil values).
#define NILABLE(obj) ((obj) != nil ? (NSObject *)(obj) : (NSObject *)[NSNull null])
// To avoid compilation warning, declare JSONKit and SBJson's
// category methods without including their header files.
@interface NSArray (StubsForSerializers)
- (NSString *)cdvjk_JSONString;
- (NSString *)cdvjk_JSONRepresentation;
@end
// Helper category method to choose which JSON serializer to use.
@interface NSArray (cdvjk_JSONSerialize)
- (NSString *)cdvjk_JSONSerialize;
@end
@implementation NSArray (cdvjk_JSONSerialize)
- (NSString *)cdvjk_JSONSerialize {
return [self respondsToSelector:@selector(cdvjk_JSONString)] ? [self cdvjk_JSONString] : [self cdvjk_JSONRepresentation];
}
@end
@implementation InAppPurchaseManager
-(void) setup:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options {
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
}
- (void) requestProductData:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options
{
if([arguments count] < 3) {
return;
}
NSLog(@"Getting product data");
NSSet *productIdentifiers = [NSSet setWithObject:[arguments objectAtIndex:0]];
SKProductsRequest *productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productIdentifiers];
ProductsRequestDelegate* delegate = [[[ProductsRequestDelegate alloc] init] retain];
delegate.command = self;
delegate.successCallback = [arguments objectAtIndex:1];
delegate.failCallback = [arguments objectAtIndex:2];
productsRequest.delegate = delegate;
[productsRequest start];
}
/**
* Request product data for the productIds given in the option with
* key "productIds". See js for further documentation.
*/
- (void) requestProductsData:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options
{
if([arguments count] < 1) {
return;
}
NSSet *productIdentifiers = [NSSet setWithArray:[options objectForKey:@"productIds"]];
NSLog(@"Getting products data");
SKProductsRequest *productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productIdentifiers];
BatchProductsRequestDelegate* delegate = [[[BatchProductsRequestDelegate alloc] init] retain];
delegate.command = self;
delegate.callback = [arguments objectAtIndex:0];
productsRequest.delegate = delegate;
[productsRequest start];
}
- (void) makePurchase:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options
{
NSLog(@"About to do IAP");
if([arguments count] < 1) {
return;
}
SKMutablePayment *payment = [SKMutablePayment paymentWithProductIdentifier:[arguments objectAtIndex:0]];
if([arguments count] > 1) {
id quantity = [arguments objectAtIndex:1];
if ([quantity respondsToSelector:@selector(integerValue)]) {
payment.quantity = [quantity integerValue];
}
}
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
- (void) restoreCompletedTransactions:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options
{
[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
}
// SKPaymentTransactionObserver methods
// called when the transaction status is updated
//
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
NSString *state, *error, *transactionIdentifier, *transactionReceipt, *productId;
NSInteger errorCode;
for (SKPaymentTransaction *transaction in transactions)
{
error = state = transactionIdentifier = transactionReceipt = productId = @"";
errorCode = 0;
switch (transaction.transactionState)
{
case SKPaymentTransactionStatePurchasing:
continue;
case SKPaymentTransactionStatePurchased:
state = @"PaymentTransactionStatePurchased";
transactionIdentifier = transaction.transactionIdentifier;
transactionReceipt = [[transaction transactionReceipt] base64EncodedString];
productId = transaction.payment.productIdentifier;
break;
case SKPaymentTransactionStateFailed:
state = @"PaymentTransactionStateFailed";
error = transaction.error.localizedDescription;
errorCode = transaction.error.code;
NSLog(@"error %d %@", errorCode, error);
break;
case SKPaymentTransactionStateRestored:
state = @"PaymentTransactionStateRestored";
transactionIdentifier = transaction.originalTransaction.transactionIdentifier;
transactionReceipt = [[transaction transactionReceipt] base64EncodedString];
productId = transaction.originalTransaction.payment.productIdentifier;
break;
default:
NSLog(@"Invalid state");
continue;
}
NSLog(@"state: %@", state);
NSArray *callbackArgs = [NSArray arrayWithObjects:
NILABLE(state),
[NSNumber numberWithInt:errorCode],
NILABLE(error),
NILABLE(transactionIdentifier),
NILABLE(productId),
NILABLE(transactionReceipt),
nil];
NSString *js = [NSString stringWithFormat:@"plugins.inAppPurchaseManager.updatedTransactionCallback.apply(plugins.inAppPurchaseManager, %@)", [callbackArgs cdvjk_JSONSerialize]];
NSLog(@"js: %@", js);
[self writeJavascript: js];
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}
}
- (void)paymentQueue:(SKPaymentQueue *)queue restoreCompletedTransactionsFailedWithError:(NSError *)error
{
NSString *js = [NSString stringWithFormat:@"plugins.inAppPurchaseManager.onRestoreCompletedTransactionsFailed(%d)", error.code];
[self writeJavascript: js];
}
- (void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue
{
NSString *js = @"plugins.inAppPurchaseManager.onRestoreCompletedTransactionsFinished()";
[self writeJavascript: js];
}
@end
@implementation ProductsRequestDelegate
@synthesize successCallback, failCallback, command;
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
NSLog(@"got iap product response");
for (SKProduct *product in response.products) {
NSLog(@"sending js for %@", product.productIdentifier);
NSArray *callbackArgs = [NSArray arrayWithObjects:
NILABLE(product.productIdentifier),
NILABLE(product.localizedTitle),
NILABLE(product.localizedDescription),
NILABLE(product.localizedPrice),
nil];
NSString *js = [NSString stringWithFormat:@"%@.apply(plugins.inAppPurchaseManager, %@)", successCallback, [callbackArgs cdvjk_JSONSerialize]];
NSLog(@"js: %@", js);
[command writeJavascript: js];
}
for (NSString *invalidProductId in response.invalidProductIdentifiers) {
NSLog(@"sending fail (%@) js for %@", failCallback, invalidProductId);
[command writeJavascript: [NSString stringWithFormat:@"%@('%@')", failCallback, invalidProductId]];
}
NSLog(@"done iap");
[command writeJavascript: [NSString stringWithFormat:@"%@('__DONE')", successCallback]];
[request release];
[self release];
}
- (void) dealloc
{
[successCallback release];
[failCallback release];
[command release];
[super dealloc];
}
@end
/**
* Receives product data for multiple productIds and passes arrays of
* js objects containing these data to a single callback method.
*/
@implementation BatchProductsRequestDelegate
@synthesize callback, command;
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response {
NSMutableArray *validProducts = [NSMutableArray array];
for (SKProduct *product in response.products) {
[validProducts addObject:
[NSDictionary dictionaryWithObjectsAndKeys:
NILABLE(product.productIdentifier), @"id",
NILABLE(product.localizedTitle), @"title",
NILABLE(product.localizedDescription), @"description",
NILABLE(product.localizedPrice), @"price",
nil]];
}
NSArray *callbackArgs = [NSArray arrayWithObjects:
NILABLE(validProducts),
NILABLE(response.invalidProductIdentifiers),
nil];
NSString *js = [NSString stringWithFormat:@"%@.apply(plugins.inAppPurchaseManager, %@);", callback, [callbackArgs cdvjk_JSONSerialize]];
[command writeJavascript: js];
[request release];
[self release];
}
- (void) dealloc {
[callback release];
[command release];
[super dealloc];
}
@end