How to test SKPaymentTransactionStateDeferred?

2019-01-30 09:43发布

问题:

iOS 8 will be rolling out soon. We have Xcode beta 6 atm, but still cannot find any docs on how to properly test Family Sharing (or did I miss something?). My question is how to properly setup Sandbox with parent/child? I tried to make it work in beta 1 without joy.

Any hints guys?

Update:

Two related stories on Apple Developer Forum:

  1. How to create a children sandbox account on iTunes Connect?(https://devforums.apple.com/message/1030357#1030357)
  2. Testing "Ask to Buy" in sandbox (https://devforums.apple.com/message/1005569#1005569)

回答1:

I've made a little headway on this topic, so thought I'd report in. Plus, I've found an apparent bug, which I've reported to Apple.

What I've done is the following:

1) Create a parent test (sandbox) account in iTunes Connect, and create a child test account. These are really just two test accounts in iTunes Connect. Call them P and C for parent and child.

2) With both accounts, go to https://appleid.apple.com and change their year for their age. iTunes Connect doesn't let you do this. For some reason, the process with family sharing doesn't work unless ages do have a year. I've found that you have to do the selection twice on the year list at https://appleid.apple.com. Odd. I set my P as older (some adult age) and my C as younger.

3) On one apple device (my iPhone, running iOS8), I setup family sharing under Settings > iCloud for the P account. I'm signed into iTunes on this device with my real iTunes Apple Id (which has my payment info).

4) I then invite my C apple id to be part of my family, under Settings > iCloud.

5) I accept the invitation from P (on my iPad, also running iOS8), which involves signing into the iCloud on that other device as C.

6) On my iPhone, I turn on "Ask To Buy" for the C family member.

Now, I'm ready to try a test purchase as C on my sandboxed app. After I go through the regular process in my app's store I get the following alert:

when I tap on "Ask", I get the next alert:

Now, I've tried two options, with separate purchases. I've tried the "OK" option, which should send a notification to the P account. I have yet to receive such a notification on my P account (still signed into iCloud as that on my iPad).

I've also tried the "Approve in Person" option on the "child"s iPad. I use the P account, and I enter in that if on the next alert:

I get no error after that, so it would seem the Approve In Person worked, but I have yet to have that purchase convert to SKPaymentTransactionStatePurchased state. All of the deferred purchases are still in the payment queue of the app, each with the state SKPaymentTransactionStateDeferred. When I restart the app, the state of each purchase, still in the queue, is deferred.

Next, I wondered if there was some problem with the particular test iTunes account for C, so I made a second child account, call that C2, and tried to establish it as a child under P on my iPhone. However, I run into a further problem there. I get the alert (on the iPad), when I try to accept the invitation to be a family member under P for C2:

To me, this limitation on iCloud account shouldn't apply to test accounts. This is the apparent bug I've reported to Apple.

So, in summary, I'm not yet 100% convinced that my SKPaymentTransactionStateDeferred implementation is working. We shall see if Apple gets back to me.



回答2:

From iOS 8.3 there is a new flag available for SKPayment: simulatesAskToBuyInSandbox.

So in case you need to test SKPaymentTransactionStateDeferred state you initialize new SKMutablePayment and set simulatesAskToBuyInSandbox = YES.

https://developer.apple.com/library/prerelease/ios/releasenotes/General/iOS83APIDiffs/frameworks/StoreKit.html

PS. WARNING: folks complain that this API doesn't work properly (see comments)



回答3:

iOS 9.2.1, Xcode 7.2.1, ARC enabled

Confirmed! The simulatesAskToBuyInSandbox property does not cause the payment queue observer to register the SKPaymentTransactionStateDeferred state. Instead, it just process the payment and the observer registers the SKPaymentTransactionStatePurchased state.

SKMutablePayment *payment = [SKMutablePayment
   paymentWithProduct:productUserRequested];

payment.simulatesAskToBuyInSandbox = true;
[[SKPaymentQueue defaultQueue] addPayment:payment];

The only test I was able to perform was to call my method for the deferred payment when the observer registered the SKPaymentTransactionStatePurchased state instead of my usual method and not call:

[[SKPaymentQueue defaultQueue] finishTransaction:transaction];

This persists the transaction upon app. termination, and gives you the ability to test the user not completing the purchase (e.g. loss of reception during final stages of purchasing) and deferred purchase. This is assuming your purchasing method passes a deferred parameter, as described in Listing 4-2 Responding to transaction statuses in In App Purchasing Guide: Delivering Products. Here is what the method would look like:

To simulate hung up purchasing:

[self showTransactionAsInProgress:transaction deferred:NO];

To simulate deferred:

[self showTransactionAsInProgress:transaction deferred:YES];

Note: Upon app. restart, the Apple in app. purchase mechanism will ask for your credentials if you did not process any other payments for the credentials, uninstalled the app., or signed out of "iTunes and App Stores" in "Settings". Also, if you tap "Cancel" here, then the transaction will not fail, because the payment queue observer will keep registering the SKPaymentTransactionStatePurchased state.

UPDATE 3/4/2016:

I found this suggestion from Apple which might prove to be helpful, it is a fancy way of doing what I suggested:

Test an Interrupted Transaction

Set a breakpoint in your transaction queue observer’s paymentQueue:updatedTransactions: method so you can control whether it delivers the product. Then make a purchase as usual in the test environment, and use the breakpoint to temporarily ignore the transaction—for example, by returning from the method immediately using the thread return command in LLDB.

Terminate and relaunch your app. Store Kit calls the paymentQueue:updatedTransactions: method again shortly after launch; this time, let your app respond normally. Verify that your app correctly delivers the product and completes the transaction.

Hope this helps! Cheers.



回答4:

When creating child account according to Chris Prince's answer, make sure you set its "age" between 13 and 18 years old. If you set it to be less than 13, you can't verify its age (even if you add credit card to your P account). If it's above 18 - option to enable Ask to buy is gone. Spent hours trying to find out what I'm doing wrong.

Also, you need to create C account via iTunes Connect, not via "Create child's account" option in family sharing screen.

Wish I could comment, but since I don't have 50 reputation points, I have to create a separate answer.



回答5:

As it turns out it would appear that the sandbox environment does not support the parent child relationship so the messages will not be sent when the accounts in question are setup as mentioned in the answer by @ChrisPrince.

The article I dug up can be found here: https://forums.developer.apple.com/thread/38561#117143

The snippet of importance from the answer by the apple staff member is

With regards to Ask-To-Buy support, there is no support for this function in the Sandbox. “Ask to Buy” is not an API implementation, but a support process implemented by iTunesConnect which requires StoreKit interaction with a specific iTunes account. This support only exists in the production environment. For this process to work in the sandbox environement, ITC would need to implement for test accounts to refer to other accounts to grant approval for purchases.

The rest of the article highlights the guidelines and flows for Ask to Buy support but testing must be done in the production environment where the child/parent account relationship is active.