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).
StoreKit
RSS for tagSupport in-app purchases and interactions with the App Store using StoreKit.
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
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!
Hello,
For In App Purchases with a renewable subscription, does the originalTransactionId change in the following scenarios?
Case 1:
A user subscribes to a subscription A within a Subscription Group SG1.
The user then cancels it at the end of the month.
Comes back later to subscribe to the same subscription A within the same Subscription Group SG1.
Case 2:
A user subscribes to a subscription A within a Subscription Group SG1.
The user then cancels it at the end of the month.
Comes back later to subscribe to subscription B within the same Subscription Group SG1.
Hey everybody, today I received an email (seemingly automated) stating that my payment is on hold due to irregular activity. However, I haven't violated any rules, and I've seen that many other people have received the same message. As soon as I saw the email, I contacted support via phone, and the representative who assisted me confirmed that my account status is correct and in good standing. She requested that I forward the email to her for further investigation.
Email received:
"We noticed some irregular activity associated with your vendor number XXXXXXXX and have paused your earnings payments while we investigate. Once our review is complete, we'll determine if we can resume your payments."
Questions:
Has anyone else experienced this issue? If so, what was the process to resolve it? How long does it typically take to have the payments resumed?
Wishing you all a great day,
Thank you.
Topic:
App & System Services
SubTopic:
StoreKit
Tags:
In-App Purchase
Subscriptions
Tap to Pay on iPhone
I am looking to move from paid app to fremium without upsetting my existing users. I see WWDC2022 session where new fields introduced in iOS 16 are used to extract original application version user used to purchase the app. While my app supports iOS 14 and above, I am willing to sacrifice iOS 14 and go iOS 15 and above as StoreKit2 requires iOS 15 at the minimum. The code below is however only valid for iOS 16. I need to know what is the best way out for iOS 15 devices if I am using StoreKit2? If it is not possible in StoreKit2, then how much is the work involved in original StoreKit API(because in that case I can handle for iOS 14 as well)?
I've recently published an app, and while developing it, I could always get consistent entitlements from Transaction.currentEntitlements. But now I see some inconsistent behaviour for a subscribed device in the AppStore version. It looks like sometimes the entitlements do not emit value for the subscriptions.
It usually happens on the first couple tries when the device goes offline, or on the first couple tries when the device goes online. But it also happens randomly at other times as well.
Can there be a problem with Transaction.currentEntitlements when the connectivity was just changed?
Of course my implementation may also be broken. I will give you the details of my implementation below.
I have a SubscriptionManager that is observable (irrelevant parts of the entity is omitted):
final class SubscriptionManager: NSObject, ObservableObject {
private let productIds = ["yearly", "monthly"]
private(set) var purchasedProductIDs = Set<String>()
var hasUnlockedPro: Bool {
return !self.purchasedProductIDs.isEmpty
}
@MainActor
func updatePurchasedProducts() async {
var purchasedProductIDs = Set<String>()
for await result in Transaction.currentEntitlements {
guard case .verified(let transaction) = result else {
continue
}
if transaction.revocationDate == nil {
purchasedProductIDs.insert(transaction.productID)
} else {
purchasedProductIDs.remove(transaction.productID)
}
}
// only update if changed to avoid unnecessary published triggers
if purchasedProductIDs != self.purchasedProductIDs {
self.purchasedProductIDs = purchasedProductIDs
}
}
}
And I call the updatePurchasedProducts() when the app first launches in AppDelegate, before returning true on didFinishLaunchingWithOptions as:
Task(priority: .high) {
await DependencyContainer.shared.subscriptionManager.updatePurchasedProducts()
}
You may be wondering maybe the request is not finished yet and I fail to refresh my UI, but it is not the case. Because later on, every time I do something related to a subscribed content, I check the hasUnlockedPro computed property of the subscription manager, which still returns false, meaning the purchasedProductIDs is empty.
You may also be curious about the dependency container approach, but I ensured by testing multiple times that there is only one instance of the SubscriptionManager at all times in the app.
Which makes me think maybe there is something wrong with Transaction.currentEntitlements
I would appreciate any help regarding this problem, or would like to know if anyone else experienced similar problems.
I am working on a banking application (includes iPhone and iPad) which includes add to wallet feature.
During the implementation I saw one document it is mentioned that for iPad app, the app must be extended to support Apple pay functionality.
Details from document says "Card Issuers with an iOS mobile banking app must support Card Issuer iOS Wallet extension functionality to enable Card issuer mobile app customers to provision new cards directly from the iOS Wallet app with all eligible Apple iOS devices. If the Card Issuer has a dedicated iPad App, that App must be extended to support Apple Pay functionality. "
Is wallet extension implementation required for Apple pay to work in iPhone and iPad?
Is wallet extension a mandatory implementation for Add to Apple Wallet feature to work and approved by Apple?
I am little confused in this.
Anyone who integrated Apple pay or done add to Apple Wallet feature recently without wallet extension faced any rejection?
Any help would be much appreciated.
when we test in app purchase feature in TestFlight, we realize that TestFlight using our real iCloud account in AppStore, but because the app installed from TestFlight, they know it is still "Testing Phase" so they purchase set to FREE.
Now im asking about how to test in app purchase for CANCEL SUBSCRIPTION?
I can't found in my real iCloud account, either for my sandbox account inside AppStore settings.
Please any response will helpful. Thankyou.
I try to call Get Transaction Info from App Store Server API, and the transactionId is for a Non-consumable type product, but it is odd that there are so many different transactionId and they have a same originalTransactionId
{
"bundleId": "${bundleId}",
"environment": "Production",
"inAppOwnershipType": "PURCHASED",
"originalPurchaseDate": 1691220528000,
"originalTransactionId": "${originalTransactionId}",
"productId": "${productId}",
"purchaseDate": 1691220528000,
"quantity": 1,
"signedDate": 1692590989925,
"storefront": "USA",
"storefrontId": "143441",
"transactionId": "${originalTransactionId}",
"transactionReason": "PURCHASE",
"type": "Non-Consumable"
}
the defination of Non-Consumable is can only purchase once for same apple account. But why there would have originalTransactionId?
Topic:
App & System Services
SubTopic:
StoreKit
Tags:
In-App Purchase
App Store Receipts
App Store Server API
Hi,
I want to develop a referral system for my subscribers. If someone suggests my app and his/her friend buy a subscription I want to give the referrer a one-month free subscription or extend the existing subscription to one month for free.
Is it possible to do this with offer codes?
I was trying to write unit test of ask to buy for SKDemo app.
Even if I set SKTestSession.askToBuyEnabled = true, I got transaction state as .purchased after I call SKTestSession.buyProduct(identifier:).
import StoreKitTest
import XCTest
final class SKDemoTests: XCTestCase {
private var session: SKTestSession!
override func setUp() async throws {
session = try .init(SKTestSession(configurationFileNamed: "Products"))
session.disableDialogs = true
session.resetToDefaultState()
session.clearTransactions()
}
func test() async throws {
session.askToBuyEnabled = true
try await session.buyProduct(identifier: "consumable.fuel.octane89")
XCTAssertEqual(session.allTransactions().first!.state, .deferred) // Gets error here. The actual state I get is .purchased
}
}
I was using Xcode 15.0.1 (15A507), Simulator iPhone 15 Pro iOS 17.0.1 (21A342)
I couldn't find the problem so I'm happy to hear any solutions.
I've watched some of the WWDC session videos about this topic and read the documentation and header files, but it is still confusing...
Because I change the pricing model of my iOS App (it was a paid App and now it will be a free App with an In-App purchase), I want to check if a user of my App purchased the App in the past. So user who have already paid in the past will get the full access without the need to pay the IAP, while new users would have to do this.
In one of the WWDC videos exactly this topic was covered and the solution would be to check out AppTransaction.originalAppVersion. This would be a simple and easy solution...
...Unless I read the information from the header file and documentation for this API. Here it says:
The string value contains the original value of the CFBundleShortVersionString for apps running in macOS, and the original value of the CFBundleVersion for apps running on all other platforms.
The problem here is that when I check the Info.plist of iOS Apps, the CFBundleShortVersionString is used for the main App version and CFBundleVersion is used for the "build" number. According to the cited documentation from above, AppTransaction.originalAppVersion would be totally uselesss on the iOS platform, because it would only return the build number and not the version number.
So I'm confused. Can I use AppTransaction.originalAppVersion to get the original version that was purchased for iOS Apps? If yes, the documentation must be wrong and misleading. If no, how can I do this?
I'm currently in testing and I only get "1.0" as originalAppVersion within the beta release. This could be either because I really only get the useless build number, or I get the "real" version because the App is on the device since version "1.0" on my device, or it is just a limitation of XCode while testing that it is returning version "1.0" but would return the correct version when the App was installed from the AppStore....
Can someone bring some light into this topic? Am I missing something or did I understand something wrong?
This is re-posted from this Stack Overflow post.
I am looking at validating the purchase of a paid app from Mac AppStore. Based on this WWDC video about StoreKit 2, I am attempting to this with AppTransaction. I have not found meaningful high-level documentation about this specific use case beyond that.
My approach is to first get the "cached" AppTransaction by calling AppTransaction.shared. If that is not there I proceed to getting it from Apple, via AppTransaction.refresh(). If they don't have it, or when the network is down, the user automagically gets the familiar "log in to your store account" UI that has been around as long as the Mac AppStore.
Once I have the AppTransaction I use it to verify we are on the right device, using code like this, where the returned Bool represents validation success:
guard let deviceVID = AppStore.deviceVerificationID?.uuidString.lowercased() else { return false }
let nonce = appTransaction.deviceVerificationNonce.uuidString.lowercased()
let combo = nonce + deviceVID
let digest = SHA384.hash(data: Data(combo.utf8))
return (digest == appTransaction.deviceVerification)
My first question is: Does that look like the right approach? Is there something else I should do, or check?
My second question is around testing this approach. Refreshing the AppTransaction in the sandbox invariably yields a valid item, even if the app version does not yet exist in AppStoreConnect. This is also the case when I log out in the App Store app on the Mac. This makes me think it is using my AppleID which I am logged into in System Settings. Does that sound right?
I would like to be able to remove / delete the cached AppTransactions - where might I find those on the system?
Thanks for everyone's help!
Topic:
App & System Services
SubTopic:
StoreKit
Tags:
macOS
StoreKit
Mac App Store
App Store Receipts
I'm getting really frustrated with emails from my App users who believe they've been charged for a free in-app purchase when they haven't.
My App offers many in-app purchases of digital items and I give 4 of these away for free to let users get comfortable with how it works in-app.
Over the last couple of years I've had a steady increase in angry emails from users who accuse me of fraud by charging them for a free item. I couldn't figure out for a while what this was as they would leave a 1 star rating, delete the app and ignore my emails for more information.
Recently I had someone a bit more patient engage and explain it to me.
The purchase for some reason popped up on my notifications right when I bought the [Free Item in my app]. It was from a movie I bought and the bill was delayed.
The timing of that notification is what is misleading users about the free in-app purchase.
Can someone take note of this please and perhaps delay any payment notifications so they aren't sent when the in-app purchase is for FREE?
Thanks!
I have a volumetric app. I am trying to present a review prompt using SKStoreReviewController's requestReview(in:) I'm using the code below:
if let scene = UIApplication.shared.connectedScenes.first(where: { $0.activationState == .foregroundActive }) as? UIWindowScene {
SKStoreReviewController.requestReview(in: scene)
}
When this code executes, though, I get a crash with the error:
Presentations are not permitted within volumetric window scenes.
What is the proper way to do this for a volumetric app?
Hello, when I check my subscriptions in test flight it loads and works. However, once the build is approved and released in the App store the subscriptions will not load. It just keeps loading and nothing else happens. Please help? Thank you.
For V1 used for internal purchase verification, when will the exclusive shared key regenerated after transfer be replaced? Will it affect in-app purchases and subscriptions by online users?
The V2 used for internal purchase verification uses the key ID instead of the dedicated shared key. In this case, what should we pay attention to before and after the transfer? Do I need to regenerate the key ID for the new account? Is the private shared key still useful? Do I need to generate a dedicated shared key again in the transferred App?
What will be the impact on existing subscriptions after the transfer? What do I need to do with the current existing subscriptions?
We have used universalLink, do we need to add a new TeamId to the apple-app-site-assn. txt file?
{
"applinks": {
"apps": [],
"details": [
{
"appID": “TeamIdA.com.***.***”,
"paths": [""]
},
{
"appID": “TeamIdB.com.***.***”,
"paths": [""]
}
]
}
}
We have stored the login information in Keychain Sharing, is there no way to get the original stored information after transfer? Is there a reasonable solution?
I'm setting up subscriptions on the App Store and need to fill out some forms. One of them is the "U.S. Certificate of Foreign Status of Beneficial Owner."
At the bottom of the form, I see a label 'U.S. Person' with my name listed underneath it.
What does "U.S. Person" mean here? My name appears below the "U.S. Person" title, but I'm not a U.S. person. What should I do? Also, what title should I enter? I'm the only developer on the app.
Im building a small iphone app with StoreKit and currently testing it in testflight right on my mac, not on iphone. StoreKit part almost exactly copied from SKDemo from one of the Apple's WWDC. For some users and for myself Transaction.currentEntitlements always returns .unverified results. I double-checked Apple Connect settings, i checked my internet connection and everything is fine. Is there some pitfalls for testflight on mac? How can I find out what is causing this problem?
Error Domain=NSURLErrorDomain Code=-1005 "The network connection was lost
Getting this error with: SKPaymentQueue.default().restoreCompletedTransactions()
Implemented: func paymentQueue(_ queue: SKPaymentQueue, restoreCompletedTransactionsFailedWithError error: any Error) {
<#code#>
}
Error returned is the 1005 error I listed above.
The laptop works fine, it is connected to the internet just fine. The problem is connecting to the AppStore Simulator when the project target is intended for the Mac.
I have an iOS project for this product and I do NOT get this problem with the transaction observer when the project target is iOS (iPhone, iPad).
This problem only occurs on the M1 Laptop and the target is MacOS.
Topic:
App & System Services
SubTopic:
StoreKit