Created
April 4, 2012 19:00
-
-
Save anonymous/2304762 to your computer and use it in GitHub Desktop.
InApp Manager
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// InAppPurchaseManager.m | |
// | |
// Created by Jiří Třečák. | |
// | |
#import <Foundation/Foundation.h> | |
#import <StoreKit/StoreKit.h> | |
// Add a couple notifications sent out when the transaction completes | |
#define INAPP_PURCHASE_SUCCEEDED @"inappPurchaseSucceeded" | |
#define INAPP_PURCHASE_FAILED @"inappPurchaseFailed" | |
#define INAPP_STORE_FETCHED_DATA @"inappStoreFetchedData" | |
@interface InAppPurchaseManager : NSObject <SKProductsRequestDelegate, SKPaymentTransactionObserver> { | |
NSArray *products; | |
SKProductsRequest *productsRequest; | |
} | |
+ (InAppPurchaseManager *)sharedInAppPurchaseManager; | |
// public methods | |
- (void)loadStore; | |
- (BOOL)canMakePurchases; | |
- (void)requestProductData; | |
- (void)kickOffPurchaseForTier:(int)aTier ; | |
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// InAppPurchaseManager.m | |
// | |
// Created by Jiří Třečák. | |
// | |
#import "InAppPurchaseManager.h" | |
#import "SynthesizeSingleton.h" | |
// All payment keys | |
#define INAPP_MAIN_IDENTIFIER @"com.myCompanyIdentifier.issueT%d" | |
#define INAPP_MAX_TIER 3 | |
@implementation InAppPurchaseManager | |
SYNTHESIZE_SINGLETON_FOR_CLASS(InAppPurchaseManager) | |
// InAppPurchaseManager.m | |
- (void)requestProductData { | |
NSMutableSet *productIdentifiers = [[NSMutableSet alloc] initWithCapacity:INAPP_MAX_TIER]; | |
// Create all identifiers | |
for (int i = 1; i <= INAPP_MAX_TIER; i++) { | |
[productIdentifiers addObject:[NSString stringWithFormat:INAPP_MAIN_IDENTIFIER,i]]; | |
} | |
// Request all products | |
productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productIdentifiers]; | |
productsRequest.delegate = self; | |
// Start request | |
[productsRequest start]; | |
[productIdentifiers release]; | |
} | |
#pragma mark - | |
#pragma mark SKProductsRequestDelegate methods | |
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response { | |
products = [[NSArray alloc] initWithArray:[response products]]; | |
// Test valid product ID's (approved for sale) | |
if (products != nil && [products count] > 0) { | |
int i = 1; | |
for (SKProduct *product in products) { | |
NSLog(@"%d. product title: %@", i, product.localizedTitle); | |
NSLog(@"%d. product description: %@", i, product.localizedDescription); | |
NSLog(@"%d. product price: %@", i, product.price); | |
NSLog(@"%d. store item initialization successful, identifier: %@", i, product.productIdentifier); | |
i++; | |
} | |
} | |
// Invalid product ID's (proly not approved yet?) | |
for (NSString *invalidProductId in response.invalidProductIdentifiers) { | |
NSLog(@"Invalid product id: %@" , invalidProductId); | |
} | |
} | |
// Store initialization | |
- (void)loadStore { | |
// restarts any purchases if they were interrupted last time the app was open | |
[[SKPaymentQueue defaultQueue] addTransactionObserver:self]; | |
// get the product description (defined in early sections) | |
[self requestProductData]; | |
} | |
// call this before making a purchase | |
- (BOOL)canMakePurchases { | |
return [SKPaymentQueue canMakePayments]; | |
} | |
- (void)kickOffPurchaseForTier:(int)aTier { | |
NSString *productIdentifier = [NSString stringWithFormat:INAPP_MAIN_IDENTIFIER,aTier]; | |
for (SKProduct *product in products) { | |
// Make payment if identifier is valid | |
if ([product.productIdentifier compare:productIdentifier] == NSOrderedSame) { | |
SKPayment *payment = [SKPayment paymentWithProduct:product]; | |
[[SKPaymentQueue defaultQueue] addPayment:payment]; | |
return; | |
} | |
} | |
// send out a notification for the failed transaction | |
[[NSNotificationCenter defaultCenter] postNotificationName:INAPP_PURCHASE_FAILED object:aIssue userInfo:nil]; | |
} | |
#pragma - | |
#pragma Purchase helpers | |
// saves a record of the transaction -> remote? | |
- (void)recordTransaction:(SKPaymentTransaction *)transaction { | |
NSError *error = nil; | |
// Write own save code here (core data manipulation etc. | |
if (error != nil) { | |
NSLog(@"Error while recording transaction %@",[error localizedDescription]); | |
} | |
} | |
// Remove transaction from the queue and posts a notification with the transaction result | |
- (void)finishTransaction:(SKPaymentTransaction *)transaction wasSuccessful:(BOOL)wasSuccessful { | |
// remove the transaction from the payment queue. | |
[[SKPaymentQueue defaultQueue] finishTransaction:transaction]; | |
NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:transaction, @"transaction" , nil]; | |
if (wasSuccessful) { | |
// send out a notification that we’ve finished the transaction | |
[[NSNotificationCenter defaultCenter] postNotificationName:INAPP_PURCHASE_SUCCEEDED object:nil userInfo:userInfo]; | |
NSLog(@"transaction successful"); | |
} else { | |
// send out a notification for the failed transaction | |
[[NSNotificationCenter defaultCenter] postNotificationName:INAPP_PURCHASE_FAILED object:nil userInfo:userInfo]; | |
NSLog(@"transaction failed"); | |
} | |
} | |
// called when the transaction was successful | |
- (void)completeTransaction:(SKPaymentTransaction *)transaction { | |
[self recordTransaction:transaction]; | |
[self finishTransaction:transaction wasSuccessful:YES]; | |
} | |
// called when a transaction has been restored and and successfully completed | |
- (void)restoreTransaction:(SKPaymentTransaction *)transaction { | |
[self recordTransaction:transaction.originalTransaction]; | |
[self finishTransaction:transaction wasSuccessful:YES]; | |
} | |
// called when a transaction has failed | |
- (void)failedTransaction:(SKPaymentTransaction *)transaction { | |
if (transaction.error.code != SKErrorPaymentCancelled) { | |
// Unknown error | |
[self finishTransaction:transaction wasSuccessful:NO]; | |
} else { | |
// User cancelled | |
[[SKPaymentQueue defaultQueue] finishTransaction:transaction]; | |
} | |
[[NSNotificationCenter defaultCenter] postNotificationName:INAPP_PURCHASE_FAILED object:lastKnownIssue userInfo:nil]; | |
} | |
#pragma mark - | |
#pragma mark SKPaymentTransactionObserver methods | |
// called when the transaction status is updated | |
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions { | |
for (SKPaymentTransaction *transaction in transactions) { | |
switch (transaction.transactionState) { | |
case SKPaymentTransactionStatePurchased: | |
[self completeTransaction:transaction]; | |
break; | |
case SKPaymentTransactionStateFailed: | |
[self failedTransaction:transaction]; | |
break; | |
case SKPaymentTransactionStateRestored: | |
[self restoreTransaction:transaction]; | |
break; | |
default: | |
break; | |
} | |
} | |
} | |
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// SynthesizeSingleton.h | |
// CocoaWithLove | |
// | |
// Created by Matt Gallagher on 20/10/08. | |
// Copyright 2009 Matt Gallagher. All rights reserved. | |
// | |
// Permission is given to use this source code file without charge in any | |
// project, commercial or otherwise, entirely at your risk, with the condition | |
// that any redistribution (in part or whole) of source code must retain | |
// this copyright and permission notice. Attribution in compiled projects is | |
// appreciated but not required. | |
// | |
#define SYNTHESIZE_SINGLETON_FOR_CLASS(classname) \ | |
\ | |
static classname *shared##classname = nil; \ | |
\ | |
+ (classname *)shared##classname { \ | |
\ | |
@synchronized(self) { \ | |
\ | |
if (shared##classname == nil) { \ | |
shared##classname = [[self alloc] init]; \ | |
} \ | |
} \ | |
\ | |
return shared##classname; \ | |
} \ | |
\ | |
+ (id)alloc { \ | |
\ | |
@synchronized(self) { \ | |
\ | |
if (shared##classname == nil) { \ | |
shared##classname = [super alloc]; \ | |
return shared##classname; \ | |
} \ | |
} \ | |
\ | |
return nil; \ | |
} \ | |
\ | |
- (id)retain { \ | |
\ | |
return self; \ | |
} \ | |
\ | |
\ | |
- (oneway void)release { \ | |
\ | |
if (shared##classname != nil) { \ | |
\ | |
shared##classname = nil; \ | |
[shared##classname release]; \ | |
} \ | |
if (self != nil) { \ | |
\ | |
[self dealloc]; \ | |
self = nil; \ | |
[super dealloc]; \ | |
} \ | |
} \ | |
\ | |
- (id)autorelease { \ | |
\ | |
return self; \ | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Usage is pretty easy: | |
- (void)use { | |
// Create shared instance | |
manager = [InAppPurchaseManager sharedInAppPurchaseManager]; | |
// Load store | |
[manager loadStore]; | |
// Make purchase (this has to be done AFTER store is initialized, which can take about 2 - 3 sec (async)) | |
[manager kickOffPurchaseForTier:1]; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment