I did everything right, here is the iTunesConnect integrated shopping screenshot and my simple code. Only he tells me "no integrated purchase".
I've done it hundreds of times, but I still do not understand it.
My productID fits well on itunes as in the code. So where's the problem ?
Help me please guys :)
Code :
#import ....
#import ....
#define kTutorialPointProductID #"com.mathrack.SocialFame.CoinsPlus"
..........
..........
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
[self fetchAvailableProducts];
[self.navigationController.navigationBar setBackgroundImage:[UIImage new]
forBarMetrics:UIBarMetricsDefault]; //UIImageNamed:#"transparent.png"
self.navigationController.navigationBar.shadowImage = [UIImage new];////UIImageNamed:#"transparent.png"
self.navigationController.navigationBar.translucent = YES;
self.navigationController.view.backgroundColor = [UIColor clearColor];
}
-(void)fetchAvailableProducts{
NSSet *productIdentifiers = [NSSet
setWithObjects:kTutorialPointProductID,nil];
productsRequest = [[SKProductsRequest alloc]
initWithProductIdentifiers:productIdentifiers];
productsRequest.delegate = self;
[productsRequest start];
}
- (BOOL)canMakePurchases
{
return [SKPaymentQueue canMakePayments];
}
- (void)purchaseMyProduct:(SKProduct*)product{
if ([self canMakePurchases]) {
SKPayment *payment = [SKPayment paymentWithProduct:product];
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
else{
UIAlertView *alertView = [[UIAlertView alloc]initWithTitle:
#"Les achats intégrés sont désactiver sur votre appareil" message:nil delegate:
self cancelButtonTitle:#"OK" otherButtonTitles: nil];
[alertView show];
}
}
- (IBAction)buy50coins:(id)sender {
[self purchaseMyProduct:[validProducts objectAtIndex:0]];
}
#pragma mark StoreKit Delegate
-(void)paymentQueue:(SKPaymentQueue *)queue
updatedTransactions:(NSArray *)transactions {
for (SKPaymentTransaction *transaction in transactions) {
switch (transaction.transactionState) {
case SKPaymentTransactionStatePurchasing:
NSLog(#"Purchasing");
break;
case SKPaymentTransactionStatePurchased:
if ([transaction.payment.productIdentifier
isEqualToString:kTutorialPointProductID]) {
NSLog(#"Purchased ");
}
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
break;
case SKPaymentTransactionStateRestored:
NSLog(#"Restored ");
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
break;
case SKPaymentTransactionStateFailed:
[self purchaseFailed];
NSLog(#"Purchase failed ");
break;
default:
break;
}
}
}
-(void)productsRequest:(SKProductsRequest *)request
didReceiveResponse:(SKProductsResponse *)response
{
SKProduct *validProduct = nil;
int count = [response.products count];
if (count>0) {
validProducts = response.products;
validProduct = [response.products objectAtIndex:0];
if ([validProduct.productIdentifier
isEqualToString:kTutorialPointProductID]) {
}
} else {
UIAlertView *tmp = [[UIAlertView alloc]
initWithTitle:#"Non disponible"
message:#"Aucun produit à acheter"
delegate:self
cancelButtonTitle:nil
otherButtonTitles:#"OK", nil];
[tmp show];
}
}
- (void)purchaseFailed {
UIAlertView *alertView = [[UIAlertView alloc]initWithTitle:
#"Achat impossible" message:#"Un problème est survenue lors de votre achat, veuillez réessayer ulterieurement" delegate:
self cancelButtonTitle:#"OK" otherButtonTitles: nil];
[alertView show];
}
ItunesConnect picture :
Related
I have implemented in-app purchase and it used to work till now. I have added a few new in-app purchases and tested. It always switches to SKPaymentTransactionStateFailed and app crashes at that stage and no error message is given. Here is code for in app-purchase:
-(void)fetchAvailableProducts{
NSSet *productIdentifiers = [NSSet
setWithObjects:#"xxx.template8",nil];
productsRequest = [[SKProductsRequest alloc]
initWithProductIdentifiers:productIdentifiers];
productsRequest.delegate = self;
[productsRequest start];
}
- (BOOL)canMakePurchases
{
return [SKPaymentQueue canMakePayments];
}
- (void)purchaseMyProduct:(SKProduct*)product{
if ([self canMakePurchases]) {
SKPayment *payment = [SKPayment paymentWithProduct:product];
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
else{
UIAlertView *alertView = [[UIAlertView alloc]initWithTitle:
#"Purchases are disabled in your device" message:nil delegate:
self cancelButtonTitle:#"Ok" otherButtonTitles: nil];
[alertView show];
}
}
-(IBAction)purchase:(id)sender{
[self purchaseMyProduct:[validProducts objectAtIndex:0]];
purchaseButton.enabled = NO;
}
#pragma mark StoreKit Delegate
-(void)paymentQueue:(SKPaymentQueue *)queue
updatedTransactions:(NSArray *)transactions {
for (SKPaymentTransaction *transaction in transactions) {
switch (transaction.transactionState) {
case SKPaymentTransactionStatePurchasing:
NSLog(#"Purchasing");
break;
case SKPaymentTransactionStatePurchased:
if ([transaction.payment.productIdentifier
isEqualToString:#"xxx.template8"]) {
NSLog(#"Purchased ");
UIAlertView *alertView = [[UIAlertView alloc]initWithTitle:
#"Purchase is completed succesfully" message:nil delegate:
self cancelButtonTitle:#"Ok" otherButtonTitles: nil];
[alertView show];
}
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
break;
case SKPaymentTransactionStateRestored:
NSLog(#"Restored ");
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
break;
case SKPaymentTransactionStateFailed:
NSLog(#"Purchase failed ");
//[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
//break;
default:
break;
}
}
}
-(void)productsRequest:(SKProductsRequest *)request
didReceiveResponse:(SKProductsResponse *)response
{
SKProduct *validProduct = nil;
NSInteger count = [response.products count];
if (count>0) {
validProducts = response.products;
validProduct = [response.products objectAtIndex:0];
if ([validProduct.productIdentifier
isEqualToString:#"xxx.template8"]) {
[productTitleLabel setText:[NSString stringWithFormat:
#"Product Title: %#",validProduct.localizedTitle]];
[productDescriptionLabel setText:[NSString stringWithFormat:
#"Product Desc: %#",validProduct.localizedDescription]];
[productPriceLabel setText:[NSString stringWithFormat:
#"Product Price: %#",validProduct.price]];
}
} else {
UIAlertView *tmp = [[UIAlertView alloc]
initWithTitle:#"Not Available"
message:#"No products to purchase"
delegate:self
cancelButtonTitle:nil
otherButtonTitles:#"Ok", nil];
[tmp show];
}
[activityIndicatorView stopAnimating];
purchaseButton.hidden = NO;
}
there is a way to check which error occurred on SKPaymentTransaction, you can do:
...
case SKPaymentTransactionStateFailed:
[self failedTransaction:transaction];
...
- (void)failedTransaction:(SKPaymentTransaction *)transaction {
NSLog(#"failedTransaction...");
if (transaction.error.code != SKErrorPaymentCancelled)
{
NSLog(#"Transaction error: %#", transaction.error.localizedDescription);
}
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
apply this code and tell us what the log says
EDIT:
since the log says that the product identifier is null check in method
- (void)purchaseMyProduct:(SKProduct*)product{
NSLog(#"product id = %#",product.productIdentifier);
I've been trying to make in-app purchase work. Currently I've an application (Version 1.1) in app store. I want to release another version (V 1.2) in that version I want to integrate in app purchase. I've created a product for that. But when I try to load all product then it shows there is no product.
V1.2 is in the form of ready to upload binary. I've associated in app purchase. I just want to test in App Purchase. I've deleted all the provisioning profile from my devices (MAC + iPhone). Currently I've only one profile installed.
Here is my code:
-(void)fetchAvailableProducts{
NSSet *productIdentifiers = [NSSet
setWithObjects:bundle_identifier,nil];
productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productIdentifiers];
productsRequest.delegate = self;
[productsRequest start];
}
- (void)requestDidFinish:(SKRequest *)request {
NSLog(#"purchase request finished");
}
- (void)request:(SKRequest *)request didFailWithError:(NSError *)error {
NSLog(#"%#", [error description]);
}
- (BOOL)canMakePurchases
{
return [SKPaymentQueue canMakePayments];
}
- (void)purchaseMyProduct:(SKProduct*)product{
if ([self canMakePurchases]) {
SKPayment *payment = [SKPayment paymentWithProduct:product];
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
else{
UIAlertView *alertView = [[UIAlertView alloc]initWithTitle:
#"Purchases are disabled in your device" message:nil delegate:
self cancelButtonTitle:#"Ok" otherButtonTitles: nil];
[alertView show];
}
}
#pragma mark StoreKit Delegate
-(void)paymentQueue:(SKPaymentQueue *)queue
updatedTransactions:(NSArray *)transactions {
for (SKPaymentTransaction *transaction in transactions) {
switch (transaction.transactionState) {
case SKPaymentTransactionStatePurchasing:
NSLog(#"Purchasing");
break;
case SKPaymentTransactionStatePurchased:
if ([transaction.payment.productIdentifier
isEqualToString:bundle_identifier]) {
NSLog(#"Purchased ");
UIAlertView *alertView = [[UIAlertView alloc]initWithTitle:
#"Purchase is completed succesfully" message:nil delegate:
self cancelButtonTitle:#"Ok" otherButtonTitles: nil];
[alertView show];
}
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
break;
case SKPaymentTransactionStateRestored:
NSLog(#"Restored ");
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
break;
case SKPaymentTransactionStateFailed:
NSLog(#"Purchase failed ");
break;
default:
break;
}
}
}
-(void)productsRequest:(SKProductsRequest *)request
didReceiveResponse:(SKProductsResponse *)response
{
SKProduct *validProduct = nil;
int count = [response.products count];
NSLog(#"%#",response.products);
if (count>0) {
validProducts = response.products;
validProduct = [response.products objectAtIndex:0];
if ([validProduct.productIdentifier
isEqualToString:bundle_identifier]) {
}
} else {
UIAlertView *tmp = [[UIAlertView alloc]
initWithTitle:#"Not Available"
message:#"No products to purchase"
delegate:self
cancelButtonTitle:nil
otherButtonTitles:#"Ok", nil];
[tmp show];
}
}
I wanted to know what is the correct procedure for enabling in-app purchase and what I am doing wrong? And what should be done?
I solved the problem, so I am adding this as answer.
I mixed up with bundle identifier and product identifier. My code was correct, I provided bundle identifier instead of product identifier, this is the reason that I was not getting any products.
NSSet *productIdentifiers = [NSSet
setWithObjects:product_identifier,nil];
productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productIdentifiers];
In the above code use product_identifier(s). as I've only one product created so I am using single element to construct the set.
Your code looks correct. Have you confirmed that your in-app product id matches exactly the value in the bundle_id variable?
+ (RageIAPHelper *)sharedInstance {
static dispatch_once_t once;
static RageIAPHelper * sharedInstance;
dispatch_once(&once, ^{
NSSet * productIdentifiers = [NSSet setWithObject:kMDPulseSubscriptionProductIdentifier];
sharedInstance = [[self alloc] initWithProductIdentifiers:productIdentifiers];
});
return sharedInstance;
}
You get the products list,
but you have to test it on real device.
I have in app purchases set up in my app which work fine, however I want to call the 'Product Price' with local currency onto a viewController.
I have 2 files set up with the InAppPurchase code in there which look like this:
InAppPurchaseSS.h
#import <Foundation/Foundation.h>
#import "StoreKit/StoreKit.h"
#define kProductPurchasedNotification #"ProductPurchased"
#define kProductPurchaseFailedNotification #"ProductPurchaseFailed"
#define kProductPurchaseCancelledNotification #"ProductPurchaseCancelled"
#interface InAppPurchaseSS : NSObject <SKProductsRequestDelegate,SKPaymentTransactionObserver,UIAlertViewDelegate>
{
SKProductsRequest* productsRequest;
SKProduct *proUpgradeProduct;
UIAlertView* waitingAlert;
BOOL isTransactionOngoing;
IBOutlet UILabel *productPriceLabel;
}
#property (retain) SKProductsRequest* productsRequest;
#property (retain) NSArray * products;
#property (retain) SKProductsRequest *request;
#property (assign) BOOL isTransactionOngoing;
+ (InAppPurchaseSS *) sharedHelper;
-(id)init;
- (void)buyProductIdentifier:(NSString *)productIdentifier;
- (BOOL)canMakePurchases;
-(void)restoreInAppPurchase;
#end
InAppPurchaseSS.m
//
// InAppPurchaseSS.m
// Pharaonia
//
// Created by iMac on 4/16/13.
// Copyright (c) 2013 Apple. All rights reserved.
//
#import "InAppPurchaseSS.h"
#import "Reachability.h"
#implementation InAppPurchaseSS
#synthesize products;
#synthesize request;
#synthesize productsRequest;
#synthesize isTransactionOngoing;
static InAppPurchaseSS * _sharedHelper;
+ (InAppPurchaseSS *) sharedHelper {
if (_sharedHelper != nil) {
return _sharedHelper;
}
_sharedHelper = [[InAppPurchaseSS alloc] init];
return _sharedHelper;
}
-(id)init {
if( (self=[super init]))
{
isTransactionOngoing=NO;
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
}
return self;
}
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response {
NSLog(#"Received products results...");
self.products = response.products;
self.request = nil;
NSLog(#"Number of product:%i : %#",[response.products count],response.products);
NSArray *product = response.products;
proUpgradeProduct = [product count] == 1 ? [[product firstObject] retain] : nil;
if (proUpgradeProduct)
{
NSLog(#"Product title: %#" , proUpgradeProduct.localizedTitle);
NSLog(#"Product description: %#" , proUpgradeProduct.localizedDescription);
NSLog(#"Product price: %#" , proUpgradeProduct.price);
NSLog(#"Product id: %#" , proUpgradeProduct.productIdentifier);
}
for (NSString *invalidProductId in response.invalidProductIdentifiers)
{
NSLog(#"Invalid product id: %#" , invalidProductId);
}
[productPriceLabel setText:[NSString stringWithFormat:
#"Product Price: %#",proUpgradeProduct.price]];
}
-(void)restoreInAppPurchase
{
Reachability *reach = [Reachability reachabilityForInternetConnection];
NetworkStatus netStatus = [reach currentReachabilityStatus];
if (netStatus == NotReachable) {
NSLog(#"No internet connection!");
[[[UIAlertView alloc] initWithTitle:#"No Internet" message:#"Sorry, no internet connection found" delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles: nil] show];
return;
}
waitingAlert = [[UIAlertView alloc] initWithTitle:#"Restoring..." message:#"Please Wait...\n\n" delegate:nil cancelButtonTitle:nil otherButtonTitles: nil];
[waitingAlert show];
[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
}
- (void)buyProductIdentifier:(NSString *)productIdentifier {
if ([productIdentifier isEqual: #""]) {
NSLog(#"No IAP Product ID specified");
return;
}
Reachability *reach = [Reachability reachabilityForInternetConnection];
NetworkStatus netStatus = [reach currentReachabilityStatus];
if (netStatus == NotReachable) {
NSLog(#"No internet connection!");
[[[UIAlertView alloc] initWithTitle:#"No Internet" message:#"Sorry, no internet connection found" delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles: nil] show];
return;
}
isTransactionOngoing=YES;
waitingAlert = [[UIAlertView alloc] initWithTitle:#"Purchasing..." message:#"Please Wait...\n\n" delegate:nil cancelButtonTitle:nil otherButtonTitles: nil];
[waitingAlert show];
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 6.0) {
SKMutablePayment *payment = [[SKMutablePayment alloc] init];
payment.productIdentifier = productIdentifier;
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
else {
SKPayment *payment = [SKPayment paymentWithProductIdentifier:productIdentifier];
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
}
-(void)enableFeature
{
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"PurchaseSuccess"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
- (void)paymentQueue:(SKPaymentQueue *)queue restoreCompletedTransactionsFailedWithError:(NSError *)error
{
[waitingAlert dismissWithClickedButtonIndex:0 animated:YES];
NSLog(#"Restore completed transaction failed");
}
- (BOOL)canMakePurchases
{
return [SKPaymentQueue canMakePayments];
}
//
- (void)finishTransaction:(SKPaymentTransaction *)transaction wasSuccessful:(BOOL)wasSuccessful
{
isTransactionOngoing=NO;
[waitingAlert dismissWithClickedButtonIndex:0 animated:YES];
// remove the transaction from the payment queue.
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
if (wasSuccessful)
{
[self enableFeature];
[[[UIAlertView alloc] initWithTitle:#"Congratulations!!" message:#"You have succesfully Purchases." delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles: nil] show];
[[NSNotificationCenter defaultCenter] postNotificationName:#"successbuy" object:self];
}
else
{
[[[UIAlertView alloc] initWithTitle:#"Error!" message:transaction.error.localizedDescription delegate:nil cancelButtonTitle:nil otherButtonTitles:#"OK", nil] show];
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
[[NSNotificationCenter defaultCenter] postNotificationName:#"TransCancel" object: self];
}
}
- (void)completeTransaction:(SKPaymentTransaction *)transaction
{
NSLog(#"succesfull transaction");
[self finishTransaction:transaction wasSuccessful:YES];
}
- (void)restoreTransaction:(SKPaymentTransaction *)transaction
{
NSLog(#"transaction is restored");
[self finishTransaction:transaction wasSuccessful:YES];
}
// called when a transaction has failed
- (void)failedTransaction:(SKPaymentTransaction *)transaction
{
isTransactionOngoing=NO;
NSLog(#"failed transaction called");
if (transaction.error.code != SKErrorPaymentCancelled)
{
NSLog(#"Transaction failed called");
NSLog(#"Transaction error: %#", transaction.error.localizedDescription);
[self finishTransaction:transaction wasSuccessful:NO];
}
else
{
[waitingAlert dismissWithClickedButtonIndex:0 animated:YES];
NSLog(#"user cancel transaction");
// this is fine, the user just cancelled, so don’t notify
[[NSNotificationCenter defaultCenter] postNotificationName:#"TransCancel" object: self];
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}
}
#pragma mark -
#pragma mark SKPaymentTransactionObserver methods
// called when the transaction status is updated
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
NSLog(#"transaction status updated");
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;
}
}
}
- (void) dealloc
{
[[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
[super dealloc];
}
#end
I have another viewController set up where I want to call the Local Product Price with UILabel. Let's assume this is called SecondViewController. I know that in InAppPurchaseSS.m I have a field for proUpgradeProduct.price but I need to call this as a UI label with the local currency
It may be something obvious Im overlooking but I'd appreciate some help with this
Thank you
SKProduct has a priceLocale attribute and price attribute you can use to create the text for your label.
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
[numberFormatter setFormatterBehavior:NSNumberFormatterBehavior10_4];
[numberFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
[numberFormatter setLocale:product.priceLocale];
NSString *formattedString = [numberFormatter stringFromNumber:product.price];
My app has been rejected by itunes.
Their reason is:
After we tap the buy button the app does not initiate the password
window to finish the In App Purchase process and only displays a
message "waiting" then nothing happens.
They mean there is purchase dialog,but when tap the buy button,their is no the password window.But it is OK when I test it.
The password window initialization is not under my control, what should I do ?
Here is my code:
-(void)buy:(NSString*)type
{
buyType = type;
//judge whether can buy product
if ([SKPaymentQueue canMakePayments]) {
NSLog(#"can buy");
[self RequestProductData];
}else{
UIAlertView *alerView = [[UIAlertView alloc] initWithTitle:#"Alert"
message:#"You can‘t purchase in app store(不允许应用程序内购买)"
delegate:nil cancelButtonTitle:NSLocalizedString(#"Close(关闭)",nil) otherButtonTitles:nil];
[alerView show];
[alerView release];
}
}
-(bool)CanMakePay
{
return [SKPaymentQueue canMakePayments];
}
-(void)RequestProductData
{
NSSet *nsset = [NSSet setWithObject:buyType];
SKProductsRequest *request=[[SKProductsRequest alloc] initWithProductIdentifiers: nsset];
request.delegate=self;
[request start];
}
//<SKProductsRequestDelegate>
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{
NSArray *myProduct = response.products;
// populate UI
for(SKProduct *product in myProduct){
SKPayment *payment = [SKPayment paymentWithProduct:product];
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
[request autorelease];
}
//alert error
- (void)request:(SKRequest *)request didFailWithError:(NSError *)error{
UIAlertView *alerView = [[UIAlertView alloc] initWithTitle:NSLocalizedString(#"Alert",NULL) message:[error localizedDescription]
delegate:nil cancelButtonTitle:NSLocalizedString(#"Close",nil) otherButtonTitles:nil];
[alerView show];
[alerView release];
}
-(void) requestDidFinish:(SKRequest *)request
{
}
-(void) PurchasedTransaction: (SKPaymentTransaction *)transaction{
NSArray *transactions =[[NSArray alloc] initWithObjects:transaction, nil];
[self paymentQueue:[SKPaymentQueue defaultQueue] updatedTransactions:transactions];
[transactions release];
}
//<SKPaymentTransactionObserver>
//----listen to the purchase result
//
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
for (SKPaymentTransaction *transaction in transactions)
{
switch (transaction.transactionState)
{
case SKPaymentTransactionStatePurchased://purchase ok
[self completeTransaction:transaction];
[[transaction payment] quantity];
NSLog(#"%#",[[NSString alloc] initWithData:transaction.transactionReceipt encoding:NSUTF8StringEncoding ]);
NSLog(#"transaction id:%#",[transaction transactionIdentifier]);
break;
case SKPaymentTransactionStateFailed:
[self failedTransaction:transaction];
NSLog(#"-----交易失败 --------");
break;
case SKPaymentTransactionStateRestored:
[self restoreTransaction:transaction];
case SKPaymentTransactionStatePurchasing:
break;
default:
break;
}
}
}
- (void) completeTransaction: (SKPaymentTransaction *)transaction
{
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
-(void)recordTransaction:(NSString *)product{
}
//
-(void)provideContent:(NSString *)product{
}
- (void) failedTransaction: (SKPaymentTransaction *)transaction{
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
-(void) paymentQueueRestoreCompletedTransactionsFinished: (SKPaymentTransaction *)transaction{
}
- (void) restoreTransaction: (SKPaymentTransaction *)transaction
{
}
-(void) paymentQueue:(SKPaymentQueue *) paymentQueue restoreCompletedTransactionsFailedWithError:(NSError *)error{
}
I use this code to process my in-app purchase:
#pragma mark StoreKit Delegate
-(void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions {
for (SKPaymentTransaction *transaction in transactions) {
switch (transaction.transactionState) {
case SKPaymentTransactionStatePurchasing:
{
// show wait view here
// statusLabel.text = #"Processing...";
}
break;
case SKPaymentTransactionStatePurchased:
{
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
// remove wait view and unlock feature 2
// statusLabel.text = #"Done!";
UIAlertView *tmp = [[UIAlertView alloc]
initWithTitle:#"Complete"
message:#"You have unlocked Feature 2!"
delegate:self
cancelButtonTitle:nil
otherButtonTitles:#"Ok", nil];
[tmp show];
NSError *error = nil;
[SFHFKeychainUtils storeUsername:#"IAPStoreSave" andPassword:#"whatever" forServiceName:kStoredData updateExisting:YES error:&error];
// apply purchase action - hide lock overlay and
[self.lockImage removeFromSuperview];
// do other thing to enable the features
}
break;
case SKPaymentTransactionStateRestored:
{
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
// remove wait view here
// statusLabel.text = #"";
}
break;
case SKPaymentTransactionStateFailed:
{
if (transaction.error.code != SKErrorPaymentCancelled) {
NSLog(#"Error payment cancelled");
}
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
// remove wait view here
// statusLabel.text = #"Purchase Error!";
}
break;
default:
{
}
break;
}
}
}
-(void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
// remove wait view here
// statusLabel.text = #"";
SKProduct *validProduct = nil;
int count = [response.products count];
if (count>0) {
validProduct = [response.products objectAtIndex:0];
SKPayment *payment = [SKPayment paymentWithProductIdentifier:#"com.app.ID"];
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
[[SKPaymentQueue defaultQueue] addPayment:payment];
} else {
UIAlertView *tmp = [[UIAlertView alloc]
initWithTitle:#"Not Available"
message:#"No products to purchase"
delegate:self
cancelButtonTitle:nil
otherButtonTitles:#"Ok", nil];
[tmp show];
}
}
-(void)requestDidFinish:(SKRequest *)request
{
}
-(void)request:(SKRequest *)request didFailWithError:(NSError *)error
{
NSLog(#"Failed to connect with error: %#", [error localizedDescription]);
}
And start it in this way:
SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithObject:#"com.app.ID"]];
request.delegate = self;
[request start];
In my itunes connect I set up the in-app with the product ID I have entered, and the status is "ready to submit", and it also says: "Your first In-App Purchase(s) must be submitted with a new app version. Select them from the In-App Purchases section of the Version Details page and then click Ready to Upload Binary." When i start the request, the alert NO PRODUCT AVAILABLE always show up. What am I doing wrong??
Are you sure that bundle ID is the same as the app on Itunes Connect? Second to check is app provisioning profile (if it handles IAP) - I think this could be the reason. Let me know.