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

81 Posts
Sort by:

Post

Replies

Boosts

Views

Activity

Business model changes by using the app transaction
Hello, I’m trying to change my business model within the app, and following Apple’s documentation guidelines HERE I created this task in the main view of the app. It seems to work perfectly in the simulator, on physical devices, and on TestFlight. However, after releasing it to production and uploading the new version to the App Store, it doesn’t work, and all users, whether new or existing, are asked to subscribe. In the console, it appears to retrieve the transactions correctly, but in production, I’m not sure how to view the console or see what it’s retrieving. Here the sandbox receipt I obtained AppTransaction.shared obtained: { "applicationVersion" : "1", "bundleId" : "com.anestesiaIB.Drugs-Infusion-Calc", "deviceVerification" : "6M0Nnw14nSEOBVTPE\/\/EfnWSwLm7LFSlrpFEwxgH74SBHp5dSzBEm896Uvo42mwr", "deviceVerificationNonce" : "8a8238c0-0aee-41e6-bfb0-1cfc52b70fb6", "originalApplicationVersion" : "1.0", "originalPurchaseDate" : 1375340400000, "receiptCreationDate" : 1737577840917, "receiptType" : "Sandbox", "requestDate" : 1737577840917 } This are the processing log while verified the receipt New business model change: 1.7 Original versionéis components: ["1", "0"] Major version: 1, Minor version: 0 This user is premium. Original version: 1.0 This is my task... .task { do { let shared = try await AppTransaction.shared if case .verified(let appTransaction) = shared { let newBusinessModelVersion = (1, 7) // Representado como (major, minor) let versionComponents = appTransaction.originalAppVersion.split(separator: ".") if let majorVersion = versionComponents.first.flatMap({ Int($0) }), let minorVersion = versionComponents.dropFirst().first.flatMap({ Int($0) }) { if (majorVersion, minorVersion) < newBusinessModelVersion { self.premiumStatus.isPremium = true isPremium = true } else { let customerInfo = try await Purchases.shared.customerInfo() self.premiumStatus.isPremium = customerInfo.entitlements["premium"]?.isActive == true isPremium = self.premiumStatus.isPremium } } else { print("Error: obteining version components") } } else { print("Not verified") } } catch { print("Error processing transaction: \(error.localizedDescription)") } }
0
0
17
1h
I don't understand apple store server to server notification
Hello, I'am trying to validate a new app from apple. I have configured sandbox url and production url for server to server apple store notification. I have created subscriptions product id, but there are no validated yet by apple. When I upload my app to testflight, I can't test sandbox notification cause the product id are not available, on local xcode with storekit file I got my product Id but I don't receive notification. So my question is how can I test there thing. I have to produce fake product id ? I'm lock its very complex process, I don't understand. I tried to send my app like that for verification but the team told me to use receipt, but its deprecated and notification webhook is better for me. What is the good order, validate my subscription product ID then test ? what is the good steps. Apple seems to don't want validate my subscription product ID I'm lock..
0
0
36
1d
TestFlight Subscription Issue
Hi everyone, I'm finally in the final steps of putting my first app online, but I'm encountering an issue during the review process. I need to fix the subscription, but the Sandbox account isn't being triggered in TestFlight. In the logs, I see the main account being requested instead, and the TestFlight payment process isn't starting. Does anyone know a workaround for this? Thanks in advance for your help!
0
0
76
2d
Migrating a Paid App to In-App Subscriptions
Hello, I’m trying to change the business model of my app to in-app subscriptions. My goal is to ensure that previous users who paid for the app have access to all premium content seamlessly, without even noticing any changes. I’ve tried using RevenueCat for this, but I’m not entirely sure it’s working as expected. I would like to use RevenueCat to manage subscriptions, so I’m attempting a hybrid model. On the first launch of the updated app, the plan is to validate the app receipts, extract the originalAppVersion, and store it in a variable. If the original version is lower than the latest paid version, the isPremium variable is set to true, and this status propagates throughout the app. For users with versions equal to or higher than the latest paid version, RevenueCat will handle the subscription status—checking if a subscription is active and determining whether to display the paywall for premium features. In a sandbox environment, it seems to work fine, but I’ve often encountered situations where the receipt doesn’t exist. I haven’t found a way to test this behavior properly in production. For example, I uploaded the app to TestFlight, but it doesn’t validate the actual transaction for a previously purchased version of the app. Correct me if I’m wrong, but it seems TestFlight doesn’t confirm whether I installed or purchased a paid version of the app. I need to be 100% sure that users who previously paid for the app won’t face any issues with this migration. Is there any method to verify this behavior in a production-like scenario that I might not be aware of? I’m sharing the code here to see if you can confirm that it will work as intended or suggest any necessary adjustments. func fetchAppReceipt(completion: @escaping (Bool) -> Void) { // Check if the receipt URL exists guard let receiptURL = Bundle.main.appStoreReceiptURL else { print("Receipt URL not found.") requestReceiptRefresh(completion: completion) return } // Check if the receipt file exists at the given path if !FileManager.default.fileExists(atPath: receiptURL.path) { print("The receipt does not exist at the specified location. Attempting to fetch a new receipt...") requestReceiptRefresh(completion: completion) return } do { // Read the receipt data from the file let receiptData = try Data(contentsOf: receiptURL) let receiptString = receiptData.base64EncodedString() print("Receipt found and encoded in base64: \(receiptString.prefix(50))...") completion(true) } catch { // Handle errors while reading the receipt print("Error reading the receipt: \(error.localizedDescription). Attempting to fetch a new receipt...") requestReceiptRefresh(completion: completion) } } func validateAppReceipt(completion: @escaping (Bool) -> Void) { print("Starting receipt validation...") guard let receiptURL = Bundle.main.appStoreReceiptURL else { print("Receipt not found on the device.") requestReceiptRefresh(completion: completion) completion(false) return } print("Receipt found at URL: \(receiptURL.absoluteString)") do { let receiptData = try Data(contentsOf: receiptURL, options: .alwaysMapped) print(receiptData) let receiptString = receiptData.base64EncodedString(options: []) print("Receipt encoded in base64: \(receiptString.prefix(50))...") let request = [ "receipt-data": receiptString, "password": "c8bc9070bf174a8a8df108ef6b8d2ae3" // Shared Secret ] print("Request prepared for Apple's validation server.") guard let url = URL(string: "https://buy.itunes.apple.com/verifyReceipt") else { print("Error: Invalid URL for Apple's validation server.") completion(false) return } print("Validation URL: \(url.absoluteString)") var urlRequest = URLRequest(url: url) urlRequest.httpMethod = "POST" urlRequest.httpBody = try? JSONSerialization.data(withJSONObject: request) URLSession.shared.dataTask(with: urlRequest) { data, response, error in if let error = error { print("Error sending the request: \(error.localizedDescription)") completion(false) return } guard let data = data else { print("No response received from Apple's server.") completion(false) return } print("Response received from Apple's server.") do { if let json = try JSONSerialization.jsonObject(with: data) as? [String: Any] { print("Response JSON: \(json)") // Verify original_application_version if let receipt = json["receipt"] as? [String: Any], let appVersion = receipt["original_application_version"] as? String { print("Original application version found: \(appVersion)") // Save the version in @AppStorage savedOriginalVersion = appVersion print("Original version saved in AppStorage: \(appVersion)") if let appVersionNumber = Double(appVersion), appVersionNumber < 1.62 { print("Original version is less than 1.62. User considered premium.") isFirstLaunch = true completion(true) } else { print("Original version is not less than 1.62. User is not premium.") completion(false) } } else { print("Could not find the original application version in the receipt.") completion(false) } } else { print("Error parsing the response JSON.") completion(false) } } catch { print("Error processing the JSON response: \(error.localizedDescription)") completion(false) } }.resume() } catch { print("Error reading the receipt: \(error.localizedDescription)") requestReceiptRefresh(completion: completion) completion(false) } } Some of these functions might seem redundant, but they are intended to double-check and ensure that the user is not a previous user. Is there any way to be certain that this will work when the app is downloaded from the App Store? Thanks in advance!
0
0
64
2d
Issues testing subscription in testflight
Hi everyone, I'm finally in the final steps of putting my first app online, but I'm encountering an issue during the review process. I need to fix the subscription, but the Sandbox account isn't being triggered in TestFlight. In the logs, I see the main account being requested instead, and the TestFlight payment process isn't starting. Does anyone know a workaround for this? Thanks in advance for your help! Brice
0
0
100
2d
关于.storekit配置文件无法与Apple store Connect同步产品
I have configured the auto-renewable subscription product through Apple Store Connect, made it available in Xcode via the .storekit configuration file, and successfully purchased it in the testing of the old version. However, during the development of the new version, it seems that I mistakenly opened the .storekit configuration file of the old version, and then one or two pop-up windows appeared (the specific content was similar to saving? I don't quite understand), after that, I found that my new version .storekit configuration file could not automatically sync the auto-renewable subscription product from Apple Store Connect. I can't understand what happened here. 我通过Apple store Connect配置好了自动续期订阅产品,将它在Xcode通过.storekit配置文件配置可用,并且在旧版本的测试中成功购买。 但是,在开发新版本的过程中,我似乎错误的打开了旧版本的.storekit配置文件,然后弹出了一个或者两个弹窗(具体内容类似保存?我不太理解),之后,我发现我的新版本.storekit配置文件无法从Apple store Connect自动同步自动续期订阅产品。 我无法理解这里发生了什么问题。
1
0
86
5d
MacOS App crashes after Apple ID login fails
I tried to get this post into the StoreKit forum because this issue is relative to In-App Purchases. My App has In-App Purchases, which work, no issues here. My App has been on the App Store for a number of years, with changes along the way. Recently, I uploaded V5.1 (Lottery Snitch) for review and the reviewer found something that had eluded everyone, until now. Since my App has In-App Purchases, of course I have Restore In-App Purchases as a User selectable function, on the menu at the top. The reviewer reported my App as crashing when this option was selected, which was a new thing since my App has been functioning for years. Skipping the next several communications and moving on to the most current findings.. If my App is put onto a Mac, iMac.. Where the User has never used my app before (this eliminates leftover data files), if the User then logs out of their Apple ID prior to running my app, starts my app, selects Restore In-App Purchases the User is then presented with Apple's Request to Log-In (this has nothing to do with me..not my code..it is all 100% Apple Login request). Now, completely ignore the request for login, allow my App to complete its wait period, the User can execute any task they wish. The App runs just fine. As soon as the User selects 'Cancel' on the Apple ID login pop-up screen, my App crashes. The Apple Login request is triggered by the restoreCompletedtransactions function for the StoreKit. The crash report indicates the DispatchQueue was the code running at the time. Thing is, my code has no DispatchQueue running. When the wait-timer completes (obvious on-screen loop) my code has zero Dispatch's running. When my code called the restoreCompletedTransactions it was not inside a Dispatch of my creation. Anyone see this before? Anyone have a suggestion how to make this stop? FYI, go ahead and login to your Apple ID when prompted and everything completes just fine. Yes, this problem exists in the current version(V5.0) available for download on the AppStore. It would take another post just as long to explain how this slid by on Development machines, just as weird. What to do? (JSYK:The App does not crash during development when running inside Xcode)
2
0
160
1w
Certificate is not temporally valid
I'm attempting to test an in app purchase for my app on my phone (not in a simulator, not sandbox testing). I'm getting an error that certificate check has failed. Could this have anything to do with the SHA-1 warnings that Apple has recently mentioned? I've tried regenerating my StoreKit file, cleaning the build, restarting XCode, resetting all of my devices purchases from the Debug > StoreKit menu, all with no luck. Any help would be greatly appreciated. 2025-01-10 19:52:19.974564-0500 MyApp[74478:30675548] [Default] Failed to verify certificate chain due to client recoverable failure: Error Domain=NSOSStatusErrorDomain Code=-67818 "“StoreKit Testing in Xcode” certificate is expired" UserInfo={NSLocalizedDescription=“StoreKit Testing in Xcode” certificate is expired, NSUnderlyingError=0x3027b9d40 {Error Domain=NSOSStatusErrorDomain Code=-67818 "Certificate 0 “StoreKit Testing in Xcode” has errors: Certificate is not temporally valid;" UserInfo={NSLocalizedDescription=Certificate 0 “StoreKit Testing in Xcode” has errors: Certificate is not temporally valid;}}} 2025-01-10 19:52:19.978233-0500 MyApp[74478:30675483] [Default] Failed to verify signature for Transaction, will assume invalid: failedToVerifyCertificateChain Purchase succeeded but verification failed: Certificate Chain Invalid Failed to purchase Premium: invalidCertificateChain saveUnencrypted: Started saving form_info.json saveUnencrypted: Saved form_info.json to Documents Directory in 9 ms (JSONEncoder chunk-based copy-on-write, 1 chunks) at ...
0
0
120
1w
"Trouble connecting consumable In-App Purchases (IAP) to App Store Connect"
I am developing an app with support for In-App Purchases (IAP) for consumable products using StoreKit. I have defined the products in ProductList.plist and Product.storekit, but I am unable to connect them correctly to App Store Connect. Here are the details: Products defined in ProductList.plist: Bolet Evento Vip: com.cover.boleto.vip Boleto Evento Básico: com.cover.boleto.basico Configuration in Product.storekit: The products have prices and basic configurations, but they do not seem to link properly in App Store Connect. Steps I have taken: Configured IAP simulation in Xcode. Attempted to register the products in App Store Connect. Issues I am facing: The products are not appearing in App Store Connect after configuration. My app cannot seem to fetch consumable products from App Store Connect. Question: What steps should I follow to correctly register consumable products in App Store Connect and connect the app with StoreKit for production? Any advice or guidance would be greatly appreciated. Thank you!
0
1
203
3w
Cannot Cancel Sandbox Subscription
I did an in app purchase in my development app and now I cannot get rid of it. It is a "monthly" subscription that seems to renew every 1 day. I can see the subscription when I go to settings then tap on Subscriptions. Then I tap the item and choose "Cancel Subscription", revealing a new modal sheet saying "Confirm Cancellation". When I "Confirm", I get the popup: "Your request is temporarily unable to be processed, please try again later". However, this is anything BUT temporary, has gone on for a couple weeks now. As such, I am unable to test subscriptions in my development app. I've tried logging out, restarting, different devices, etc. The phone is logged in under my primary user account, and I may not have been logged into sandbox email when I did the purchase. Can someone forcibly remove it for me?
0
0
209
3w
Introductory offer is not seen on system bottom sheet with Subscribe button.
I have a yearly_subscription subscription in my App Store Connect. I have added an introductory offer for this product - pay up front 6 month for different price. When I fetch products with try await Product.products(for: Set(identifiers)) I receive this product and introductory offer is present there. When I test with StoreKit Configuration and launch buy flow and system bottom sheet with Subscribe button is shown, I can see 6 month for different price offer there. However on TestFlight and on production system bottom sheet with Subscribe button does not contain this introductory offer. product.subscription.isEligibleForIntroOffer returns true. Also, if I set length of Introductory offer to 1 year, everything works correctly. What can be the reason for 6 month Introductory Offer not being shown on system bottom sheet?
0
0
218
Dec ’24
IAP Sandbox - No Products
Hello, I've been trying to get the sandbox environment working for in-app purchases, but so far, no luck. I can use a storekit config file to simulate purchases just fine. The item is a single consumable product. I've checked that my product ID matches, followed the advice tendered to other forum users, created a sandbox user, all to no avail. I've signed into the app store using my sandbox account on one phone - I can't get the "Sandbox User" option to appear on the second after attempting to make a purchase (per https://developer.apple.com/documentation/storekit/testing-in-app-purchases-with-sandbox ). What I'm wondering is, do I need to get the in-app-purchase approved/released through App Review before I can even perform testing or something? I've signed all agreements, set up our banking information, everything seems to be in order, but I just cannot get the StoreKIt products call to return anything. ( let products = try await Product.products(for: productId) ) Is there anything else I can check? I've also checked everything here: https://forums.developer.apple.com/forums/thread/652077 Thanks!
1
0
283
Dec ’24
Unable to retreive transactions history or Info (StoreKit2)
Hi everyone, I’m currently integrating auto-renewable subscriptions in my React Native app, and I’m encountering an issue with the StoreKit2 API. What Works I’ve successfully implemented in-app purchases, and I can purchase auto-renewable subscriptions without any issues. After the purchase, I’m receiving the following transaction details: ``{ "originalTransactionDateIOS": 1732733802000, "originalTransactionIdentifierIOS": "2000007891139879", "productId": "product.id", "transactionDate": 1732748202000, "transactionId": "2000007935522994", "transactionReceipt": "xxxxxxxxxxxxCwIBAwIBAQ" }`` The Problem When I send the transactionId to my server and call either getTransactionHistory or getTransactionInfo using the App Store Server API, I always receive an empty array as the response. Additionally, I’ve tried testing with StoreKit Testing in Xcode, but I consistently get 0 as the transactionId, which makes it impossible to verify the transactions. Here’s what I’ve done so far: I’m using a sandbox account for testing. The subscription purchase flow works, and the transactionId is successfully retrieved in the app. I’ve double-checked that the transactionId sent to the server matches the one from the app. Thanks in advance!
0
0
196
Dec ’24
How get the backend service get the fefund amount in the subscription plan "Upgrade" cases?
If a user applies for and is approved for a subscription refund by Apple, we understand that the developer can receive a server notification of "REFUND." However, this notification doesn't include the refund amount. Therefore, we thought about linking the refund amount information output in the financial report "All Countries or Regions (Detailed)" with individual end-user transaction information. However, it seems that this report doesn't have a transaction ID, and the records appear to be aggregated daily. Is there any way we can find out how much was refunded to which user for individual refunds? If a user applies for a subscription refund from Apple, are there cases where only a part of the plan, rather than the full amount, is refunded?
0
0
169
Dec ’24
In-App Purchase Transaction Handling and Refund Implications in App Store API
Hello, I am currently encountering an issue while using the server-side API for in-app purchase integration. Suppose a user has already purchased a product, and the App Store returns a transactionId of 1. After some time, the user repeats the purchase for some reason, and the App Store returns a transactionId of 2. However, when I use the Get Transaction History interface to query the transaction information for transactionId 2, I see that the data returned by the App Store does not include the transaction data for transactionId 2; it only contains the transaction data for transactionId 1. In this situation, my guess is that when the user makes a repeat purchase, the App Store recognizes that the user has already purchased the item and has not executed a refund. Therefore, the App Store generates a new transactionId for this request (the user's purchase) and associates it with the previous purchase's transaction data. This is my inference. If this user has made 5 repeat purchases, when the user successfully requests a refund, if I query the transaction information through the Get Transaction History interface, will the revocationDate for all 5 transactions in the App Store's official database be modified to the same date? Additionally, after the user successfully refunds and makes another purchase, will the new transactionId still be associated with the previous transaction data?
0
0
281
Nov ’24
Implementing In-App Purchases for the first time
Hi, I want to apply in app purchases in my app. I have set it up in xcode and on appstoreconnect, it is saying ready to submit. I dont understand what i need to do now to connect the two. I have read i need to send my app for review for them to be reviewed, but i want to test the in app purchases first on test flight and on sandbox before i send my app for review. Please can someone clarify for me and help me?
1
0
284
Nov ’24