簡體   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