StoreKit

RSS for tag

Support in-app purchases and interactions with the App Store using StoreKit.

StoreKit Documentation

Post

Replies

Boosts

Views

Activity

Operation of Server Notifications V2 when Apple account is withdrawal
Please allow me to confirm the Server Notifications V2 specification. I am aware that if withdrawal an Apple account that has a subscription, the subscription will eventually be cancelled. Regarding Server Notifications V2 notifications with a notificationType of EXPIRED, am I correct in thinking that they will be sent when the subscription expires even if the Apple account is withdrawal?
0
0
58
5h
Behavior of the "get all subscription statuses" API.
We are running auto-renewing subscriptions with StoreKit2 and the “get all subscription statuses” API is behaving unexpectedly. record the originalTransactionId from the iPhone to the server side when purchasing a subscription with Storekit2. query the get all subscription statuses API from the server side with the originalTransactionId recorded. get all subscription statuses returns a response, but there is no data in the response that matches the originalTransactionId. I have an error on my system because I have built my system on the assumption that all subscriptions including originalTransactionId will be returned.
0
0
70
5h
Potential Issue Identified in Apple Documentation
While reviewing the Apple Documentation, I came across a potential issue in one of the examples that I believe is worth addressing. The example appears to compare strings instead of integers, which could lead to unexpected behavior in production environments. Specifically, in the line where originalMajorVersion (a string) is compared with newBusinessModelMajorVersion (also a string) using <: if originalMajorVersion < newBusinessModelMajorVersion This comparison performs a lexicographical check rather than evaluating the numerical values of the strings. As a result, strings like "10" would incorrectly be considered less than "2", which is not the desired behaviour when comparing version numbers. I have reported this via the Feedback assistant (FB16432337) but at the time of posting this there has been no reply at all (23 days) Supporting business model changes by using the app transaction do { // Get the appTransaction. let shared = try await AppTransaction.shared if case .verified(let appTransaction) = shared { // Hard-code the major version number in which the app's business model changed. let newBusinessModelMajorVersion = "2" // Get the major version number of the version the customer originally purchased. let versionComponents = appTransaction.originalAppVersion.split(separator: ".") let originalMajorVersion = versionComponents[0] if originalMajorVersion < newBusinessModelMajorVersion { // This customer purchased the app before the business model changed. // Deliver content that they're entitled to based on their app purchase. } else { // This customer purchased the app after the business model changed. } } } catch { // Handle errors. }
3
0
149
2d
In App Purchase does not work
I read the documentation and it told I had to prepare the product on App Store connect and once it is at the state "Ready to submit" I could access it on a phone where I am connected with an Icloud account in the developper list of the apple development account. This is what I've done but when I try to fetch in my flutter code the product with the id I set in App Store connect it says "No product found" Here is where I fetch the product: Future purchaseProduct(String productId) async { try { Set<String> _pIds = {productId}; final ProductDetailsResponse response = await _iap.queryProductDetails(_pIds); if (response.productDetails.isEmpty) { throw 'Product not found'; } final ProductDetails productDetails = response.productDetails.first; final PurchaseParam purchaseParam = PurchaseParam(productDetails: productDetails); _iap.buyConsumable(purchaseParam: purchaseParam); } catch (e) { Services.debugLog('Error purchasing product: $e'); throw e; } } I checked the product ID and it does not seems to be the problem. Is there some other steps I need to do ?
2
0
141
3d
InApp purchase get stuck in paymentQueue purchasing status.
Some of my users reported they can not completed the purchase . According to the logs and screen captures . Their purchase progress's last status are "purchasing" func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) { .... .... case .purchasing: // 处理正在购买的情况 //print("购买中"); AppDelegate.log.debug("paymentQueue purchasing"); LoadingAlert.shared.setText(text: "购买中".localized()) .... After this ,It neither entered any error branch nor prompted the user to confirm the purchase or enter a password, but simply stopped here. There are no other purchase-related logs, and the program is still running normally. At the same time, other users are able to complete their purchases without any issues. However, there have been 4-5 users recently who reported problems with purchasing. What could be the possible reasons? In my local environment, I repeated the test many times, including using sandbox users from different regions and real Apple IDs, and everything worked fine. // // Payment.swift // RadialMenu // // Created by pat on 2023/6/26. // import Foundation import StoreKit class Payment:NSObject,SKProductsRequestDelegate,SKPaymentTransactionObserver{ func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) { for transaction in transactions { AppDelegate.log.debug("paymentQueue transaction product = \(transaction.payment.productIdentifier) state = \(transaction.transactionState)"); //let productID = transaction.payment.productIdentifier switch transaction.transactionState { case .purchased,.restored: if(transaction.transactionState == .purchased){ AppDelegate.log.debug("paymentQueue purchased"); LoadingAlert.shared.setText(text: "已购买".localized()) } if(transaction.transactionState == .restored){ LoadingAlert.shared.setText(text: "已恢复".localized()) AppDelegate.log.debug("paymentQueue restored"); } //} break; case .failed: AppDelegate.log.debug("paymentQueue failed "); if let error = transaction.error as? NSError { // 获取错误代码和描述 let errorCode = error.code let errorDescription = error.localizedDescription AppDelegate.log.debug("paymentQueue Transaction failed with error code: \(errorCode), description: \(errorDescription)") } queue.finishTransaction(transaction) LoadingAlert.shared.hideModal(); // 处理购买失败的情况 // 提供错误信息给用户 //print("购买失败"); alertRetry(); break; case .deferred: AppDelegate.log.debug("paymentQueue deferred"); LoadingAlert.shared.setText(text: "购买延迟".localized()) // 处理交易延迟的情况(仅限家庭共享) break; case .purchasing: // 处理正在购买的情况 //print("购买中"); AppDelegate.log.debug("paymentQueue purchasing"); LoadingAlert.shared.setText(text: "购买中".localized()) break; @unknown default: AppDelegate.log.debug("paymentQueue nknown default\(transaction.transactionState)"); break } } }
0
0
96
3d
Verify Receipt is not found - After successful payment for Annual subscription.
The application is developed with Xamarin Framework and it is live now. The customer installed the app and purchased the annual subscription. And for some reason, they uninstall and reinstall the application on the same device. Now user wants to restore the subscription. In the application, there is an option to Restore the subscription. But restore API not return purchase details. But when clicking the subscription button instead of restoring the subscription, it says you subscribed to this plan". is there any possibility of not getting VerifyRecipt even after a successful purchase?
0
0
94
4d
tvOS In-app purchase not working
I am trying to implement in-app purchases in Apple TV. I added a "non-consumable" product and started testing in Sandbox, but it did not work properly. While I am trying to fetch the product from the appstore, it won't give any responses like success or failure. So that our app gets rejected in the App Store. Please provide me the steps to implement in-app purhcase in Apple tvos using Swift. Note: The same code is working fine in iOS.
0
0
68
4d
IAP Can not Use Sand Box Test
I am currently using StoreKit2 to set up the in-app purchase subscription flow, and I have already configured the subscription products in App Connect. I created a StoreKit Configuration file in Xcode and used it in the scheme. However, after completing the purchase, the transaction.jsonRepresentation data returns a transactionId of 0. After checking the documentation, I found that I need to disable the StoreKit Configuration and enable Sandbox Testing. But after disabling the StoreKit Configuration, I can't retrieve the real product data using Product.products(for: productIds). I can confirm that the ProductId I provided is real and matches the data configured in App Connect. Could you please help me identify the issue?
0
0
45
4d
My iOS application cannot connect to the Sandbox environment.
I am testing the subscription flow in my iOS app. Initially, everything was working fine when following the official StoreKit and sandbox testing documentation. After a successful subscription, the “You’re all set” popup always displayed the environment as “sandbox.” However, after some changes, possibly upgrading macOS to the latest version, upgrading Xcode, or regenerating certificates, I can no longer connect to the sandbox testing environment. The subscription success popup now always shows the environment as “xcode.” By default, the iOS app should run in the sandbox on macOS, so I didn’t set the “Enable App Sandbox” option to “Yes” in the Xcode build settings. When I try enabling it, Xcode throws the following error: “Failed to verify code signature of /var/installd/Library/Caches/com.apple.mobile.installd.staging/temp.n3J0tr/extracted/Payload/XXXX.app : 0xe8008015 (A valid provisioning profile for this executable was not found.) Please ensure that your app is signed by a valid provisioning profile.” Additionally, if “Enable App Sandbox” is set to “No,” the app installs successfully on a real device, but there is no prompt to trust an untrusted developer certificate, which usually appears for such certificates. I’m not sure if this information will be useful to others, but I’ve been stuck on this issue for a while, and it’s preventing me from moving forward with my work. Any help to resolve this would be greatly appreciated. Thank you!
3
0
135
6d
App Store Server Notification sends old transactions
I've noticed that CONSUMPTION_REQUEST notifications sometimes have a signedTransactionInfo which corresponds not to the latest transaction, but to an earlier transaction in a subscription. Is this expected? I thought signedTransactionInfo was always the latest subscription information? Are there any other notification types for which signedTransactionInfo can be out of date?
1
0
142
6d
StoreKit2 Subscription Verification
My question is simple, I do not have much experience in writing swift code, I am only doing it to create a small executable that I can call from my python application which completes Subcription Management. I was hoping someone with more experience could point out my flaws along with giving me tips on how to verify that the check is working for my applicaiton. Any inight is appreciated, thank you. import Foundation import StoreKit class SubscriptionValidator { static func getReceiptURL() -> URL? { guard let appStoreReceiptURL = Bundle.main.appStoreReceiptURL else { print("No receipt found.") return nil } return appStoreReceiptURL } static func validateReceipt() -> Bool { guard let receiptURL = getReceiptURL(), let receiptData = try? Data(contentsOf: receiptURL) else { print("Could not read receipt.") return false } let receiptString = receiptData.base64EncodedString() let validationResult = sendReceiptToApple(receiptString: receiptString) return validationResult } static func sendReceiptToApple(receiptString: String) -> Bool { let isSandbox = Bundle.main.appStoreReceiptURL?.lastPathComponent == "sandboxReceipt" let urlString = isSandbox ? "https://sandbox.itunes.apple.com/verifyReceipt" : "https://buy.itunes.apple.com/verifyReceipt" let url = URL(string: urlString)! let requestData: [String: Any] = [ "receipt-data": receiptString, "password": "0b7f88907b77443997838c72be52f5fc" ] guard let requestBody = try? JSONSerialization.data(withJSONObject: requestData) else { print("Error creating request body.") return false } var request = URLRequest(url: url) request.httpMethod = "POST" request.httpBody = requestBody request.setValue("application/json", forHTTPHeaderField: "Content-Type") let semaphore = DispatchSemaphore(value: 0) var isValid = false let task = URLSession.shared.dataTask(with: request) { data, response, error in guard let data = data, error == nil, let jsonResponse = try? JSONSerialization.jsonObject(with: data) as? [String: Any], let status = jsonResponse["status"] as? Int else { print("Receipt validation failed.") semaphore.signal() return } if status == 0, let receipt = jsonResponse["receipt"] as? [String: Any], let inApp = receipt["in_app"] as? [[String: Any]] { for purchase in inApp { if let expiresDateMS = purchase["expires_date_ms"] as? String, let expiresDate = Double(expiresDateMS) { let expiryDate = Date(timeIntervalSince1970: expiresDate / 1000.0) if expiryDate > Date() { isValid = true } } } } semaphore.signal() } task.resume() semaphore.wait() return isValid } }
0
0
137
6d
Could not find the main bundle or the Info.plist is missing a CFBundleIdentifier
I had a standalone python application (created with pyinstaller) which was working perfectly alone. This macOS application was created in VS. I later decided to improve the application by implementing some Swift features (Subscription Manager). This required me to write a brief Swift file (Subscription Management) in XCode which the Python file called on. Python Standalone Application Calling Swift : # Function to check if the user has a valid subscription def check_subscription(): subscription_manager_path = "/Users/isseyyohannes/Library/Developer/Xcode/DerivedData/SubscriptionManager2-ezwjnnjruizvamaesqighyoxljmy/Build/Products/Debug/SubscriptionManager2" # Adjust path try: result = subprocess.run([subscription_manager_path], capture_output=True, text=True, check=True) return "VALID_SUBSCRIPTION" in result.stdout # Return True if valid, False otherwise except subprocess.CalledProcessError as e: print(f"Error checking subscription: {e}") return False # Return False if there's an issue However, when I try to run xcrun altool --validate-app ... I get the following error message. The error reads as follows Running altool at path '/Applications/Xcode.app/Contents/SharedFrameworks/ContentDeliveryServices.framework/Frameworks/AppStoreService.framework/Support/altool'... 2025-02-16 11:02:21.089 *** Error: Validation failed for '/Users/isseyyohannes/Desktop/ALGORA Performance.app'. 2025-02-16 11:02:21.089 *** Error: Could not find the main bundle or the Info.plist is missing a CFBundleIdentifier in ‘/Users/isseyyohannes/Desktop/ALGORA Performance.app’. Unable to validate your application. (-21017) { NSLocalizedDescription = "Could not find the main bundle or the Info.plist is missing a CFBundleIdentifier in \U2018/Users/isseyyohannes/Desktop/ALGORA Performance.app\U2019."; NSLocalizedFailureReason = "Unable to validate your application."; I located the Info.plist file which had everything correct (my Bundle ID, etc.) for the python file. I am successfully able to notarize the application, just having issues submitting it. **It is worth noting I currently have a python executable calling on a file written in swift code and created in xcode. I created the python application with the following command on VS. pyinstaller --onefile --noconsole \ --icon="/Users/isseyyohannes/Downloads/E0BWowfbDkzEiEAckjsHAsYMzpdjjttT.icns" \ --codesign-identity "Developer ID Application: Issey Yohannes (GL5BCCW69X)" \ --add-binary="/Users/isseyyohannes/Library/Developer/Xcode/DerivedData/SubscriptionManager2-ezwjnnjruizvamaesqighyoxljmy/Build/Products/Debug/SubscriptionManager2:." \ --osx-bundle-identifier com.algora1 \ /Users/isseyyohannes/Desktop/ALGORA\ Performance.py Note : All steps on Apple Developer site are done (ex. Creating identifier, secret password etc)
1
0
157
1w
Download ID in AppTransaction
Hello, I would like to draw your attention to the following imperfection. For validating purchases of my paid application Guru Maps Pro, I use the download id. This is a unique ID that can replace the Transaction ID for paid applications. However, with the release of the new AppTransaction API, this field is no longer present in the data. I tried parsing the receipt, but that field is absent there as well. The only way to obtain the download id is to send the receipt to the deprecated /verifyReceipt endpoint. This deprecated status concerns me, because at some point it might stop working. Let me explain a little about why I need this. My users have a guru-account, which they can use both in the web version and on Android. When a user purchases the paid version of the application, they can access the paid features on both web and Android. This works great for in-app purchases, where there is a transaction ID, but it may soon stop working for paid applications because there is no way to determine any ID associated with the purchase. Transaction ID or Download ID – I don't mind which.
0
0
141
2w
No subscriptions showed to buy in release phase
I have auto-renewable subscriptions, and in Xcode everything works fine. It shows a list of subscriptions where I can make a test purchase. But when I send it for review, the review team, as well as TestFlight, simply do not have subscriptions. If the problem was in the code, it would not work in the sandbox as I think. But I think that I configured everything correctly in the subscription settings. The only thing: it shows there for the subscription in appstoreconnect that it is preparing for review, but nothing can be done about it, because it will be solved with the first release of the application. But I do not know where else to look and what to do. The problem is probably not in the code, but I also redirected the subscription config in appstoreconnect a bunch of times. I asked help on review team, no way. Tried to google and chat GPT, no ideas where to find a solution.
1
0
188
2w
Reporting your App Store Server Notifications issue
To receive server notifications from the App Store, follow the instructions in Enabling App Store Server Notifications. If your server doesn’t receive any notifications, check your server logs for any incoming web request issues, and confirm that your server supports the Transport Layer Security (TLS) 1.2 protocol or later. If you implement version 2 of App Store Server Notifications, call the Get Notification History endpoint. If there is an issue sending a notification, the endpoint returns the error the App Store received from your server. If your issue persists, submit a Feedback Assistant report with the following information: The bundleId or appAppleId of your app The date and time your issue occurred The raw HTTP body of your notification The affected transactionId(s) if applicable The version of App Store Server Notifications (i.e., Version 1 or Version 2) The environment (i.e., Production or Sandbox) To submit the report, perform these steps: Log into Feedback Assistant. Click on the Compose icon to create a new report. Select the Developer Tools & Resources topic. In the sheet that appears: Enter a title for your report. Select “App Store Server Notifications” from the “Which area are you seeing an issue with?” pop-up menu. Select “Incorrect/Unexpected Behavior” from the “What type of feedback are you reporting?” pop-up menu. Enter a description of your issue. Add the information gathered above to the sheet. Submit your report. After filing your report, please respond in your existing Developer Forums post with the Feedback Assistant ID. Use your Feedback Assistant ID to check for updates or resolutions. For more information, see Understanding feedback status.
0
0
129
2w
Reporting your App Store Server Library issue
If you are experiencing an unexpected or inconsistent behavior when using the App Store Server Library, review the following resources to ensure that your implementation workflow didn’t cause the issue: Simplifying your implementation by using the App Store Server Library Explore App Store server APIs for In-App Purchase Meet the App Store Server Library If you are unable to resolve your issue using the above resources, file a GitHub issue. Alternatively, if you wish to provide specific requests, transactions, or other private information for review, submit a Feedback Assistant report with the following information: The bundleId or appAppleId of your app The date and time your issue occurred The library language(s) The version of the library The environment (i.e., Production, Sandbox, or Xcode) The GitHub issue for this report if available The endpoint(s) reproducing your issue The HTTP body and headers of the endpoint raw request The HTTP body and headers of the endpoint response To submit the report, perform these steps: Log into Feedback Assistant. Click on the Compose icon to create a new report. Select the Developer Tools &amp; Resources topic. In the sheet that appears: Enter a title for your report. Select “App Store Server Library” from the “Which area are you seeing an issue with?” pop-up menu. Select “Incorrect/Unexpected Behavior” from the “What type of feedback are you reporting?” pop-up menu. Enter a description of your issue and how to reproduce it. Add the information gathered above to the sheet. Submit your report. After filing your report, please respond in your existing Developer Forums post with the Feedback Assistant ID. Use your Feedback Assistant ID to check for updates or resolutions. For more information, see Understanding feedback status.
0
0
125
2w
Best practices: ensuring server-side that the AppReceipt sent up by a client belongs to the client
Hi, all! I have an AppStore Server-side question. User sends up an AppReceipt that I am validating. What's the best way to tell the receipt belongs to said user? I want to make sure that the source of the AppReceipt was actually the original purchaser of the item. Is fetching Transaction + AppAccountToken the only way? AppAccountToken can only be utilized if the original purchase used it, and it is associated with the user's data. Is there another way?
0
0
142
2w