Auto-renewing subscription: app-store completes transaction despite finishTransaction not called
Asked Answered
B

5

11

I'm simulating purchases of an Auto-renewing subscription in my app on an iPhone. My issue is that the purchase is considered to be done by the App store while it is not.

Here is what is going on:

  1. The user presses a button to purchase the renewing subscription
  2. The user gives his iTunes password and confirms the purchase
  3. The app submits the receipt received from the app store to my server to check validity
  4. The server returns a "ok" or "not ok" string. The app calls finishTransaction only on "ok"

I have an issue when there is a network failure on step 3. I can't validate the receipt. But if the user tries to purchase a second time, the app store tells him that he has already subscribed, even though I didn't call the finishTransaction method to complete the purchase!

Is this an expected behavior? Shouldn't the app-store treat non-finished transactions as non-finished, or am I missing something? I would welcome any suggestion to solve this issue.

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

-(void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions {
    NSLog(@"paymentQueue updatedTransaction");
    for (SKPaymentTransaction * transaction in transactions) {
        switch (transaction.transactionState) {
            case SKPaymentTransactionStatePurchasing:
                break;
            case SKPaymentTransactionStatePurchased:
                [self recordSubscription:transaction];
                break;
            case SKPaymentTransactionStateFailed:
                [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
                break;
            case SKPaymentTransactionStateRestored:
                [self recordSubscription:transaction];
                break;
            default: NSLog(@"Default");
                break;
        }
    };
}


-(void) recordSubscription:(SKPaymentTransaction*)transaction{
    NSString *jsonObjectString = [self encode:(uint8_t *)transaction.transactionReceipt.bytes length:transaction.transactionReceipt.length];
    NSMutableDictionary *params = [[NSMutableDictionary alloc] initWithObjectsAndKeys:jsonObjectString,@"receiptdata", nil];
    [[AFNetworkSubClass sharedClient] postPath:@"myserver" params:params 
    success:^(AFHTTPRequestOperation *operation, id output) {
        /* some code */
        if([valstring isEqualToString:@"ok"]){
            [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
        }
    }
    }failure:^(AFHTTPRequestOperation *operation, NSError *error) {
            NSLog(@"validation failed");
    }
Behring answered 19/11, 2013 at 8:27 Comment(0)
C
1

If you haven't called finishTransaction that doesn't meant the transaction has not taken money from the user. All that call does is prevent StoreKit from notifying your App on the transaction every launch. Its just a means for you to tell StoreKit that you have finished with the transaction i.e. unlocked the users content and saved that to your backend etc.

So even with a network error you should be retrying your API call. If you close the App and reopen you should get a transaction update to indicate it has been 'purchased' giving you time to submit to your server again:)

This is the expected behaviour otherwise you would be double/triple billing users.

Cud answered 8/7, 2016 at 8:52 Comment(0)
C
0

I think before you call recordSubscription method, you can call finish finishTransaction method to remove payment from payment queue because you have finished the purchase action with apple server.

If network failure make you can't validate app receipt, just record the receipt and validate the receipt to your own server again or validate when network is reachable another time.

I hope it can help you.

Cisneros answered 27/11, 2013 at 8:40 Comment(0)
G
0

Users cannot purchase same subscription until it expires. In your case, the purchasing transaction was finished, but you didn't provide the service because of the network failure. I used to have similar problem. You may need to ask the users to restore all completed transactions.

Then completeTransaction function will be called. Good luck!

Gumma answered 29/11, 2013 at 4:50 Comment(0)
A
-1

Just a heads up if your App doesn't fit within the following statement then you will not be able to use Auto-renewing Subscriptions. The following is from the App Review Guidelines;

11.15 Apps may only use auto renewing subscriptions for periodicals (newspapers, magazines), business Apps (enterprise, productivity, professional creative, cloud storage) and media Apps (video, audio, voice), or the App will be rejected

In case your app does fit into this bracket then what you could do setup your app so it considers itself to be temporarily "Subscribed" and it keeps trying to authenticate with the server (notify the user if it has been too long since it was connected to the internet).

Atlanta answered 27/11, 2013 at 4:21 Comment(2)
what comes under enterprise, productivity?Dandy
Enterprise are typically B2B(Business 2 Business) apps where a subscription or licensing (via Subscription) can be used. Enterprise can also be in-house apps, but unless there is a business requirement for a subscription to be in an in-house app you wouldn't use it. Productivity would be something like Evernote, Dropbox ,etc. These don't fit into the Enterprise definition as they are available to the general population and aren't exclusive to BusinessesAtlanta
F
-1

I used to have issues like this with both the app store purchases and the game center. And I know this is going to sound like a non answer, but it worked for me.

I deleted the app and all its data from my device, restarted xcode and cleaned the project. Turned the device on and setup a fresh deployment. And the app started to receive the correct response from the App Store. I'm not sure if it was because something was cached on the device or if the App Store just needed more time to work correctly but things just fell into place after that.

Although I have never worked with subscription based purchases, nothing in your code stands out as incorrect as far as I can tell.

Good luck.

Ferde answered 2/12, 2013 at 22:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.