StoreKit Test

RSS for tag

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

Posts under StoreKit Test tag

68 Posts
Sort by:

Post

Replies

Boosts

Views

Activity

StoreKit 2: Issue with Subscription Validation in Sandbox
I'm opening this post because I've encountered a perplexing issue in my application utilizing StoreKit 2 with the Sandbox environment for subscription validation. My app makes a server call each time it opens to verify if there's an active subscription. The problem arose after successfully making a purchase in the Sandbox. When I clear history from the Sandbox user and reopen the app, it resends a request to check the subscription, indicating that the user is still subscribed even though the purchases were deleted. Has anyone encountered a similar issue? if I testing it with transaction manager in Xcode it working well. ` 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) print("# purchased") } else { self.purchasedProductIDs.remove(transaction.productID) print("# canceled") } } } Thank you very much!
0
0
469
Jan ’24
macOS TestFlight app using Xcode environment for IAP
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!
3
1
1.2k
Jan ’24
Beta testers have to keep subscribing to recurring subscriptions
I have an app that I distribute to beta testers via TestFlight. The app has auto-renewable subscriptions. In the sandbox environment the subscriptions expire at an accelerated rate; every hour. They renew up to 12 times. This means that my testers have to re-subscribe every 12 hours. Is there a way to make the sandbox operate at realtime for certain users?
0
0
464
Jan ’24
StoreKit2: Transaction.currentEntitlements returns expired subscriptions (Testing locally with shortened sub periods)
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).
2
1
1.2k
Jan ’24
In-App Purchases Entitlement Key????
Hello, What is the key for In-App Purchases entitlement I can add to my app.entitlements file in my project, so that I can autonomously enable the In-App Purchase capability? I have searched far a wide for this, however, it's unclear where it can be located. I know I can enable this capability manually by opening Xcode -> Selecting the "Signing & Capabilities" tab -> selecting "+ Capability" -> selecting "In-App Purchase" capability. However, this is not really an ideal solution for adding the capability to my app, especially when automated processes for building, testing, distributing via CI/CD are integrated. It would beneficial to be able to reference some documentation or resources for enabling capabilities (or any other build settings) autonomously in a project as opposed to having to manually click my way through enabling them. Looking forward to hearing back. Thanks!
3
0
1.1k
Jan ’24
How to use Sandbox for IAP testing
Need some help here. I've got an iPhone 11 PM on 16.6.1 and I'm trying to test Family Sharing IAPs. However, I can't seem to test via the Sandbox environment (which I need to validate receipt handling for Family Sharing). The app is running locally on my device and was built straight from Xcode. When I tap to make a purchase in my app (which uses StoreKit2, if that makes any difference) a sheet pops up with a purchase button which, when tapped, immediately completes and I get the following dialog box: "Your purchase was successful" [Environment: Xcode] How do I get my app to use the Sandbox environment? All documentation suggestions when I tap my purchase button I should simply be presented with a login modal and then, after the purchase has completed, be able to see my Sandbox credentials under Settings -> App Store. At the moment no dialog is presented (the purchase completes immediately) and the entire "Sandbox Account" section is missing from Settings -> App Store. Any help will be greatly appreciated!
1
0
499
Jan ’24
SKAN not receiving postbacks correctly / wrong attribution to "direct"
SKAN / SkAdNetwork Error ERROR: We never received any http request from the "skan.ourdomain.com" as expected. ERROR: All the attributions(YES! ALL OF THE INSTALLS) in the Google Analytics / Singular / AppsFlyer / Twitter / Facebook, shows the source are "direct organic". We Did These We use Google Ads and Twitter Ads and Facebook Ads to promote our apps. We spent enough money, and got thousands of paid installs from these ads. We set the NSAdvertisingAttributionReportEndpoint to "skan.ourdomain.com". We call the SKAdNetwork.updatePostbackConversionValue(1). in "AppDelegate" and "Subscribe" source codes. And from our app logs, we see there are SKAN_UPDATE_CONVERSION_VALUE_OK. Source Code if #available(iOS 15.4, *) { SKAdNetwork.updatePostbackConversionValue(1) { err in if let err = err { Tracker.shared.reportEvent(.SKAN_UPDATE_CONVERSION_VALUE_FAIL, name: err.localizedDescription, value: 1) } else { Tracker.shared.reportEvent(.SKAN_UPDATE_CONVERSION_VALUE_OK) } } } else { SKAdNetwork.registerAppForAdNetworkAttribution() Tracker.shared.reporxtEvent( .SKAN_UPDATE_CONVERSION_VALUE_OLD_VERSION, name: "AppDelegate") }
0
1
560
Jan ’24
Can't change store kit renewal rate, stuck at every two seconds
I wrote a StoreKit unit test and set the renewal rate to .oneRenewalEveryTwoSeconds for the test session. But now my App expires and renews every two seconds when running normally, even though the StoreKit Configuration file is set to "Real Time." Changing it to anything else doesn't change the renewal rate. I've tried cleaning the build folder. If, however, I set my SKTestSession explicitly to .realTime and run the test again, then my app behaves. However, again, it doesn't matter what I set the Configuration Settings to. Anyone know where this information is stored?
0
0
433
Jan ’24
SKTestSession.buyProduct(identifier: options:) doesn't work in swift package
We are doing a Swift Package to manage our iap with storekit 2. This packages also contains the unit tests for the code. (as well as all the required files .storekit, certificate, ...) when calling SKTestSession.buyProduct(identifier: options:) we catch an error : Error Domain=SKErrorDomain Code=0 "(null)" Note when trying exactly the same code but in a project instead of a package that works perfectly. Any idea what could it be? The code is really simple : var testSession: SKTestSession! override func setUpWithError() throws { testSession = try SKTestSession(configurationFileNamed: "Products") } func testExample() async throws { do { let productID = "nonConsumable.crystal.tier1" try await testSession.buyProduct(identifier: productID) } catch { XCTFail("An error occured during purchase : \(error)") } } }
0
0
379
Jan ’24
How to exit `inBillingRetryPeriod` state in Storekit2
I'm currently testing subscriptions in Sandbox. In AppstoreConnect, I set a grace period of 3 days. I subscribed for a service which expired and now it's inBillingRetryPeriod state. I thought it had to do with my payment method. After updating my payment method, it still remains in that state. I checked Status.RenewalInfo's gracePeriodExpiration and expirationReason values but both produced nil. How do I exit the inBillingRetry state? I'm new to in-app purchases. Thanks. Here's the relevant code that updates subscription status: @MainActor func updateSubscriptionStatus() async { do { guard let product = storeManager.renewables.first, let statuses = try await product.subscription?.status else {return} var highestProduct: Product? = nil var highestStatus: Product.SubscriptionInfo.Status? = nil for status in statuses { switch status.state { case .expired, .revoked: continue default: let verifiedRenewalInfo = try storeManager.checkVerified(status.renewalInfo) //Find the first subscription in the store that matches id on the `status.renewalInfo` guard let newSubscription = storeManager.renewables.first(where: {$0.id == verifiedRenewalInfo.autoRenewPreference}) else { continue } guard let currentProduct = highestProduct else { highestProduct = newSubscription highestStatus = status // next status continue } let currentProductTier = storeManager.tierDuration(for: currentProduct.id) let newTier = storeManager.tierDuration(for: newSubscription.id) if newTier > currentProductTier { //updated product and status highestProduct = newSubscription highestStatus = status } } } currentSubscription = highestProduct // currentSubscription is an @State status = highestStatus // status is an @State if let mySubcriptionStatus = status, case .verified(let renewalInfo) = highestStatus?.renewalInfo { print(mySubcriptionStatus.state) // StoreKit.Product.SubscriptionInfo.RenewalState(rawValue: 3))-- inBillingRetry. print(renewalInfo.expirationReason) // nil print(renewalInfo.gracePeriodExpirationDate) // nil } } catch { print(error) } }
1
0
383
Jan ’24
Storekit2 debug: subscription doesn't exist and code still append a subscription??!! BUG??
I am really frustrated with storekit2, is it me or is it an Apple bug? the subscription doesn't exist LITERALLY and the code still append a subscription to my currentSubscriptions!! Unfortunatelly I cannot attach an image but the susbcrioption doesn't exist in the storekit debug window but the code still append a valid subscription! https://stackoverflow.com/questions/77783897/storekit2-subscription-is-not-existant-and-still-append-subscription-bug // update the customers products @MainActor func updateCustomerProductStatus() async { var purchasedSubs: [Product] = [] var purchasedIAP: [Product] = [] //iterate through all the user's purchased products for await result in Transaction.currentEntitlements { do { //again check if transaction is verified let transaction = try checkVerified(result) //Check the `productType` of the transaction and get the corresponding product from the store. switch transaction.productType { case .consumable: if let iap = iaps.first(where: { $0.id == transaction.productID }) { purchasedIAP.append(iap) } case .autoRenewable: if let subscription = subscriptions.first(where: { $0.id == transaction.productID }) { //SUBSCRIPTION DOESN'T EXIST AND STILL GETS APPENDED!! purchasedSubs.append(subscription) } default: break } } catch { //storekit has a transaction that fails verification, don't delvier content to the user print("Transaction failed verification") } //finally assign the purchased products self.purchasedIAPs = purchasedIAP self.purchasedSubscriptions = purchasedSubs } }
0
0
363
Jan ’24
Store Kit 2 not availiable in Sandbox environment
I have implemented Store Kit for my Swift UI App. I defined all products in app store connect (auto-renewables & non-renewables). I tested everything in Xcode and it seems to run fine. However i want to test it in Sandbox to be able to check the server side dependencies. After creating Sandbox users and logging in to those accounts on my physical device, i am still only able to do payments in Xcode ("[Environment: Xcode]"). I added the In-App Purchase Capability to my project in the Signing & Capability Targets and made sure the app runs in debug mode. So according to the docs (https://developer.apple.com/documentation/storekit/in-app_purchase/testing_in-app_purchases_with_sandbox) everything seems to be set-up.
1
0
421
Jan ’24
Introductory offer does not appear for Sandbox testing
Hi, I currently have an introductory offer set up in App Store Connect, which is in the 'Ready to Submit' state. When testing with the StoreKit configuration testing for Xcode, the introductory offer appears correctly, and I can successfully make and cancel purchases. However, when testing on a device without the StoreKit configuration, using a new sandbox account, the introductory offer does not appear, though the introductory price is visible for subscription. Could you advise on how to ensure the introductory offer is displayed in this scenario? Using Storekit 2
2
0
603
Jan ’24
Error in remote proxy while processing transaction: Error Domain=NSCocoaErrorDomain Code=4097 "connection to service named com.apple.storekitd"
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.
3
0
1.7k
Dec ’23
How to exit `inBillingRetryPeriod` state in Storekit2
I'm currently testing subscriptions in Sandbox. In AppstoreConnect, I set a grace period of 3 days. I subscribed for a service which expired and now it's inBillingRetryPeriod state. I thought it had to do with my payment method. After updating my payment method, it still remains in that state. I am checking Status.RenewalInfo's gracePeriodExpiration and expirationReason values produce nil. How do I exit the inBillingRetry state? I'm new to in-app purchases. Thanks. Here's the relevant code: ... @MainActor func updateSubscriptionStatus() async { do { guard let product = storeManager.renewables.first, let statuses = try await product.subscription?.status else {return} var highestProduct: Product? = nil var highestStatus: Product.SubscriptionInfo.Status? = nil for status in statuses { switch status.state { case .expired, .revoked: continue default: let verifiedRenewalInfo = try storeManager.checkVerified(status.renewalInfo) //Find the first subscription in the store that matches id on the `status.renewalInfo` guard let newSubscription = storeManager.renewables.first(where: {$0.id == verifiedRenewalInfo.autoRenewPreference}) else { continue } guard let currentProduct = highestProduct else { highestProduct = newSubscription highestStatus = status // next status continue } let currentProductTier = storeManager.tierDuration(for: currentProduct.id) let newTier = storeManager.tierDuration(for: newSubscription.id) if newTier > currentProductTier { //updated product and status highestProduct = newSubscription highestStatus = status } } } currentSubscription = highestProduct // currentSubscription is an @State status = highestStatus // status is an @State if let mySubcriptionStatus = status, case .verified(let renewalInfo) = highestStatus?.renewalInfo { print(mySubcriptionStatus.state) // StoreKit.Product.SubscriptionInfo.RenewalState(rawValue: 3) -- inBillingRetry print(renewalInfo.expirationReason) // nil print(renewalInfo.gracePeriodExpirationDate) // nil } } catch { print(error) } }
0
0
394
Dec ’23
Use of SubscriptionStoreView
I am developing my first app and having issues understanding how SubscriptionStoreView works. I used some business logic available from Apple, but I see other resources that insinuate the StoreKit views can handle all of the business logic itself, and all I need is the config file. Can anyone confirm? When I'm previewing SubscriptionStoreView, It just says, "The subscription is unavailable in the current storefront," and I cannot find what that means or what to fix.
1
0
841
Dec ’23
StoreKit test unable to test plan change scenario in iOS 17
I have a unit test case to test subscription plan change scenario, that is working until iOS 16, but the test failed starting iOS 17 and above. Test case setup: let session = try SKTestSession(configurationFileNamed: "IAPTestConfiguration") session.disableDialogs = true session.clearTransactions() // Buy a monthly subscription first try session.buyProduct(productIdentifier: "test.apple.test_mobile.1m") if let transaction = session.allTransactions().first { let id = transaction.identifier // and disable monthly subscription try session.disableAutoRenewForTransaction(identifier: id) } // buy a yearly subscription to create a subscription change scenario. try session.buyProduct(productIdentifier: "test.apple.test_mobile.1y")` Now this is the logic I have to determine that there is going to be a plan change: if let autoRenewPreference = renewalInfo.autoRenewPreference, autoRenewPreference != renewalInfo.currentProductID, renewalInfo.willAutoRenew { // means subscription change } until iOS 16, the above test setup resulted in : renewalInfo.autoRenewPreference = "test.apple.test_mobile.1y" renewalInfo.currentProductID = "test.apple.test_mobile.1m" renewalInfo.willAutoRenew = true But in iOS 17, the above setup seems to be not working because, the second time I try to buy a product seems to have no effect. // This has no effect, when there is already an active subscription, in our case "test.apple.test_mobile.1m" . try session.buyProduct(productIdentifier: "test.apple.test_mobile.1y") I expect there should be at least two transactions with my current setup, in iOS 16 I get 2 transactions when I query session.allTransactions() at the end, but in iOS 17 I only get 1 transaction, which is the first buyProduct, the last buyProduct seems to have no effect, as I do not get any callback in the SKPaymentQueue updateTransactions method for the last buyProduct call. In iOS 16, I get callbacks in SKPaymnetQueue for both buyProduct calls. I also tried to use async buyProduct in iOS 17, and updated my test case accordingly, but it resulted in the same behaviour. Please let me know if you need any other detail that could help sort this issue.
0
0
339
Dec ’23