繁体   English   中英

iOS 应用内购买不适用于 TestFlight 中的非沙盒帐户

[英]iOS In-App-Purchases don't work for non-sandbox accounts in TestFlight

我使用https://www.raywenderlich.com/5456-in-app-purchase-tutorial-getting-started 中的教程在我的应用程序中实现了应用内购买。 我没有使用我自己的服务器来验证购买或类似的东西。

我创建了一个沙箱用户来测试代码。 一切正常,但是,如果我尝试使用我的个人 Apple ID 登录,购买将失败(在 TestFlight 上测试)。

这是预期的行为还是我做错了什么? https://stackoverflow.com/a/37042040/11912101指出每个帐户都应该能够购买物品。

此外,我在 App Store Connect 中为沙盒用户启用了“中断购买”选项。 下面的代码将运行函数 failed(...),即使购买通过并且项目在我的应用程序中被解锁并被添加到购买的产品标识符中。 有没有办法处理那些中断的购买?

谢谢回答!

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)
    }
}

看到这个这个

我最近用其他帐户测试 IAP 没有问题。 这很奇怪,因为默认情况下 testflight 是沙盒环境,所以我认为不需要像发布版本那样等待,但可能要等几个小时以防万一。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM