StoreKit Test

RSS for tag

Create and automate tests in Xcode for your app's submission and in-app purchase transactions.

StoreKit Test Documentation

Posts under StoreKit Test tag

69 Posts
Sort by:
Post not yet marked as solved
1 Replies
1.8k Views
test - https://developer.apple.com/forums/content/attachment/0233d5fd-a2cf-4ac3-843c-b1ce58672dab linkText<script> - https://www.example.com/
Posted
by
Post marked as solved
12 Replies
10k Views
When testing In-App Purchases in Xcode with a .storekit file, I can delete past purchase transactions, so I can re-test the purchase experience. I've switched to using a Sandbox tester and made purchases. However, I cannot find how to delete previous purchase transactions made in the sandbox so I can re-run the tests. Is this possible?
Posted
by
Post not yet marked as solved
2 Replies
1.7k Views
Hello all, Created and tested successfully auto renewal subscription products in my app. Both products offer 7 days free trial. Once purchased for the first time, isEligibleForIntroOffer value was true and when I tried to subscribe again later, the value is false - everything worked as expected. However, when I reset the eligibility for my sandbox user through the edit subscription screen, I do see that the Free Trial offering becomes available again, as expected, but when I test it in the app, the value for isEligibleForIntroOffer is still false. The value is false for the group (Product.SubscriptionInfo.isEligibleForIntroOffer(for: renewableSubscription.subscriptionGroupID)) and also for the product (renewableSubscription.isEligibleForIntroOffer). iOS 15.4. Is this a bug? Can I still trust this property value as the only source to check whether the user is eligible for intro in production? Thanks a lot.
Posted
by
Post marked as solved
3 Replies
1.3k Views
I am trying to test Ask to Buy for consumable product. When the transaction was approved, I can get verified transaction in Transaction.updates, meaning the process stops at a breakpoint in Transaction.updates. However, when I call Transaction.currentEntitlements after that, I cannot handle transaction as consumable. Am I missing anything? Here is my code. func newTransactionListenerTask() -> Task<Void, Never> { Task(priority: .background) { for await verificationResult in Transaction.updates { guard case .verified(let transaction) = verificationResult,             transaction.revocationDate == nil         else { return }         // Breakpoint stops here await refreshPurchasedProducts()         await transaction.finish()         }    } } func refreshPurchasedProducts() async { for await verificationResult in Transaction.currentEntitlements { guard case .verified(let transaction) = verificationResult else { return } switch transaction.productType { case .consumable: // This code is not called             updateConsumablePurchaseCount(productID: transaction.productID)         default:             break }     } }
Posted
by
Post not yet marked as solved
11 Replies
5.8k Views
Hi, thanks for reading my question. I need help with some odd behaviour with product.purchase() not triggering a confirmation dialog after a subscription has expired and trying to purchase it again. Seeing this in iOS 16.2 and 15.7.2 (haven't tried any other versions) on actual devices, not in simulator. I'm using a sandbox user on the sandbox environment (not using the local store kit config file testing option). Using a newly created sandbox user, first subscription purchase goes through just fine, dialog box pops up, login with sandbox user, get confirmation of purchase and then Transaction.currentEntitlements has one item as expected. It auto renews for 12 times (each time Transaction.currentEntitlements contains the correct results) and then expires, as expected for sandbox. Transaction.currentEntitlements is then also empty, as expected. All good so far. Now I want to test purchasing it again...Call product.purchase() again to renew/start a new subscription and nothing happens, no confirm purchase dialog box pops up at all. The purchase function simply exits BUT returns success (as in the following gets called) but in self.updatePurchasedProducts(), Transaction.currentEntitlements is empty. case let .success(.verified(transaction)):      // Successful purchase       await transaction.finish()      await self.updatePurchasedProducts() if I instead go to Settings->App Store->Sandbox User-> Manage Subscriptions and renew the subscription there, instead of in my app, then Transaction.currentEntitlements has a new entry and all is good again. Alternatively, if I create yet another new sandbox user and logout of the old one I was using, I am once again able to purchase from within the app, so .purchase() once again works as normal. Is there something I am missing about expired subscriptions and trying to purchase them again in the app? Is this a sandbox issue and in production I'll have no problem? The sandbox user has purchasing enabled in Settings->App Store. I've also tried calling AppStore.sync() (which is in my "Restore Purchase" button) before calling product.purchase() after the subscription stops renewing, expires and this issue comes up, doesn't resolve it. Also have a less important question, the initial call to product.purchase(), the one that works as expected, has a bit of a delay before the confirmation dialog pops up, a few seconds, which will probably result in the user clicking the buy button again thinking it didn't work. Is a bit of a delay normal for sandbox? Will it be ok in production? When it fails, and I have to renew in Settings->AppStore->Sandbox user, there's also a bit of a delay after I return to my app, 5-15 or so seconds, before the transaction observer fires and currentEntitlements is checked again, is there a way to reduce this delay? Thank you! Colin @MainActor class IAPManager: NSObject, ObservableObject {  // removed other functions.....   func purchase(_ product: Product) async throws {    let result = try await product.purchase()     switch result {    case let .success(.verified(transaction)):      // Successful purchase       await transaction.finish()      await self.updatePurchasedProducts()    case let .success(.unverified(_, error)):       break     case .pending:       break     case .userCancelled:       break     @unknown default:       break   } }  func updatePurchasedProducts() async {     for await result in Transaction.currentEntitlements {       guard case .verified(let transaction) = result else {         continue       }       if transaction.revocationDate == nil {         self.purchasedProductIDs.insert(transaction.productID)       } else {         self.purchasedProductIDs.remove(transaction.productID)       }     }   } }
Posted
by
Post not yet marked as solved
3 Replies
1.5k Views
import StoreKitTest try SKTestSession(configurationFileNamed: "Configuration") Xcode Version 14.1 (14B47b) iOS14.* Configuration.storekit file created when running this test code will testing failed, can anyone tell me how to solve this problem? iOS15 and iOS16 is no problem Failed to load the test bundle. If you believe this error represents a bug, please attach the result bundle *** Underlying Error: The bundle *** couldn’t be loaded because it is damaged or missing necessary resources. The bundle is damaged or missing necessary resources. Try reinstalling the bundle *** Reason: Incompatible library version: StoreKitTest requires version 1.0.0 or later, but XCTest provides version 0.0.0))
Posted
by
Post not yet marked as solved
1 Replies
741 Views
Hi We are adding subscriptions auto-renewable in our app. Subscription will be one month, auto-renewable. We are testing in sandbox. Results of Transaction.currentEntitlements and Transaction.all are sometimes not available : for example, we buy a subscription, we always well receive the hook sent (responseBodyV2DecodedPayload is correct), so subscription is active BUT when we ask Transaction.currentEntitlements, result is no subscription available, neither to Transaction.all (for this one, last transaction is not present) - this problem happens in around 20% of tests. possibly, once the auto-renew is done (5 minutes later, because of sandbox) everything works fine OR not Is it possible that in sandbox, behavior is a bit "random", not 100% safe ? Thanks for any help :)
Posted
by
Post not yet marked as solved
2 Replies
986 Views
Hello everyone, I am writing to inquire about a strange behavior that I encountered while using StoreKit 2 on watchOS 9.1 and Xcode 14.2. Specifically, when using the Transaction.currentEntitlements method, it returns refunded non-consumable purchases alongside valid ones. Additionally, I have observed that Transaction.updates does not notify me of refunded purchases or cancelled subscriptions while testing on my local environment with Xcode. When implementing the same code with an iOS app, it works as expected, indicating that this may be a watchOS-specific issue. This behavior is unexpected, and I am unsure if this issue also occurs in a production environment. Can anyone please help me with this issue? Thank you in advance.
Posted
by
Post not yet marked as solved
2 Replies
1.6k Views
I am working on a billing implementation in UnityIAP. Recently, when I press the billing button on iOS, I get an Unknown error the first time, I checked the logs and found the following error. <SKPaymentQueue: 0x2823b65c0>: Error in remote proxy while processing transaction: Error Domain=NSCocoaErrorDomain Code=4097 "connection to service named com.apple.storekitd" UserInfo={NSDebugDescription=connection to service named com.apple.storekitd}\ Special conditions, When this is occurring, addTransactionObserver is being called after the purchase order. If addTransactionObserver is called for a paymentQueue during the purchase process, would this error be called? Or if there is any problem on the AppleStore side, I would appreciate it if you could let me know. Thank you in advance.
Posted
by
Post not yet marked as solved
0 Replies
449 Views
Hi, I'm looking for the way to clear history purchases in TestFlight Environment. In my app, there is non-consumable item, I purchased it and now I'd cancel it to test another functionality. But I cannot find any related guideline or docs about clear history purchases in TestFlight Environment not Sandbox Do you have any idea or suggestion without creating new test account?
Posted
by
Post not yet marked as solved
1 Replies
840 Views
I have been stuck on this issue for a long time. I'm a newer in Swift and I couldn't find a way to solve this problem. I got the receipt data from my App, the code is, if let appStoreReceiptURL = Bundle.main.appStoreReceiptURL, FileManager.default.fileExists(atPath: appStoreReceiptURL.path) { do { let receiptData = try Foundation.Data(contentsOf: appStoreReceiptURL, options: .alwaysMapped) print(receiptData) // Read ReceiptData print("receipt: \(receiptData.base64EncodedString(options: []))") } catch { print("Couldn't read receipt data with error: " + error.localizedDescription) } } which is copied from sample code from Apple Developer Document. And this is one of the receipt data got from sandbox environment, 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 But when I use it to verify in sandbox environment, I always got 21002 error. Then I found some receipt data from stackoverflow https://stackoverflow.com/questions/33843281/apple-receipt-data-sample/53286406#53286406 . I use them to test my python code, it works. Here is the python code, receipt = "xxxxxx" url = 'https://sandbox.itunes.apple.com/verifyReceipt' headers = {"Content-type": "application/json"} data = json.dumps({"receipt-data": receipt}) res = requests.post(url=url, data=data, headers=headers, verify=False).text print(res) So, it seems that it's the receipt data I got from Apple wrong. I don't know why the receipt data is wrong. Is there anyway to find out the problem? I'm using XCode (Version 14.1 beta 2 (14B5024i)) and a iphone SE to make a test. It purchased and verified according to StoreKit 2.
Posted
by
Post not yet marked as solved
1 Replies
1.2k Views
Greetings community! A) I am trying to implement Apple In-App-Purchases for a new iOS app/game. B) I have a client-server application, and the purchase validation and entitlement grant needs to happen on our game-server. As best as I can tell, I want to use Get Transaction History to validate the purchase on the game server. I'm testing a sandbox app/APIs using TestFlight. My generated transactionID's are sequential integers starting at 0, but some documentation suggests it should be a UUID. So far, the integer transactionID/originalTransactionID have not yielded a valid response from GetTransactionHistory. The errors I get are: {"errorCode":4000008,"errorMessage":"Invalid original transaction id."} {"errorCode":4040005,"errorMessage":"Original transaction id not found."} I'm mostly stumped at this point, as I can't find any documentation describing what I may have missed, and there are no other forum posts or search results for those error codes. So my questions: Will GetTransactionHistory ever this work with sequential integer transactionIDs? I've deployed the signed app through TestFlight, and I'm still getting sequential integer transactionIDs. Is that expected? What am I doing wrong?
Posted
by
Post not yet marked as solved
2 Replies
1.1k Views
Hi, title says it all: I have Transaction.currentEntitlements returning expired subscriptions (testing both transaction expirationDate & RenewalState). Environment: local via .storekit file. Subscription duration is shortened for testing. Could it be the issue? The sub duration is normally 1 year. The documentation says it should only returns active subscription (RenewalState.subscribed) or in grace period (RenewalState.inGracePeriod).
Posted
by
Post not yet marked as solved
0 Replies
611 Views
I am trying to test two apps using TestFlight. I have two separate "feature POC" apps that we publish to TestFlight for testing. One of them is an IAP feature app which utilizes in-app-purchases. IAP documentation talked about the necessity of using "sandbox tester" users, so I've been resetting the user between dev and sandbox user accounts on my phone. I've accidentally locked myself out of TestFlight access by doing this. I have two apps that I've granted myself TestFlight access, but only one shows on TestFlight on my phone. I've tried revoking and re-adding my account, but it says "Installed" as the status, instantly upon re-adding myself to the app's users. It won't send me another invite, and I can't see the app in TestFlight. I've even tried redeeming the old code, and it says it's already been used. It WAS used... on this device for this user, but it still doesn't come back. How can I fix this?
Posted
by
Post not yet marked as solved
1 Replies
782 Views
So trying to release a new (iOS/iPadOS) app and I'm in endless rejection purgatory trying to get it approved along with its first In App purchase product (an auto-renewable subscription). This is the final issue holding back the release and I do not know how to get out of this rejection loop. First, yes, In App purchase works fine when testing in the sandbox environment. My In App purchase infrastructure is based on the well-regarded StoreHelper Swift package and works great in all my testing. The rejection is based on the fact the "store" in my app always displays an empty products list when Apple reviews the app. Of course, since they haven't approved my lone subscription product, which has a status of 'Waiting for Review' I'm not surprised they see an empty store, but Apple is apparently surprised and refuses to stop being surprised. All they do is toss a link to the StoreKit documentation at me. So I pore over it looking for clues. Hmm. Hmm. Yeah I know this, I do this, what are you not telling me? So I'm climbing the walls trying to figure out if indeed I'm overlooking something. Apple, like a pedantic college professor, apparently wants me to figure out on my own. Well I can't. I can't find the secret handshake. So questions: When I create my .storekit configuration file I do so by syncing with my App in App Store Connect. This works dandy, but do I or do I not include this configuration file with the distribution build I submit for review? I can't find any info on whether this is only for testing or for both production and testing, and since I have to manually add it to my project after creating it, I worry that's not how it's intended to be used. So do I add the .storekit bundle to my app target and leave it there during distribution? (Note: I already do so, wondering if I should not) Since I'm using fastlane to produce and upload my builds, how can I be sure this StoreKit Configuration is being set correctly (right now I use the pop-up in the Options tab of my Release scheme)? Does it even need to be set when distributing? I assume so. Apple has this strange ambiguous language about "your first In App purchase must be submitted with a new build". Well, early on there was indeed a way to add my not yet approved Subscription product with the build review request, but now that's gone. So I have this subscription product sitting in "Waiting for Review", I have my working app that can't get approved because it can't see the not yet approved subscription product. Though maybe it can't see it for reasons other than it's not approved yet. Do I just... wait and hope Apple eventually moves my Subscription product to an approved status and submit again? At my wits end as this is now rejection round 6. I've heard horror stories of similar first In App purchase doom loops going a dozen or more rejection rounds. Developing the app was hard enough but to be stuck in this maddening bureaucracy is killing me. Many thanks in advance!
Posted
by
Post not yet marked as solved
1 Replies
493 Views
Here is the code, I tried two ways to make a test, pids = [ "me_xxxxxxxx_xxxxxxxx_sub_pro_yearly" , "me_xxxxxxxx_xxxxxxxx_sub_pro_lifetime" ] L.d { "Requesting products from apple: \(pids)" } let appProducts = try await Product.products(for: pids) What's wrong with the code I copied from Apple Store Document? The product info was configed on Apple Store Connect, and it's waiting to commit now. It proved that the configuration of product is fine. I tired to use XCode storekit configuration to request product info, It also works fine. So, I don't know why? Here is detail of the log, Error Domain=ASDErrorDomain Code=500 "(null)" UserInfo={NSUnderlyingError=0x280303c00 {Error Domain=AMSErrorDomain Code=1 I logged Sandbox account in iPhone (Setting-Apple Store-Sandbox). It used to work well and I even made a purchase. But with no reason, it doesn't work any more! And yesterday, I was even unable to log in the Apple Store Connect suddenly with no reason. And I contacted you for support, not work. Few hours later, it worked as usual.
Posted
by
Post not yet marked as solved
3 Replies
1.1k Views
I don't know how this happened or how to reset this, but I can't test the StoreKit part of my TestFlight app anymore. When I try to retrieve or buy products (IAPs), I get all kinds of strange behavior. I think it is caused by storekitagent thinking the app is in "Xcode sandbox environment". One of the errors from storekitagent looks like this: [51852D62] [LoadSubscriptionStatusTask]: Subscription status request failed with error - Error Domain=NSURLErrorDomain Code=-1003 "A server with the specified hostname could not be found." UserInfo={AMSStatusCode=0, _NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <468756B3-DA53-4FED-B35C-E093954C27D8>.<1>, NSErrorFailingURLKey=http://localhost:49828/inApps/subscriptions?guid=98DD60024C21&reason=push, _kCFStreamErrorDomainKey=10, _NSURLErrorRelatedURLSessionTaskErrorKey=( "LocalDataTask <468756B3-DA53-4FED-B35C-E093954C27D8>.<1>" ), NSLocalizedDescription=A server with the specified hostname could not be found., NSErrorFailingURLStringKey=http://localhost:49828/inApps/subscriptions?guid=98DD60024C21&reason=push, NSUnderlyingError=0x122f638d0 {Error Domain=kCFErrorDomainCFNetwork Code=-1003 "(null)" UserInfo={_NSURLErrorNWPathKey=satisfied (Path is satisfied), interface: lo0, _kCFStreamErrorCodeKey=-72000, _kCFStreamErrorDomainKey=10}}, _kCFStreamErrorCodeKey=-72000} It looks like it's trying to connect to a local server instead of contacting Apple's App Store servers. I'm on the latest macOS and Xcode. Any help is greatly appreciated:) Thanks!
Posted
by
Post not yet marked as solved
0 Replies
475 Views
On iOS 15 with Xcode 14.3, Product.priceFormatStyle does not appear to be populated with valid data when running unit tests and setting up an SKTestSession. If I try to access the property in the debugger (po product.priceFormatStyle) it hangs Xcode indefinitely. If I use a print statement, I get the following output. Currency(locale: xx_XX (fixed), currencyCode: "", collection: Foundation.CurrencyFormatStyleConfiguration.Collection(scale: nil, precision: nil, group: nil, signDisplayStrategy: nil, decimalSeparatorStrategy: nil, rounding: nil, roundingIncrement: nil, presentation: Foundation.CurrencyFormatStyleConfiguration.Presentation(option: Foundation.CurrencyFormatStyleConfiguration.Presentation.Option.standard))) The same output when running on iOS 16 is: Currency(locale: en_US@currency=USD (fixed), currencyCode: "USD", collection: Foundation.CurrencyFormatStyleConfiguration.Collection(scale: nil, precision: nil, group: nil, signDisplayStrategy: nil, decimalSeparatorStrategy: nil, rounding: nil, roundingIncrement: nil, presentation: Foundation.CurrencyFormatStyleConfiguration.Presentation(option: Foundation.CurrencyFormatStyleConfiguration.Presentation.Option.standard))) A simple test to replicate the issue is: let session: SKTestSession = try! SKTestSession(configurationFileNamed: "Subscriptions") override func setUpWithError() throws { session.resetToDefaultState() session.disableDialogs = true session.clearTransactions() session.storefront = "USA" } func testPriceFormat() async throws { guard let product = try await Product.products(for: ["test.product"]).first else { XCTFail() return } XCTAssertEqual(product.priceFormatStyle.currencyCode, "USD") // Fails on iOS 15 with testPriceFormat(): XCTAssertEqual failed: ("") is not equal to ("USD") } It seems to be working fine when run on the live app using App Store data; I get the same output on both iOS 15 and 16. These outputs are using the same test StoreKit configuration. Is there a trick to getting this working for iOS 15?
Posted
by