我在 iOS 应用程序中提供订阅服务。如果应用程序在 iOS 15 或更高版本上运行,我会StoreKit 2用来处理订阅启动和续订。我的实现紧密遵循Apple 的示例代码。
我的一小部分用户 (<1%) 报告说,他们的有效订阅未被识别- 通常是在续订之后(开始新订阅似乎总是有效)。似乎没有显示任何用于续订的 StoreKit 交易。
经过一些故障排除后我发现:
AppStore.sync()没有帮助。我永远无法在我的设备上重现这个错误。
这是我的实现的要点:我有一个StoreManager类来处理与StoreKit. 初始化后,我立即迭代Transaction.all以获取用户完整的购买历史记录,并启动一个监听Transaction.updates. PurchasedItem是一个自定义结构,我用它来对有关交易的所有相关信息进行分组。购买的物品收集在字典中purchasedItems,我在字典中使用交易identifier作为键。对该字典的所有写入仅发生在绑定updatePurchasedItemFor()到MainActor.
class StoreManager {
static let shared = StoreManager()
private var updateListenerTask: Task<Void, Error>? = nil
init() {
updateListenerTask = listenForTransactions()
loadAllTransactions()
}
func loadAllTransactions() {
Task { @MainActor in
for await …Run Code Online (Sandbox Code Playgroud) 我正在寻找为iPhone应用程序设置In App Purchases.我打算使用新的自动续订订阅类型.但是,我想为特定订阅提供多个持续时间,但无法查看如何从SKProductsResponse.products数组中返回的SKProduct中检索持续时间.
SKProduct对象具有price,localizedTitle和localizedDescription.但是,如果您设置具有多个持续时间的订阅系列,则为该系列设置一次标题/说明,以便您不能包括持续时间,并且文档明确表示不在标题/说明中包含持续时间.但是,看不到任何其他字段,我可以检索在我的自定义应用商店中显示的持续时间.我要么缺少某些东西,要么在4.3之前无法使用?
指针非常感谢!
我在恢复已完成的交易时遇到了一些问题.
[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
Run Code Online (Sandbox Code Playgroud)
我添加了几个例子中提到的观察者,我已经尝试过添加paymentQueueRestoreCompletedTransactionsFinished并且已经有了updatedTransactions.paymentQueueRestoreCompletedTransactionsFinished说没有交易.
我可以买一个产品,如果我再次尝试购买,它会阻止我并说我已经购买了该产品,使用此代码.
SKPayment *payment = [SKPayment paymentWithProductIdentifier:productIdentifier];
[[SKPaymentQueue defaultQueue] addPayment:payment];
Run Code Online (Sandbox Code Playgroud)
我想也许我的捆绑标识符有问题,但这看起来很好,如果不是,购买将不起作用.
我一直在设备和模拟器上尝试这个,但这有相同的结果.此外,它没有什么区别如果我使用英国或美国商店.
我真的抓住了吸管,找出为什么这对我不起作用?
如何检查用户是否点击了取消按钮(当他被问到是否要购买smth时,或者他是否已购买此SKProduct是否要下载它)?
现在我只是在paymentQueue:updatedTransactions:方法中收到SKPaymentTransactionStateFailed,用户点击取消按钮后,例如没有互联网时.有什么方法可以区分这两种情况?
我们正在尝试使用StoreKit实现简单的应用程序内购买(不确定它是否与它有关)并且到目前为止一切顺利,但是我们面临一个特定问题:当我们退出应用程序时,iOS会永久询问我们登录:

只有在使用沙箱或TestFlight帐户登录时才会发生这种情况,但这非常令人讨厌.这背后有什么理由或我们不应该担心吗?我读过许多人面临类似的问题,并且一旦应用程序投入生产就会解决,但这似乎是一种处理它的hacky /不可预测的方式.
如果您需要,我准备提供更多信息.在这一点上,我只是不知道为什么会发生这种情况(我已将它与许多事情联系起来,但它们都没有真正证明是正确的......例如收据验证请求,付款队列中未完成的交易等. ).
我正在使用.storekit配置。尝试购买此类产品时出现错误
<SKPaymentQueue:0x600001240ce0>:付款已完成,但出现错误:错误域= ASDErrorDomain代码= 500“未处理的异常”UserInfo = {NSUnderlyingError = 0x600001c62160 {Error Domain = AMSErrorDomain代码= 100“身份验证失败”UserInfo = {NSLocalizedFailureReason =验证凭据调用失败., NSLocalizedDescription=身份验证失败,NSUnderlyingError=0x600001c60960 {Error Domain=com.apple.accounts Code=4“没有身份验证插件来验证 com.apple.account.iTunesStore.sandbox 类型帐户的凭据” UserInfo={NSLocalizedDescription=无身份验证用于验证 com.apple.account.iTunesStore.sandbox 类型帐户凭据的插件}}}},NSLocalizedFailureReason=发生未知错误,NSLocalizedDescription=未处理的异常}
如何解决这个问题?
我正在为我的应用实施应用内购买(即将发布),并为iOS6和iOS7提供支持.我的问题与iOS6和iOS7上的非续订订阅机制之间的差异有关,更具体地说,关于如何实现恢复.为了适应iOS6和iOS7,我实现了一个服务器端解决方案来启用恢复.我可以选择允许用户创建可以在不同设备上使用的用户名/密码(如果数据丢失,则使用同一设备)进行恢复.我的大部分工作基本上都在工作,但随着我的测试进展,我发现了一些奇怪的东西.
iOS7恢复过程的初始部分使用SKReceiptRefreshRequest刷新应用程序中的收据.当我从iOS7设备上删除应用程序时,重新安装(此时没有收据;使用iExplorer进行测试),并进行恢复,SKReceiptRefreshRequest恢复10次购买(我在测试期间为此特定用户创建) .其中一个是非消耗品,其中九个不续订.这让我很困惑.从Apple文档中,我预计只会在刷新的收据中看到非消费品购买.来自https://developer.apple.com/library/ios/releasenotes/General/ValidateAppStoreReceipt/Chapters/ValidateLocally.html:
"消耗品和非更新订阅:在购买时,消费品或非续订订购的应用内购买收据会添加到收据中.它会保留在收据中,直到您的应用完成该交易.在此之后,下次更新收据时会将其从收据中删除 - 例如,当用户再次购买时,或者您的应用明确刷新收据时.
与非续订订阅有关,请访问https://developer.apple.com/in-app-purchase/In-App-Purchase-Guidelines.pdf:
使用iCloud或您自己的服务器跟踪购买情况,并允许用户将购买的订阅恢复到单个用户拥有的所有iOS设备

有人有任何见解吗?
问题:为什么SKReceiptRefreshRequest会在收据中留下非续订产品的购买?这是Apple文档中的错误还是还有其他事情发生?
14年2月23日; 更新:我最近在Apple上发布了一个错误报告.还没回来.虽然,实际上,我不希望这个"虫子"消失!
15年10月20日; 更新:似乎Apple实际上已经解决了这个"错误".现在,当我使用恢复时SKReceiptRefreshRequest(这似乎是Apple推荐的恢复方法,请参阅https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/StoreKitGuide/Chapters/Restoring.html) ,我现在没有在收据中显示未续订的订阅购买.我只收到非消耗品(我的应用程序只有非续订订阅和非消耗品购买).在我写完这篇文章后,我会立即向Apple提交一份错误报告,他们的文档对预期的行为不明确.
到目前为止,我对此测试的测试包括我在iOS 8.4和iOS9上运行的应用程序(实际上因为我没有正确的设备运行生产版本,因此测试版为9.1 beta),因此看起来这是Apple的服务器端更改而不是严格说iOS /设备方改变.另请注意,到目前为止,我的所有测试都是在我的应用程序的开发版本中,因此在应用内购买沙箱中也是如此.我很快就会进行生产测试.
15年12月3日; 更新; 在Apple技术支持的提示下,我又进行了一些测试.这一次,在运行iOS9.2 beta 4(13C75)的iPad上.现在看来我们已经恢复"正常",不续订订阅.也就是说,当我进行恢复时,我再次看到收据中未续订的订阅.
我在我的应用程序中进行了应用程序内购买,iOS 8中的新增内容是"延期"交易,部分在技术说明中描述
我理解它的作用,我需要不阻止UI,并更新我的UI以反映事务状态是延迟的.但是,我应该在-(void)transactionDeferred:(SKPaymentTransaction *)transaction暂时忽略交易的方法中放置什么呢?
我只更新了用户界面吗?UI的内容应该是什么?我是否需要用"您的购买延期"等替换价格标签?我认为没有办法测试这个,至少我没有看到任何与我的沙箱测试帐户有关的事情.如果有办法完成整个过程,看看它是如何工作的,那对我来说会更有意义.
我得到"这个应用程序购买已经被购买它将被免费恢复"但代表updatedTransactions没有被调用,没有任何反应,IAP没有执行.
我已经实现了恢复购买,它工作正常,但我如何阻止用户再次购买非消耗品?为什么没有调用委托updatedTransactions(SKPaymentTransactionState.Restored)?
即使在删除并重新安装应用程序后进行购买也会显示此弹出窗口.
这是我的代码.如果我做错了,请告诉我.谢谢
func makePaymentForProduct(product:SKProduct){
let payment = SKPayment.init(product: product)
SKPaymentQueue.defaultQueue().addPayment(payment)
SKPaymentQueue.defaultQueue().addTransactionObserver(self)
}
func restorePurchases(){
SKPaymentQueue.defaultQueue().restoreCompletedTransactions()
SKPaymentQueue.defaultQueue().addTransactionObserver(self)
}
//MARK: SKProductsRequestDelegate
func productsRequest(request: SKProductsRequest, didReceiveResponse response: SKProductsResponse) {
self.delegate?.didGetProducts(response.products)
}
func request(request: SKRequest, didFailWithError error: NSError) {
self.delegate?.purchaseFailed(error.localizedDescription)
}
//MARK: SKPaymentTransactionObserver
func paymentQueue(queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
for (_, transaction) in transactions.enumerate() {
switch (transaction.transactionState) {
case SKPaymentTransactionState.Purchased:
self.completeTransaction(transaction)
break
case SKPaymentTransactionState.Restored:
self.restoreTransaction(transaction)
break
case SKPaymentTransactionState.Failed:
self.failedTransaction(transaction)
break
default:
break
}
}
}
func completeTransaction(transaction:SKPaymentTransaction){
self.delegate?.purchaseSuccessful()
SKPaymentQueue.defaultQueue().finishTransaction(transaction)
}
func …Run Code Online (Sandbox Code Playgroud) iOS 15 引入了 StoreKit 2。我正在研究它,看看是否可以在我现有的应用程序中采用它,但我不知道该怎么做。特别是,我不知道如何实现所需的恢复功能(例如,如果用户删除了我的应用程序)。
我想我们应该使用Transaction.latest(for:)?是对的吗?
但在我的测试中,如果用户使用 StoreKit 1 进行了购买,则该调用将返回nil. 这是真的?或者,如果我做错了,从 StoreKit 1 迁移到 StoreKit 2 的正确方法是什么,以及我们如何处理恢复?
storekit ×10
ios ×7
iphone ×2
swift ×2
cocoa-touch ×1
ios7 ×1
objective-c ×1
restore ×1
tvos ×1
xcode ×1