首页 > 解决方案 > 如何检查用户是否已在 Swift 中为 App 购买中的自动续订订阅付费

问题描述

我目前有一个Non-Consumable和一个Auto Renewal Subscription应用内购买设置在iTunesConnect. 我的问题是我不确定如何检查内容是否可以为Auto Renewal Subscription. 我对应用内购买没有任何问题Non-Consumables,我通过检查产品 ID 是否存在来验证它们,如果存在UserDefaults,我解锁内容,否则我通知用户,但此方法不适用于Auto Renewal Subscription应用内购买。当我测试它时,我可以通过应用商店进行购买交易,但是当我尝试查看产品 ID 是否存在时,UserDefaults它返回 false。事实上,我手动检查了密钥是否存在,它只显示Non-Consumable购买密钥。

这是我正在使用的代码。

这是我多年来一直用于验证Non-Consumable应用购买的工作代码。

这是In App Manager我正在使用的课程。

import UIKit
import StoreKit

protocol IAPManagerDelegate {
    func managerDidRestorePurchases()
}

class IAPManager: NSObject, SKProductsRequestDelegate, SKPaymentTransactionObserver, SKRequestDelegate {
    static let sharedInstance = IAPManager()
    var request:SKProductsRequest!
    var products:NSArray!
    var delegate:IAPManagerDelegate?

    func setupInAppPurchases(){
        self.validateProductIdentifiers(self.getProductIdentifiersFromMainBundle())

        SKPaymentQueue.default().add(self)
    }

    func getProductIdentifiersFromMainBundle() -> NSArray {
        var identifiers = NSArray()
        if let url = Bundle.main.url(forResource: "iap_product_ids", withExtension: "plist"){
            identifiers = NSArray(contentsOf: url)!
        }
        return identifiers
    }

    func validateProductIdentifiers(_ identifiers:NSArray) {
        let productIdentifiers = NSSet(array: identifiers as [AnyObject])
        let productRequest = SKProductsRequest(productIdentifiers: productIdentifiers as! Set<String>)
        self.request = productRequest
        productRequest.delegate = self
        productRequest.start()
    }

    func createPaymentRequestForProduct(_ product:SKProduct){
        let payment = SKMutablePayment(product: product)
        payment.quantity = 1
        SKPaymentQueue.default().add(payment)
    }

    func verifyReceipt(_ transaction:SKPaymentTransaction?){
        let receiptURL = Bundle.main.appStoreReceiptURL!
        if let receipt = try? Data(contentsOf: receiptURL){

            let requestContents = ["receipt-data" : receipt.base64EncodedString(options: NSData.Base64EncodingOptions(rawValue: 0))]

            do {
                let requestData = try JSONSerialization.data(withJSONObject: requestContents, options: JSONSerialization.WritingOptions(rawValue: 0))
                //  PRODUCTION URL
                // let storeURL = URL(string: "https://buy.itunes.apple.com/verifyReceipt")
                //  TESTING URL: Uncomment for testing InAppPurchases
                let storeURL = URL(string: "https:/sandbox.itunes.apple.com/verifyReceipt")

                var request = URLRequest(url: storeURL!)
                request.httpMethod = "Post"
                request.httpBody = requestData

                let session = URLSession.shared
                let task = session.dataTask(with: request,
                                            completionHandler: { (responseData, response, error) -> Void in
                    do {
                        let json = try JSONSerialization.jsonObject(with: responseData!, options: .mutableLeaves) as! NSDictionary
                        if (json.object(forKey: "status") as! NSNumber) == 0 {
                            if let latest_receipt = json["latest_receipt_info"]{
                                self.validatePurchaseArray(latest_receipt as! NSArray)
                            } else {
                                let receipt_dict = json["receipt"] as! NSDictionary
                                if let purchases = receipt_dict["in_app"] as? NSArray{
                                    self.validatePurchaseArray(purchases)
                                }
                            }
                            if transaction != nil {
                                SKPaymentQueue.default().finishTransaction(transaction!)
                            }
                            DispatchQueue.main.sync(execute: { () -> Void in
                                self.delegate?.managerDidRestorePurchases()
                            })
                        } else {
                            print(json.object(forKey: "status") as! NSNumber)
                        }
                    } catch {
                        print(error)
                    }
                })
                task.resume()
            } catch {
                print(error)
            }
        } else {
            print("No Receipt")
        }
    }

    func validatePurchaseArray(_ purchases:NSArray){
        for purchase in purchases as! [NSDictionary]{
            self.unlockPurchasedFunctionalityForProductIdentifier(purchase["product_id"] as! String)
        }
    }

    func unlockPurchasedFunctionalityForProductIdentifier(_ productIdentifier:String){
        UserDefaults.standard.set(true, forKey: productIdentifier)
        UserDefaults.standard.synchronize()
        DispatchQueue.main.async {
            UIApplication.shared.isNetworkActivityIndicatorVisible = false
        }
    }

    func lockPurchasedFunctionalityForProductIdentifier(_ productIdentifier:String){
        UserDefaults.standard.set(false, forKey: productIdentifier)
        UserDefaults.standard.synchronize()
        UIApplication.shared.isNetworkActivityIndicatorVisible = false
    }

    func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
        let inAppPurchases = response.products
        // Sort the items
        self.products = inAppPurchases.reversed() as NSArray
    }

    func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
        for transaction in transactions as [SKPaymentTransaction]{
            switch transaction.transactionState{
            case .purchasing:
                print("Purchasing")
                UIApplication.shared.isNetworkActivityIndicatorVisible = true
            case .deferred:
                print("Deferrred")
                UIApplication.shared.isNetworkActivityIndicatorVisible = false
            case .failed:
                print("Failed")
                //print(transaction.error?.localizedDescription)
                UIApplication.shared.isNetworkActivityIndicatorVisible = false
                SKPaymentQueue.default().finishTransaction(transaction)
            case.purchased:
                print("Purchased")
                self.verifyReceipt(transaction)
            case .restored:
                print("Restored")

            }
        }
    }

    func restorePurchases(){
        let request = SKReceiptRefreshRequest()
        request.delegate = self
        request.start()
    }

    func requestDidFinish(_ request: SKRequest) {
        self.verifyReceipt(nil)
    }
}

这是我如何In App PurchasesUITableView.

class StoreTableViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, IAPManagerDelegate {
    @IBOutlet weak var premiumFeaturesTable: UITableView!
    @IBOutlet weak var buttonClose: UIButton!
    @IBOutlet weak var buttonRestore: UIButton!

    override func viewDidLoad() {
        super.viewDidLoad()
        IAPManager.sharedInstance.delegate = self
    }

    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return IAPManager.sharedInstance.products.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell =  tableView.dequeueReusableCell(withIdentifier: "cellInAppPurchase")as! CustomCellForInAppPurchasesTableViewCell
        let product = IAPManager.sharedInstance.products.object(at: indexPath.row) as! SKProduct

         cell.labelIAppItem.text = product.localizedTitle
        return cell
    }

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.deselectRow(at: indexPath, animated: true)
        IAPManager.sharedInstance.createPaymentRequestForProduct(IAPManager.sharedInstance.products.object(at: indexPath.row) as! SKProduct)
    }

    @IBAction func closeViewController(_ sender: AnyObject) {
        self.presentingViewController!.dismiss(animated: true, completion: nil)
    }

    @IBAction func restorePurchases(_ sender: AnyObject) {
        IAPManager.sharedInstance.restorePurchases()
    }
}

这是我解锁内容的方式

if NSUserDefaults.standardUserDefaults().boolForKey("com.theAppID.app"){
    // Unlock content.
}else{
    // Notify user.
}

同样,一切正常,Non-ConsumablesAuto Renewal Subscriptions我不确定如何在用户购买后解锁内容。

我错过了什么,检查用户是否已Auto Renewal Subscription根据上述代码付费的正确方法是什么?

编辑:最简单的答案是......为您的基于订阅的应用程序使用 RevenueCat,它让您的生活更轻松。

标签: iosswiftin-app-purchase

解决方案


请检查此链接以获取自动续订订阅。

您可以使用应用内管理器类中的以下功能。

func verifyReceipt(_ transaction:SKPaymentTransaction?) 

验证后,您将获得以下响应代码和订阅最后日期的详细信息。请检查此链接

注意:不要忘记在自动续订的收据验证中传递“密码”字段。


推荐阅读