double inAppPurchase when logged in with TestUserAcoount - in-app-purchase

when i´m logged in with my testUserAcount, my inAppPurchases runs twice the buyAction. why is that? when my testUserAccount is not logged in, the buy action runs correctly:
-(void)fetchProducts{
NSLog(#"fetchProdukts");
SKProductsRequest *request = [[SKProductsRequest alloc]initWithProductIdentifiers:[NSSet setWithArray:self.products]];
request.delegate = (id)self;
[request start];}
-(void)productsRequest:(SKProductsRequest*)request didReceiveResponse:(SKProductsResponse *)response{
self.products = response.products;}
-(void)request:(SKRequest *) request didFailWithError:(NSError *)error{
NSLog(#"%#", error);}
-(void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions{
for (SKPaymentTransaction *transaction in transactions) {
//PURCHASED
switch (transaction.transactionState) {
case SKPaymentTransactionStatePurchased:
[[SKPaymentQueue defaultQueue]finishTransaction:transaction];
if ([transaction.payment.productIdentifier isEqualToString:#"StarMultiplier1"]) {
NSLog(#"Multiplier unlocked");
[self buyMultiplierAction];
}
if ([transaction.payment.productIdentifier isEqualToString:#"add15000Stars3"]) {
NSLog(#"Stars buyed");
[self buyStarsAction];
}
if ([transaction.payment.productIdentifier isEqualToString:#"unlockArtefacts3"]) {
NSLog(#"Artefacts unlocked");
[self buyArtefactsAction];
}
if ([transaction.payment.productIdentifier isEqualToString:#"addPowerUps4"]) {
NSLog(#"PowerUps buyed");
[self buyPowerUpsAction];
}
break;
//NOT PURCHASED
case SKPaymentTransactionStateFailed:
[[SKPaymentQueue defaultQueue]finishTransaction:transaction];
NSLog(#"Error: %#", transaction.error);
(when logged in)
for every action i get the logs twice. my code is correct.
???

Related

Storekit Restore delegate method called multiple time

I have implemented in-app purchase in my app. My problem is when a new user clicks on restore button, the process is not stopped after completing 1 cycle And execute again and again. After executing 3 to 4 times process get stopped.
I want to stop process instant when a new user doesn't have any purchased transaction.
Here is code of my IAP class.
- (void)restorePurchases
{
[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
}
- (void)paymentQueue:(SKPaymentQueue *)queue restoreCompletedTransactionsFailedWithError:(NSError *)error
{
[[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
[ProgressHUD dismiss];
}
- (void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue
{
[[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
[ProgressHUD dismiss];
}
// Sent when transactions are removed from the queue (via finishTransaction:).
- (void)paymentQueue:(SKPaymentQueue *)queue removedTransactions:(NSArray *)transactions
{
[[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
[ProgressHUD dismiss];
}
// Called when the transaction status is updated
-(void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions {
for (SKPaymentTransaction *transaction in transactions) {
switch (transaction.transactionState)
{
case SKPaymentTransactionStatePurchasing:
[self transactionStart:transaction];
break;
case SKPaymentTransactionStatePurchased:
[self transactionComplete:transaction];
[[SKPaymentQueue defaultQueue]
finishTransaction:transaction];
break;
case SKPaymentTransactionStateFailed:
[self transactionFailed:transaction];
[[SKPaymentQueue defaultQueue]
finishTransaction:transaction];
break;
case SKPaymentTransactionStateRestored:
{
[self transactionRestored:transaction];
[[SKPaymentQueue defaultQueue]
finishTransaction:transaction];
break;
}
default:
break;
}
}
}
#pragma mark - Local method for mange transactions -
-(void)transactionStart:(SKPaymentTransaction *)transaction
{
if([self.delegate respondsToSelector:#selector(startPayment:)]){
[self.delegate startPayment:transaction];
}
}
-(void)transactionComplete:(SKPaymentTransaction *)transaction
{
if([self.delegate respondsToSelector:#selector(completePayment:)]){
[self.delegate completePayment:transaction];
}
}
-(void)transactionFailed:(SKPaymentTransaction *)transaction
{
if ([self.delegate respondsToSelector:#selector(failedPayment:)]) {
[self.delegate failedPayment:transaction];
}
}
-(void)transactionRestored:(SKPaymentTransaction *)transaction
{
if([self.delegate respondsToSelector:#selector(restoredPayment:)]){
[[AppDelegate sharedAppDelegate].arrayConacatResponse addObject:[NSString stringWithFormat:#"transactionRestored method "] ];
[self.delegate restoredPayment:transaction];
}
}
In Restore payment method
- (void)restoredPayment:(SKPaymentTransaction *)transactions
{
if ([transactions.payment.productIdentifier isEqualToString:monthlySubscription]) {
NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
NSError *receiptError;
BOOL isPresent = [receiptURL checkResourceIsReachableAndReturnError:&receiptError];
if (isPresent)
{
NSData *receiptData = [[NSData alloc] initWithContentsOfURL:[[NSBundle mainBundle] appStoreReceiptURL]];
BOOL isSubscriptionPeriodValid = [[DataBase sharedInstance] getSubscriptionStatusFromAppleWithReceipt:receiptData];
if (isSubscriptionPeriodValid)
{
[self removeFromSuperview];
}else{
// Here I want to stop
[CommonUtilities showAlertWithTitle:#"" Message:#"You have no transaction to restore."];
}
}
}
[ProgressHUD dismiss];
}

can't find IAP in productrequest

I create IAP in itune connect (non-consumable) to access view controller but I test in iPhone it not pop up to purchase page
my IAP product ID is "Egayov"
my app id is "my.com.th.myapp"
this is my code
- (void)viewDidLoad {
[super viewDidLoad];
if([SKPaymentQueue canMakePayments]){
NSLog(#"can buy all IAP");
SKProductsRequest *productRequest = [[SKProductsRequest alloc]initWithProductIdentifiers:[NSSet setWithObject:#"my.com.th.myapp"]];
productRequest.delegate = self;
[productRequest start];
}
else{
NSLog(#"Parental controll on");
}
}
-(IBAction)Buyvoyage{
SKPayment *vo = [SKPayment paymentWithProductIdentifier:#"my.com.th.myapp"];
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
[[SKPaymentQueue defaultQueue] addPayment:vo];
}
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
SKProduct *vaildproduct = nil;
int count = [response.products count];
if (count>0) {
vaildproduct = [response.products objectAtIndex:0];
}
if (!vaildproduct){
NSLog(#"no iap %#",vaildproduct);
}
}
-(void)paymentQueue:(SKPaymentQueue *)queue removedTransactions:(NSArray *)transactions{
for (SKPaymentTransaction *transaction in transactions) {
switch (transaction.transactionState) {
case SKPaymentTransactionStatePurchasing:
break;
case SKPaymentTransactionStatePurchased:
[self checkiap];
break;
case SKPaymentTransactionStateRestored:
[[SKPaymentQueue defaultQueue]finishTransaction:transaction];
break;
case SKPaymentTransactionStateFailed:
if (transaction.error.code != SKErrorPaymentCancelled) {
NSLog(#"Payment Failed");
}
[[SKPaymentQueue defaultQueue]finishTransaction:transaction];
break;
}
}
}
in productrequest function it go to else condition
I had the same problem and honestly saying it wasn't solved. It's much easier to implement IAPs with Parse. It takes just few lines of code and it really works. Read this, I'm sure it will help you:
http://blog.parse.com/announcements/in-app-purchase/

Method for restoring in app purchases is unlocking features that hadn't been purchased

I have a nonconsumable IAP for a "Save Feature." It was recently rejected because I did not include a restore feature in the app. I added code for restoring, but when I created a new test user that hadn't purchased the app and pressed the restore button, the save feature was unlocked.
Here is how I check if a user has purchased the save feature
if (![userDefaults boolForKey:#"isPurchase"]){
[self purchaseMyProduct:[validProducts objectAtIndex:0]];
}
else { ... }
These are the methods I added to restore IAP's.
- (void)restorePurchases { //called when button pressed
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
[[SKPaymentQueue defaultQueue]restoreCompletedTransactions];
}
- (void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue {
for (SKPaymentTransaction *transaction in queue.transactions) {
NSString *productID = transaction.payment.productIdentifier;
if ([productID isEqualToString:#"facePuppetsSave"]) {
NSLog(#"called");
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setBool:YES forKey:#"isPurchase"];
[userDefaults synchronize];
}
}
}
Here are the methods I already had.
-(void)paymentQueue:(SKPaymentQueue *)queue
updatedTransactions:(NSArray *)transactions {
for (SKPaymentTransaction *transaction in transactions) {
switch (transaction.transactionState) {
case SKPaymentTransactionStatePurchasing:
break;
case SKPaymentTransactionStatePurchased:
if ([transaction.payment.productIdentifier
isEqualToString:#"facePuppetsSave"]) {
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setBool:YES forKey:#"isPurchase"];
[userDefaults synchronize];
UIAlertView *alertView = [[UIAlertView alloc]initWithTitle:
#"Purchase completed. Saving now available." message:nil delegate:
self cancelButtonTitle:#"Ok" otherButtonTitles: nil];
[alertView show];
[alertView release];
}
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
break;
case SKPaymentTransactionStateRestored:
NSLog(#"Restored ");
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
break;
case SKPaymentTransactionStateFailed:
break;
default:
break;
}
}
}
-(void)productsRequest:(SKProductsRequest *)request
didReceiveResponse:(SKProductsResponse *)response
{
SKProduct *validProduct = nil;
int count = [response.products count];
if (count>0) {
validProducts = response.products;
[validProducts retain];
validProduct = [response.products objectAtIndex:0];
}
Also, for the new test user example, I noticed that the NSLog "called" from the paymentQueueRestoreCompletedTransactionsFinished method is being called twice and "restored" from the paymentQueue:updatedTransactions: method is not being called at all.
How can I modify my code to restore properly?
Follow this:
#pragma mark SKPaymentTransactionOBserver
- (void)storeRestoreTransactionsFinished:(NSNotification*)notification
{
NSLog(#"- (void)storeRestoreTransactionsFinished:(NSNotification*)notification");
[apDelegate hideLoading];
}
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
for (SKPaymentTransaction *transaction in transactions) {
switch (transaction.transactionState) {
case SKPaymentTransactionStatePurchasing:
NSLog(#"Prossing.............");
break;
case SKPaymentTransactionStatePurchased:
{
[self completeTransaction:transaction];
NSError* error;
NSDictionary* jsonDict = [NSJSONSerialization
JSONObjectWithData:transaction.transactionReceipt
options:kNilOptions
error:&error];
NSLog(#"JSON Receipt: %#",jsonDict);
[[NSUserDefaults standardUserDefaults] setObject:jsonDict forKey:#"A"];
NSLog(#"Purchase was a Success.....");
}
break;
case SKPaymentTransactionStateFailed:
[self failedTransaction:transaction];
NSLog(#"Purchase cancelled");
break;
case SKPaymentTransactionStateRestored:
[self restoreTransaction:transaction];
default:
break;
}
}
}
- (void)restoreTransaction:(SKPaymentTransaction *)transaction {
NSLog(#"restoreTransaction...");
[self validateReceiptForTransaction:transaction];
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}
- (void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue
{
NSLog(#"Restore completed transactions finished.");
NSLog(#" Number of transactions in queue: %d", [[queue transactions] count]);
for (SKPaymentTransaction *trans in [queue transactions])
{
NSLog(#" transaction id %# for product %#.", [trans transactionIdentifier], [[trans payment] productIdentifier]);
NSLog(#" original transaction id: %# for product %#.", [[trans originalTransaction] transactionIdentifier],
[[[trans originalTransaction] payment]productIdentifier]);
if ([[[trans payment] productIdentifier] isEqual: kMDPulseSubscriptionProductIdentifier]) {
NSLog(#"Purchase Restored");
// Do your stuff to unlock
}
}
}
- (void)restoreCompletedTransactions
{
NSLog(#"Restore Tapped in transaction process");
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
}

ios application rejected due to in app purchase payment issue

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{
}

In-App-Purchase Remove From Queue

I am new on iOS, i am trying to download 3 products from my service but the user needs to buy these products, i have 3 buttons, i click first one and after enter username and password, it is downloading, then i click second product, firstly it is downloading first product then second product,then i click third product, it is downloading first->second->third product.How can i remove the first product from the queue after download first product? Sorry for my bad english.
Thanks.
Best Regards.
- (IBAction)downloadButtonPressed:(id)sender {
SKPayment *payment = [SKPayment paymentWithProductIdentifier:#"com.company.testtest123"];
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
[[SKPaymentQueue defaultQueue]addPayment:payment];
}
- (void)paymentQueue:(SKPaymentQueue *)queue removedTransactions:(NSArray *)transactions {
for (SKPaymentTransaction *transaction in transactions) {
// Count down
#synchronized(self) {
NSInteger numOfTransaction = [[NSUserDefaults standardUserDefaults] integerForKey:#"NumberOfTransactions"];
[[NSUserDefaults standardUserDefaults] setInteger:numOfTransaction-1 forKey:#"NumberOfTransactions"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
}
}
-(void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{
SKProduct *validProduct =nil;
int count = [response.products count];
if (count>0) {
validProduct =[response.products objectAtIndex:0];
}else if(!validProduct){
NSLog(#"No products avaible");
}
}
-(void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions{
for (SKPaymentTransaction *transaction in transactions) {
switch (transaction.transactionState) {
case SKPaymentTransactionStatePurchasing:
break;
case SKPaymentTransactionStatePurchased:{
//download kismi buraya
NSLog(#"_mainDict = %#",_mainDict);
float _csize = (float) 0 / 1024;
float _tsize = (float) [[_mainDict valueForKey:#"Size"] integerValue] / 1024;
NSString *strDownload = [NSString stringWithFormat:#"downloading \n (%0.2f MB/%.2f MB)",_csize,_tsize];
[SVProgressHUD showProgress:0 status:strDownload maskType:SVProgressHUDMaskTypeBlack];
[service servicePicList];
[[SKPaymentQueue defaultQueue]finishTransaction:transaction];
break;
}
case SKPaymentTransactionStateRestored:{
[[SKPaymentQueue defaultQueue]finishTransaction:transaction];
break;
}
case SKPaymentTransactionStateFailed:
{
if (transaction.error.code != SKErrorPaymentCancelled) {
NSLog(#"An error encountered");
}
[[SKPaymentQueue defaultQueue]finishTransaction:transaction];
break;
}
}
}
}
- (void)failedTransaction:(SKPaymentTransaction *)transaction {
NSLog(#"failedTransaction...");
if (transaction.error.code != SKErrorPaymentCancelled)
{
NSLog(#"Transaction error: %#", transaction.error.localizedDescription);
}
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
i solved the my question :) i just added this line [[SKPaymentQueue defaultQueue] removeTransactionObserver:self]; and now it is working ...:)
-(void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions{
for (SKPaymentTransaction *transaction in transactions) {
switch (transaction.transactionState) {
case SKPaymentTransactionStatePurchasing:
break;
case SKPaymentTransactionStatePurchased:{
//I added this line.
[[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
NSLog(#"_mainDict = %#",_mainDict);
float _csize = (float) 0 / 1024;
float _tsize = (float) [[_mainDict valueForKey:#"Size"] integerValue] / 1024;
NSString *strDownload = [NSString stringWithFormat:#"downloading \n (%0.2f MB/%.2f MB)",_csize,_tsize];
[SVProgressHUD showProgress:0 status:strDownload maskType:SVProgressHUDMaskTypeBlack];
[service servicePicList];
[[SKPaymentQueue defaultQueue]finishTransaction:transaction];
break;
}
case SKPaymentTransactionStateRestored:{
[[SKPaymentQueue defaultQueue]finishTransaction:transaction];
break;
}
case SKPaymentTransactionStateFailed:
{
if (transaction.error.code != SKErrorPaymentCancelled) {
NSLog(#"An error encountered");
}
[[SKPaymentQueue defaultQueue]finishTransaction:transaction];
break;
}
}
}
}

Resources