iOS 应用内购买不适用于 TestFlight 中的非沙盒帐户
Posted
技术标签:
【中文标题】iOS 应用内购买不适用于 TestFlight 中的非沙盒帐户【英文标题】:iOS In-App-Purchases don't work for non-sandbox accounts in TestFlight 【发布时间】:2020-11-01 12:43:00 【问题描述】:我使用来自https://www.raywenderlich.com/5456-in-app-purchase-tutorial-getting-started 的教程在我的应用中实现了应用内购买。我没有使用我自己的服务器来验证购买或类似的东西。
我创建了一个沙盒用户来测试代码。一切正常,但是,如果我尝试使用我的个人 Apple ID 登录,购买将失败(在 TestFlight 上测试)。
这是预期的行为还是我做错了什么? https://***.com/a/37042040/11912101 声明每个帐户都应该能够购买物品。
另外,我在 App Store Connect 中为沙盒用户启用了“中断购买”选项。下面的代码将运行函数 failed(...),即使购买已通过并且该项目在我的应用程序中已解锁并被添加到购买的 ProductIdentifiers 中。有没有办法处理那些中断的购买?
感谢您的回答!
import StoreKit
public struct InAppPurchases
static let proVersionID = "myapp.proversion"
private static let productIdentifiers: Set<ProductIdentifier> = [proVersionID]
public static let helper = InAppPurchaseHelper(productIds: InAppPurchases.productIdentifiers)
func resourceNameForProductIdentifier(_ productIdentifier: String) -> String?
return productIdentifier.components(separatedBy: ".").last
public typealias ProductIdentifier = String
public typealias ProductsRequestCompletionHandler = (_ success: Bool, _ products: [SKProduct]?) -> Void
extension Notification.Name
static let IAPHelperPurchaseNotification = Notification.Name("IAPHelperPurchaseNotification")
open class InAppPurchaseHelper: NSObject, ObservableObject
private let productIdentifiers: Set<ProductIdentifier>
private var purchasedProductIdentifiers: Set<ProductIdentifier> = []
willSet
self.objectWillChange.send()
private var productsRequest: SKProductsRequest?
private var productsRequestCompletionHandler: ProductsRequestCompletionHandler?
@Published var didFail = false
var availableProducts = [SKProduct]()
willSet
DispatchQueue.main.async
self.objectWillChange.send()
public init(productIds: Set<ProductIdentifier>)
productIdentifiers = productIds
for productIdentifier in productIds
let purchased = UserDefaults.standard.bool(forKey: productIdentifier)
if purchased
purchasedProductIdentifiers.insert(productIdentifier)
print("Previously purchased: \(productIdentifier)")
else
print("Not purchased: \(productIdentifier)")
super.init()
SKPaymentQueue.default().add(self)
reloadInAppPurchases()
func reloadInAppPurchases()
DispatchQueue.main.async
InAppPurchases.helper.requestProducts [weak self] success, products in
guard let self = self else return
if success
self.availableProducts = products!
extension InAppPurchaseHelper
public func requestProducts(_ completionHandler: @escaping ProductsRequestCompletionHandler)
productsRequest?.cancel()
productsRequestCompletionHandler = completionHandler
productsRequest = SKProductsRequest(productIdentifiers: productIdentifiers)
productsRequest!.delegate = self
productsRequest!.start()
public func buyProduct(_ product: SKProduct)
print("Buying \(product.productIdentifier)...")
let payment = SKPayment(product: product)
SKPaymentQueue.default().add(payment)
public func isProductPurchased(_ productIdentifier: ProductIdentifier) -> Bool
return purchasedProductIdentifiers.contains(productIdentifier)
public func isProVersion () -> Bool
if(isProductPurchased(InAppPurchases.proVersionID))
return true
return false
public class func canMakePayments() -> Bool
return SKPaymentQueue.canMakePayments()
public func restorePurchases()
SKPaymentQueue.default().restoreCompletedTransactions()
extension InAppPurchaseHelper: SKProductsRequestDelegate
public func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse)
print("Loaded list of products...")
let products = response.products
productsRequestCompletionHandler?(true, products)
clearRequestAndHandler()
for p in products
print("Found product: \(p.productIdentifier) \(p.localizedTitle) \(p.price.floatValue)")
public func request(_ request: SKRequest, didFailWithError error: Error)
print("Failed to load list of products.")
print("Error: \(error.localizedDescription)")
productsRequestCompletionHandler?(false, nil)
clearRequestAndHandler()
private func clearRequestAndHandler()
productsRequest = nil
productsRequestCompletionHandler = nil
extension InAppPurchaseHelper: SKPaymentTransactionObserver
public func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction])
for transaction in transactions
switch (transaction.transactionState)
case .purchased:
complete(transaction: transaction)
break
case .failed:
fail(transaction: transaction)
break
case .restored:
restore(transaction: transaction)
break
case .deferred:
break
case .purchasing:
break
@unknown default:
break
private func complete(transaction: SKPaymentTransaction)
print("complete...")
deliverPurchaseNotificationFor(identifier: transaction.payment.productIdentifier)
SKPaymentQueue.default().finishTransaction(transaction)
private func restore(transaction: SKPaymentTransaction)
guard let productIdentifier = transaction.original?.payment.productIdentifier else return
print("restore... \(productIdentifier)")
deliverPurchaseNotificationFor(identifier: productIdentifier)
SKPaymentQueue.default().finishTransaction(transaction)
private func fail(transaction: SKPaymentTransaction)
print("fail...")
if let transactionError = transaction.error as NSError?,
let localizedDescription = transaction.error?.localizedDescription,
transactionError.code != SKError.paymentCancelled.rawValue
print("Transaction Error: \(localizedDescription)")
SKPaymentQueue.default().finishTransaction(transaction)
if(!isProVersion())
didFail.toggle()
private func deliverPurchaseNotificationFor(identifier: String?)
guard let identifier = identifier else return
purchasedProductIdentifiers.insert(identifier)
UserDefaults.standard.set(true, forKey: identifier)
NotificationCenter.default.post(name: .IAPHelperPurchaseNotification, object: identifier)
【问题讨论】:
【参考方案1】:请参阅 this 和 this。
我最近使用其他帐户测试 IAP 没有问题。这很奇怪,因为默认情况下 testflight 是沙盒环境,所以我认为不需要像发布版本那样等待,但可能会等待几个小时以防万一。
【讨论】:
谢谢。我的代码正确吗?还是我需要为发布更改一些内容? 如果使用沙盒账户支付成功,那么您的代码应该没问题。您是否在 testflight 中填写了完整的测试信息?我建议您这样做并等待几个小时再进行测试。 关于“中断购买”问题,我不确定,因为我自己没有遇到过。但是,一旦您从自己的服务器验证购买,也许会得到处理,因为在结束购买之前会有额外的检查。 是的,我在 TestFlight 中填写了所有测试信息。仍然无法使用我的普通 iCloud 帐户登录。测试应用时,输入密码和id后登录页面消失,购买失败。以上是关于iOS 应用内购买不适用于 TestFlight 中的非沙盒帐户的主要内容,如果未能解决你的问题,请参考以下文章
应用内购买适用于 iOS 3 和 5,但不适用于 iOS 4