I am trying to make an application purchase in my application. But I do not get when I try to run it on the device.
My code is as follows:
This is the object required to obtain product information and purchase.
.h
#import <Foundation/Foundation.h>
#import "StoreKit/StoreKit.h"
#define kProductsLoadedNotification @"ProductsLoaded"
#define kProductPurchasedNotification @"ProductPurchased"
#define kProductPurchaseFailedNotification @"ProductPurchaseFailed"
@interface StoreManager : NSObject <SKProductsRequestDelegate, SKPaymentTransactionObserver>
@property (strong, nonatomic) NSMutableSet * _purchasedProducts;
@property (strong, nonatomic) NSArray *products;
@property (strong, nonatomic) NSSet *_productIdentifiers;
@property (strong, nonatomic) SKProductsRequest *request;
- (id)initWithProductIdentifiers:(NSSet *)productIdentifiers;
- (void)requestProducts;
- (void)buyProduct:(SKProduct *)product;
- (void)completeTransaction:(SKPaymentTransaction *)transaction;
- (void)restoreTransaction:(SKPaymentTransaction *)transaction;
- (void)failedTransaction:(SKPaymentTransaction *)transaction;
- (void)provideContent:(NSString *)productIdentifier;
- (void)recordTransaction:(SKPaymentTransaction *)transaction;
@end
wow
#import "StoreManager.h"
@implementation StoreManager
@synthesize _purchasedProducts;
@synthesize products;
@synthesize _productIdentifiers;
@synthesize request;
- (id)initWithProductIdentifiers:(NSSet *)productIdentifiers{
self = [super init];
if(self){
self._productIdentifiers = productIdentifiers;
NSMutableSet *purchased = [NSMutableSet set];
for(NSString * productId in self._productIdentifiers){
BOOL flag = [[NSUserDefaults standardUserDefaults] boolForKey:productId];
if(flag){
[purchased addObject:productId];
NSLog(@"Previously purchased: %@", productId);
}
NSLog(@"Not purchased: %@", productId);
}
self._purchasedProducts = purchased;
}
return self;
}
- (void)requestProducts{
self.request = [[SKProductsRequest alloc] initWithProductIdentifiers:self._productIdentifiers];
self.request.delegate = self;
[self.request start];
}
- (void)request:(SKRequest *)request didFailWithError:(NSError *)error{
NSLog(@"Fail request! Error: %@", error);
}
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{
self.products = response.products;
self.request = nil;
[[NSNotificationCenter defaultCenter] postNotificationName:kProductsLoadedNotification object:self.products];
}
- (void)buyProduct:(SKProduct *)product{
SKPayment *payment = [SKPayment paymentWithProduct:product];
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
- (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];
default:
break;
}
}
}
- (void)recordTransaction:(SKPaymentTransaction *)transaction {
}
- (void)completeTransaction:(SKPaymentTransaction *)transaction{
[self recordTransaction: transaction];
[self provideContent: transaction.payment.productIdentifier];
NSLog(@"completeTransaction...");
}
- (void)provideContent:(NSString *)productIdentifier {
NSLog(@"Toggling flag for: %@", productIdentifier);
[[NSUserDefaults standardUserDefaults] setBool:TRUE forKey:productIdentifier];
[[NSUserDefaults standardUserDefaults] synchronize];
[self._purchasedProducts addObject:productIdentifier];
[[NSNotificationCenter defaultCenter] postNotificationName:kProductPurchasedNotification object:productIdentifier];
}
- (void)restoreTransaction:(SKPaymentTransaction *)transaction {
NSLog(@"restoreTransaction...");
[self recordTransaction: transaction];
[self provideContent: transaction.originalTransaction.payment.productIdentifier];
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
- (void)failedTransaction:(SKPaymentTransaction *)transaction {
if (transaction.error.code != SKErrorPaymentCancelled)
{
NSLog(@"Transaction error: %@", transaction.error.localizedDescription);
}
[[NSNotificationCenter defaultCenter] postNotificationName:kProductPurchaseFailedNotification object:transaction];
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
@end
Singleton Object
.h
#import <Foundation/Foundation.h>
#import "StoreManager.h"
@interface StoreWrapper : StoreManager
+ (StoreWrapper *)sharedInstance;
@end
wow
#import "StoreWrapper.h"
@implementation StoreWrapper
static StoreWrapper *gInstance = NULL;
- (id)init{
NSSet *productId = [NSSet setWithObjects:@"com.company.sb.pack1", @"com.company.sb.pack5", nil];
self = [super initWithProductIdentifiers:productId];
if(self){
}
return self;
}
+ (StoreWrapper *)sharedInstance{
if(gInstance == NULL){
gInstance = [[self alloc] init];
}
return gInstance;
}
@end
In my view controller, I call the following:
- (void)viewWillAppear:(BOOL)animated
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(productsLoaded:) name:kProductsLoadedNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(productPurchased:) name:kProductPurchasedNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector: @selector(productPurchaseFailed:) name:kProductPurchaseFailedNotification object: nil];
Reachability *reach = [Reachability reachabilityForInternetConnection];
NetworkStatus netStatus = [reach currentReachabilityStatus];
if (netStatus == NotReachable) {
NSLog(@"No internet connection!");
} else {
NSLog(@"Internet connection available!");
[[StoreWrapper sharedInstance] requestProducts];
[activIndicator startAnimating];
}
[super viewWillAppear:animated];
}
for this moment I am sending a request to receive product information from a server with a product identifier
next, if the product is loaded, my class receives a notification about this (and calls the next method).
- (void)productsLoaded:(NSNotification *)notification{
[activIndicator stopAnimating];
[activIndicator setHidden:YES];
NSArray *arr = [notification object];
for(int i = 0; i < [arr count]; i++){
SKProduct *product = [[StoreWrapper sharedInstance].products objectAtIndex:i];
UIButton *btn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[btn setFrame:CGRectMake(0, i*55, 100, 50)];
[btn setTitle:product.localizedTitle forState:UIControlStateNormal];
[btn setTag:i];
[btn addTarget:self action:@selector(buyProduct:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:btn];
}
}
For the button, I add a buyProduct selector (as shown above)
- (void)buyProduct:(id)sender{
NSLog(@"sender tag %d", [sender tag]);
int tag = [sender tag];
SKProduct *product = [[StoreWrapper sharedInstance].products objectAtIndex:tag];
[[StoreWrapper sharedInstance] buyProduct:product];
}
For iPhone Simulator, this work is great, but I have a button on the device because response.products is not loading.
, * - (void) productsRequest: (SKProductsRequest *) didReceiveResponse: (SKProductsResponse) response.products.
!