Code Block #import "GIFMIAPHelper.h"| #import <SecureNSUserDefaults/NSUserDefaults+SecureAdditions.h> |
|
| #define SecureSalt @"SecuredPaymentSalt" |
|
| @interface GIFMIAPHelper()<SKProductsRequestDelegate, SKPaymentTransactionObserver> |
|
| @end |
|
| @implementation GIFMIAPHelper |
| + (instancetype)defaultHelper { |
| static GIFMIAPHelper *defaultHelper; |
| static dispatch_once_t onceToken; |
| dispatch_once(&onceToken, ^{ |
| NSSet *productIdentifiers = [NSSet setWithObject:GIFMProduct_VomboPro]; |
| defaultHelper = [[self alloc] initWithProductIdentifiers:productIdentifiers]; |
| }); |
| return defaultHelper; |
| } |
|
| - (instancetype)initWithProductIdentifiers:(NSSet *)productIdentifiers { |
| self = [super init]; |
| if (self) { |
| NSString *udid = [[[UIDevice currentDevice] identifierForVendor] UUIDString]; |
| [[NSUserDefaults standardUserDefaults] setSecret:[NSString stringWithFormat:@"%@%@", udid, SecureSalt]]; |
| self.productsIdentifiers = productIdentifiers; |
| self.purchasedProductIdentifiers = [NSMutableSet set]; |
| for (NSString *productId in productIdentifiers) { |
| BOOL productPurchased = [[NSUserDefaults standardUserDefaults] secretBoolForKey:productId]; |
| if (productPurchased) { |
| [self.purchasedProductIdentifiers addObject:productId]; |
| } else { |
| DLog(@"Not purchased: %@", productId); |
| } |
| } |
| [[SKPaymentQueue defaultQueue] addTransactionObserver:self]; |
| } |
| return self; |
| } |
|
| - (void)requestProductsWithCompletionHandler:(GIFMRequestProductsCompletionHandler)completionHandler { |
| @try { |
| self.completionHandler = [completionHandler copy]; |
| |
| self.productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:_productsIdentifiers]; |
| self.productsRequest.delegate = self; |
| [self.productsRequest start]; |
| } |
| @catch (NSException *exception) { |
| DLog(@"Failed transaction %@", exception.description); |
| } |
| } |
|
| - (void)buyVomoboPro:(SKProduct *)product { |
| @try { |
| SKPayment *payment = [SKPayment paymentWithProduct:product]; |
| [[SKPaymentQueue defaultQueue] addPayment:payment]; |
| } |
| @catch (NSException *exception) { |
| DLog(@"Failed transaction %@", exception.description); |
| } |
| } |
|
| - (BOOL)vomboProPurchased { |
| #ifdef DEBUG_PREMIUM_LEVEL |
| return YES; |
| #endif |
| #ifdef DEBUG_FREEMIUM_LEVEL |
| return NO; |
| #endif |
|
| return [self.purchasedProductIdentifiers containsObject:GIFMProduct_VomboPro]; |
| } |
|
| - (void)restoreVomboProPurchase { |
| [[SKPaymentQueue defaultQueue] restoreCompletedTransactions]; |
| } |
|
| - (void)storeProductPurchasedState:(NSString *)productIdentifier { |
| [self.purchasedProductIdentifiers addObject:productIdentifier]; |
| [[NSUserDefaults standardUserDefaults] setSecretBool:YES forKey:productIdentifier]; |
| [[NSUserDefaults standardUserDefaults] synchronize]; |
| } |
|
| - (void)completeVomboProTransaction:(SKPaymentTransaction *)transaction { |
| [[SKPaymentQueue defaultQueue] finishTransaction:transaction]; |
| NSString *productIdentifier = transaction.payment.productIdentifier; |
| [self storeProductPurchasedState:productIdentifier]; |
| [[NSNotificationCenter defaultCenter] postNotificationName:GIFMIAPHelperProductPurchasedCompletedNotification object:productIdentifier]; |
| } |
|
| - (void)vomboProTransactionFailed:(SKPaymentTransaction *)transaction { |
| @try { |
| [[SKPaymentQueue defaultQueue] finishTransaction:transaction]; |
| [[NSNotificationCenter defaultCenter] postNotificationName:GIFMIAPHelperProductPurchasedFailedNotification object:transaction.error.localizedDescription]; |
| } |
| @catch (NSException *exception) { |
| DLog(@"Failed transaction %@", exception.description); |
| } |
| } |
|
| #pragma mark - SKProductsRequestDelegate, SKPaymentTransactionObserver |
| - (void)productsRequest:(nonnull SKProductsRequest *)request didReceiveResponse:(nonnull SKProductsResponse *)response { |
| NSLog(@"Fetched products"); |
| self.productsRequest = NULL; |
| NSArray *products = response.products; |
| for (SKProduct *product in products) { |
| if ([product.productIdentifier isEqualToString:GIFMProduct_VomboPro]) { |
| NSLog(@"Found product: %@ – Product: %@ – Price: %0.2f", product.productIdentifier, product.localizedTitle, product.price.floatValue); |
| if (self.completionHandler){ |
| self.completionHandler(YES, product, nil); |
| } |
| return; |
| } |
| } |
| NSError *error = [NSError errorWithDomain:@"SKProductsRequestNotFound" code:-1 userInfo:@{NSLocalizedDescriptionKey: @"Vombo Pro Not Found"}]; |
| |
| if (self.completionHandler){ |
| self.completionHandler(NO, NULL, error); |
| } |
| return; |
| } |
|
| - (void)request:(SKRequest *)request didFailWithError:(NSError *)error { |
| self.productsRequest = NULL; |
| if (self.completionHandler){ |
| self.completionHandler(NO, NULL, error); |
| } |
| } |
|
| - (void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue { |
| DLog(@"Restore Payment Finished"); |
| } |
|
| - (void)paymentQueue:(SKPaymentQueue *)queue restoreCompletedTransactionsFailedWithError:(NSError *)error { |
| DLog(@"Restore PaymentQueue Failed"); |
| } |
|
| - (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray<SKPaymentTransaction *> *)transactions { |
| DLog(@"Payment Updated"); |
| for (SKPaymentTransaction *transaction in transactions) { |
| switch (transaction.transactionState) { |
| case SKPaymentTransactionStatePurchased: |
| [self completeVomboProTransaction:transaction]; |
| [[SKPaymentQueue defaultQueue] finishTransaction:transaction]; |
| break; |
| case SKPaymentTransactionStateFailed:NSLog(@"Failed"); |
| [[SKPaymentQueue defaultQueue] finishTransaction:transaction]; |
| break; |
| case SKPaymentTransactionStateRestored: |
| [self completeVomboProTransaction:transaction]; |
| NSLog(@"Transaction state -> Restored"); |
| [[SKPaymentQueue defaultQueue] finishTransaction:transaction]; |
| break; |
| default: |
| break; |
| } |
| } |
| } |
|
| @end |