I implemented IAP in my app with this code:
-(void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
for (SKPaymentTransaction *transaction in transactions)
{
[_loadingIndicator startAnimating];
switch (transaction.transactionState) {
case SKPaymentTransactionStatePurchased:
[self unlockPurchase];
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
break;
case SKPaymentTransactionStateRestored:
[self unlockPurchase];
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
break;
case SKPaymentTransactionStateFailed:
NSLog(#"Transaction failed");
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
break;
default:
break;
}
}
}
When purchase button is pressed and an alert view pops up and asks for Apple ID and password, if user presses Cancel button, the code goes into SKPaymentTransactionStatePurchased: case and the app unlocks the product. What is wrong with the code?
I found what was going on. Local IAP Store tweak from Cydia was running.
I installed it to check if it is possible to bypass ITunes Store with this tweak and find a workaround to prevent it and then I forgot to turn it off.
Related
I have successfully implemented IAP in ios sdk.
But the problem is when user click on Restore purchase button I initiate the restore by this code:
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
And also I have written this code to handle and initiate the purchase:
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions{
for(SKPaymentTransaction *transaction in transactions){
switch(transaction.transactionState){
case SKPaymentTransactionStatePurchasing: NSLog(#"Transaction state -> Purchasing");
//called when the user is in the process of purchasing, do not add any of your own code here.
break;
case SKPaymentTransactionStatePurchased:
//this is called when the user has successfully purchased the package
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
[SVProgressHUD dismiss];
[self doRemoveAds]; //you can add your code for what you want to happen when the user buys the purchase here, for this tutorial we use removing ads
break;
case SKPaymentTransactionStateRestored:
[SVProgressHUD dismiss];
NSLog(#"Transaction state -> Restored");
//add the same code as you did from SKPaymentTransactionStatePurchased here
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
break;
case SKPaymentTransactionStateFailed:
[SVProgressHUD dismiss];
//called when the transaction does not finish
if(transaction.error.code == SKErrorPaymentCancelled){
[SVProgressHUD dismiss];
NSLog(#"Transaction state -> Cancelled");
//the user cancelled the payment ;(
}
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
break;
}
}
}
When I select Restore then A dialogs come which ask for password. When I cancel it The progress hud doesn't hides.
How can I do this. How to update UI when user cancel purchase in between the process.
Here is the image.
EDIT now when i use the delegate method
- (void)paymentQueue:(SKPaymentQueue *)queue restoreCompletedTransactionsFailedWithError:(NSError *)error
{
[SVProgressHUD dismiss];
}
When It asks for password the SVProgressHUD hides. No matter I press cancel or OK. How to handle this.
And How to update the UI and continue Purchase when user enters correct password.
Your delegate should implement this method:
- (void)paymentQueue:(SKPaymentQueue *)queue restoreCompletedTransactionsFailedWithError:(NSError *)error
The error in this case will indicate a cancel action.
I have a problem which either allows me to download apple hosted content or finishTransaction but not both;
#pragma mark -
#pragma mark SKPaymentTransactionObserver methods
-(void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
for (SKPaymentTransaction *transaction in transactions)
{
switch (transaction.transactionState)
{
case SKPaymentTransactionStatePurchasing:
NSLog(#"Purchasing");
break;
case SKPaymentTransactionStatePurchased:
NSLog(#"Transaction State Purchased");
[[SKPaymentQueue defaultQueue]startDownloads:transaction.downloads];
break;
case SKPaymentTransactionStateFailed:
NSLog(#"Transaction State Failed");
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
[[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
[self failedTransaction:transaction];
break;
case SKPaymentTransactionStateRestored:
NSLog(#"Transaction State Restored");
[[SKPaymentQueue defaultQueue] startDownloads:transaction.downloads];
buyButton.enabled = NO;
[buyButton setTitle:#"Purchased"
forState:UIControlStateDisabled];
//break;
default:
break;
}
}
}
- (void)paymentQueue:(SKPaymentQueue *)queue updatedDownloads:(NSArray *)downloads;
{
for (SKDownload *download in downloads) {
switch (download.downloadState) {
case SKDownloadStateFinished:
NSLog(#"Completing transaction-B");
[self processDownload:download];
[queue finishTransaction:download.transaction];
[[SKPaymentQueue defaultQueue] finishTransaction:download.transaction];
[[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
break;
case SKDownloadStateActive:
NSLog(#"%f", download.progress);
NSLog(#"%f remaining", download.timeRemaining);
break;
default:
break;
}
}
}
-(void)completeTransaction:(SKPaymentTransaction *)transaction
{ //checked!!
NSLog(#"Complete transaction");
//[[SKPaymentQueue defaultQueue]finishTransaction:transaction];
buyButton.enabled = NO;
[buyButton setTitle:#"Purchased"
forState:UIControlStateDisabled];
}
generally the code works fine;
the product is displayed
I can select to buy
login request
then as per the code above the download works and is processed (moved to the Document directory).
However, if i finishTransaction in updatedTransactions then the download will not occur. (makes sense!)
if I call [self completeTransaction:transaction] to finishTransaction from updatedTransactions I get the same.
If i neglect to call completeTransaction (as per the code) then content is downloaded but then I can't seem to call finish transaction.
where/how do I call finish transaction?
so close but so far!!!
I was calling finish transaction too early and my download was not able to finish.
When I opened app it's popup's iTunes login with out any interaction of user.That popup contains my old test user account mail id sometimes my current testuser mail id aslo.I heard that i have to call
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
I called it several times where ever I thought it's needed.But still it's asking password.
And here is my code:
-(void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
for(SKPaymentTransaction *transaction in transactions)
{
NSLog(#"Updated transaction %#",transaction);
switch (transaction.transactionState)
{
case SKPaymentTransactionStateFailed:
[self errorWithTransaction:transaction];
[[SKPaymentQueue defaultQueue]finishTransaction:transaction];
break;
case SKPaymentTransactionStatePurchasing:
NSLog(#"Purchasing...");
break;
case SKPaymentTransactionStatePurchased:
{
if(no need to download)
{
// I will download the content later by restoring transactions.
[[SKPaymentQueue defaultQueue]finishTransaction:transaction];
}
else
{
[[SKPaymentQueue defaultQueue] startDownloads:transaction.downloads];
}
}
case SKPaymentTransactionStateRestored:
{
if(no need to download content)
{
[[SKPaymentQueue defaultQueue]finishTransaction:transaction];
}
else
{
[[SKPaymentQueue defaultQueue] startDownloads:transaction.downloads];
}
}
break;
default:
break;
}
}
-(void) paymentQueue:(SKPaymentQueue *)queue updatedDownloads:(NSArray *)downloads
{
for (SKDownload *download in downloads)
{
switch (download.downloadState)
{
case SKDownloadStateActive:
{
// showing download progress
}
case SKDownloadStateCancelled:
{
[[SKPaymentQueue defaultQueue] finishTransaction:download.transaction];
}
case SKDownloadStateFailed:
{
// showing alert and finish transactions
[[SKPaymentQueue defaultQueue] finishTransaction:download.transaction];
}break;
case SKDownloadStateFinished:
{
// processing content and finished the transactions
[[SKPaymentQueue defaultQueue] finishTransaction:download.transaction];
}break;
}
}
}
Is this correct and is there any place to call finishTransaction: method.Please let me know is any...
thanks in advance..
Anybody know how to make restore option using IAP.
I use non consumable product for purchase.
I know that I have to implement this delegate methods:
- (void)restoreTransaction:(SKPaymentTransaction *)transaction
- (void)paymentQueue:(SKPaymentQueue *)queue restoreCompletedTransactionsFailedWithError:(NSError *)error
- (void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue
but I still can not figure out with a process invoke this method.
I assume that I need to invoke this method [[SKPaymentQueue defaultQueue] restoreCompletedTransactions]; before I get invoke callback method.
Can you explain step by step how it work.
You assume right! The only thing you have to invoke is:
[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
This restores all the completed transactions that the user has made. For each transaction this SKPaymentTransactionObserver method is called (the same method is also called each time a user makes a purchase):
- (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];
break;
default:
break;
}
}
}
Using the transactionState you can distinguish whether the transaction was a original purchase (SKPaymentTransactionStatePurchased) or a restore (SKPaymentTransactionStateRestored) if you need to do that.
If you need to know when the restore is finished you can use:
- (void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue {
NSLog(#"%d items restored", queue.transactions.count);
}
iOS In-App purchases: When and why does SKPaymentTransactionStateRestored get sent back as status of a transaction?
Does it related to having a recurring subscription plan?
You get SKPaymentTransactionStateRestored transactions instead of SKPaymentTransactionStatePurchased transactions when you are restoring the user's purchases by sending a restoreCompletedTransactions message to the SKPaymentQueue.
General rule is to process both callbacks: for purchase and restore purchase.
- (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) completeTransaction: (SKPaymentTransaction *)transaction
{
[self recordTransaction: transaction content:transaction.payment.productIdentifier];
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
- (void) restoreTransaction: (SKPaymentTransaction *)transaction
{
[self recordTransaction: transaction content:transaction.originalTransaction.payment.productIdentifier];
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}