Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In App purchase not work on device

I try to make in app purchase on my app. But I have not result when I try to run it in device.

My code is following:

This is object needed for get info about products and purchase it.

.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

.m

#import "StoreManager.h"

@implementation StoreManager
@synthesize _purchasedProducts;
@synthesize products;
@synthesize _productIdentifiers;
@synthesize request;

// Initializes the request object with the set of product identifiers.
- (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;
}

// Request info for the product.
- (void)requestProducts{
    self.request = [[SKProductsRequest alloc] initWithProductIdentifiers:self._productIdentifiers];
    self.request.delegate = self;
    [self.request start];
}

// Request fail.
- (void)request:(SKRequest *)request didFailWithError:(NSError *)error{
    NSLog(@"Fail request! Error: %@", error);
}

// Delegate method - did receive responce.
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{
    self.products = response.products;
    self.request = nil;
    [[NSNotificationCenter defaultCenter] postNotificationName:kProductsLoadedNotification object:self.products];
}

// Buy product.
- (void)buyProduct:(SKProduct *)product{    
    SKPayment *payment = [SKPayment paymentWithProduct:product];
    [[SKPaymentQueue defaultQueue] addPayment:payment];
}

// Payment transactions
- (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 {    
    // TODO: Record the transaction on the server side...    
}

- (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

.m

#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 the my view controller i call next:

- (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!");   
        // Request product
        [[StoreWrapper sharedInstance] requestProducts];        
        [activIndicator startAnimating];
    }    
    [super viewWillAppear:animated];
}

for this point I send an request for get product info from server with my product id

next if product loaded my class get notification about this (and call following 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 selector buyProduct (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 wonderful, but on device I don have any button, because response.products not download.

All method are called, but delegate method *- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse )response not return response.products.

Thanks for your time and thanks for answer!

like image 218
Matrosov Oleksandr Avatar asked Feb 08 '12 12:02

Matrosov Oleksandr


1 Answers

For resolving, this problem I reset my device and rerun the application.

This helps for me.

like image 121
Matrosov Oleksandr Avatar answered Oct 11 '22 20:10

Matrosov Oleksandr