Last active
August 29, 2015 14:17
-
-
Save calebhicks/13d2460c98b9918b7891 to your computer and use it in GitHub Desktop.
StorePurchaseController
This file contains hidden or 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
// | |
// SSInAppPurchaseController.h | |
// SimpleStore | |
// | |
// Created by Joshua Howland on 7/2/14. | |
// Copyright (c) 2014 DevMountain. All rights reserved. | |
// | |
#import <Foundation/Foundation.h> | |
#import <StoreKit/StoreKit.h> | |
static NSString * const kInAppPurchaseFetchedNotification = @"kInAppPurchaseFetchedNotification"; | |
static NSString * const kInAppPurchaseCompletedNotification = @"kInAppPurchaseCompletedNotification"; | |
static NSString * const kInAppPurchaseRestoredNotification = @"kInAppPurchaseRestoredNotification"; | |
static NSString * const kProductIDKey = @"productID"; | |
@interface StorePurchaseController : NSObject | |
@property (nonatomic, strong) NSArray *products; | |
+ (StorePurchaseController *)sharedInstance; | |
- (void)requestProducts; | |
- (void)restorePurchases; | |
- (void)purchaseOptionSelectedObjectIndex:(NSUInteger)index; | |
- (NSSet *)bundledProducts; | |
@end |
This file contains hidden or 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
// | |
// SSInAppPurchaseController.m | |
// SimpleStore | |
// | |
// Created by Joshua Howland on 7/2/14. | |
// Copyright (c) 2014 DevMountain. All rights reserved. | |
// | |
#import "StorePurchaseController.h" | |
@interface StorePurchaseController () <SKProductsRequestDelegate, SKPaymentTransactionObserver> | |
@property (nonatomic, strong) SKProductsRequest *productsRequest; | |
@property (nonatomic, assign) BOOL productsRequested; | |
@end | |
@implementation StorePurchaseController | |
+ (StorePurchaseController *)sharedInstance { | |
static StorePurchaseController *sharedInstance = nil; | |
static dispatch_once_t onceToken; | |
dispatch_once(&onceToken, ^{ | |
sharedInstance = [[StorePurchaseController alloc] init]; | |
[sharedInstance loadStore]; | |
}); | |
return sharedInstance; | |
} | |
- (NSSet *)bundledProducts { | |
// gets all product IDs from the Products.json file | |
NSBundle *bundle = [NSBundle mainBundle]; | |
NSArray *bundleProducts = [NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfURL:[bundle URLForResource:@"Products" withExtension:@"json"]] options:0 error:nil]; | |
if (bundleProducts) { | |
NSSet *products = [NSSet setWithArray:bundleProducts]; | |
return products; | |
} | |
return nil; | |
} | |
- (void)requestProducts { | |
if (!self.productsRequest) { | |
// grabs product IDs | |
self.productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:[self bundledProducts]]; | |
self.productsRequest.delegate = self; | |
} | |
if (!self.productsRequested) { | |
// requests products from iTunes Connect | |
[self.productsRequest start]; | |
self.productsRequested = YES; | |
} | |
} | |
- (void) restorePurchases { | |
// restores purchases for the user | |
[[SKPaymentQueue defaultQueue] restoreCompletedTransactions]; | |
} | |
#pragma mark - Actions | |
- (void)purchaseOptionSelectedObjectIndex:(NSUInteger)index { | |
if ([SKPaymentQueue canMakePayments]) { | |
if ([self.products count] > 0) { | |
// create payment with the selected product | |
SKPayment *payment = [SKPayment paymentWithProduct:self.products[index]]; | |
[[SKPaymentQueue defaultQueue] addPayment:payment]; | |
} else { | |
UIAlertView *alertView = [[UIAlertView alloc] | |
initWithTitle:@"Unable to Purchase" | |
message:@"This purchase is currently unavailable. Please try again later." | |
delegate:nil | |
cancelButtonTitle:@"OK" | |
otherButtonTitles:nil]; | |
[alertView show]; | |
} | |
} else { | |
UIAlertView *alertView = [[UIAlertView alloc] | |
initWithTitle:@"Unable to Purchase" | |
message:@"In-app purchases are disabled. You'll have to enable them to enjoy the full app." | |
delegate:nil | |
cancelButtonTitle:@"OK" | |
otherButtonTitles:nil]; | |
[alertView show]; | |
} | |
} | |
#pragma mark - SKProductsRequestDelegate methods | |
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response { | |
self.productsRequested = NO; | |
NSArray *products = response.products; | |
self.products = products; | |
for (SKProduct *validProduct in response.products) { | |
NSLog(@"Found product: %@", validProduct.productIdentifier); | |
} | |
for (NSString *invalidProductId in response.invalidProductIdentifiers) { | |
NSLog(@"Invalid product id: %@" , invalidProductId); | |
} | |
// notifies app that products were loaded | |
[[NSNotificationCenter defaultCenter] postNotificationName:kInAppPurchaseFetchedNotification object:self userInfo:nil]; | |
} | |
#pragma mark - Store Methods | |
- (void)loadStore { | |
[[SKPaymentQueue defaultQueue] addTransactionObserver:self]; | |
[self requestProducts]; | |
} | |
- (void)finishTransaction:(SKPaymentTransaction *)transaction wasSuccessful:(BOOL)wasSuccessful { | |
[[SKPaymentQueue defaultQueue] finishTransaction:transaction]; | |
} | |
- (void)completeTransaction:(SKPaymentTransaction *)transaction { | |
// notifies app that purchase succeeded and passes the product identifier | |
NSString *productIdentifier = @""; | |
if (transaction.payment.productIdentifier) { | |
productIdentifier = transaction.payment.productIdentifier; | |
} else if (transaction.originalTransaction.payment.productIdentifier) { | |
productIdentifier = transaction.payment.productIdentifier; | |
} | |
[self finishTransaction:transaction wasSuccessful:YES]; | |
[[NSNotificationCenter defaultCenter] postNotificationName:kInAppPurchaseCompletedNotification object:self userInfo:@{kProductIDKey:productIdentifier}]; | |
} | |
- (void)restoreTransaction:(SKPaymentTransaction *)transaction { | |
UIAlertView *alertView = [[UIAlertView alloc] | |
initWithTitle:@"Restore Upgrade" | |
message:@"Finished restoring. Enjoy!" | |
delegate:nil | |
cancelButtonTitle:@"OK" | |
otherButtonTitles:nil]; | |
[alertView show]; | |
// notifies app that purchase was restored and passes the product identifier | |
NSString *productIdentifier = @""; | |
if (transaction.payment.productIdentifier) { | |
productIdentifier = transaction.payment.productIdentifier; | |
} else if (transaction.originalTransaction.payment.productIdentifier) { | |
productIdentifier = transaction.payment.productIdentifier; | |
} | |
[[NSNotificationCenter defaultCenter] postNotificationName:kInAppPurchaseRestoredNotification object:self userInfo:@{kProductIDKey:productIdentifier}]; | |
[self finishTransaction:transaction wasSuccessful:YES]; | |
} | |
- (void)failedTransaction:(SKPaymentTransaction *)transaction { | |
// closes a failed transaction and logs the error | |
if (transaction.error.code != SKErrorPaymentCancelled) { | |
NSLog(@"Error: %@", [transaction error]); | |
// error! | |
[self finishTransaction:transaction wasSuccessful:NO]; | |
} else { | |
// this is fine, the user just cancelled, so don’t notify | |
[[SKPaymentQueue defaultQueue] finishTransaction:transaction]; | |
} | |
} | |
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions { | |
NSLog(@"Payment Queue method called"); | |
// processes the transactions as they work through the queue | |
for (SKPaymentTransaction *transaction in transactions) { | |
switch (transaction.transactionState) { | |
case SKPaymentTransactionStatePurchasing: | |
NSLog(@"payment purchasing"); | |
break; | |
case SKPaymentTransactionStatePurchased: | |
[self completeTransaction:transaction]; | |
NSLog(@"payment purchased"); | |
break; | |
case SKPaymentTransactionStateFailed: | |
[self failedTransaction:transaction]; | |
NSLog(@"payment failed"); | |
break; | |
case SKPaymentTransactionStateRestored: | |
[self restoreTransaction:transaction]; | |
NSLog(@"payment restored"); | |
break; | |
case SKPaymentTransactionStateDeferred: | |
NSLog(@"payment deferred"); | |
break; | |
} | |
} | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment