【问题标题】:iOS in App purchase - auto renewal subscriptioniOS 应用内购买 - 自动续订订阅
【发布时间】:2018-06-01 07:51:40
【问题描述】:

亲爱的,

我有一个关于 iOS 应用购买的问题,专门针对“自动续订订阅” 我开发的应用程序包含免费功能和付费功能: 基于“每月订阅和用户免费试用 1 周”的付费功能

所有过程都很好:我们将获取产品&用户可以购买&我们将验证收据(我知道配方包含“is_trial..”和“Purchase_date”的标志......)........

请注意:我在购买或恢复后称为“验证配方”

但我有以下问题: 我怎么知道以下内容:

1- 如果用户第二次打开应用程序,我如何知道用户是否仍处于试用期?

2- 如果用户在 1 个月后打开应用程序:我如何知道订阅是否过期......(所以如果订阅过期,我将再次拨打购买电话......)

,是每次用户打开应用时我都会调用“验证配方”的解决方案,这样我就可以知道用户是在付费期间还是在付费期(过期)之后……

或者我将在本地保存购买日期(例如:用户默认)&当用户打开应用程序时,我会将当前日期与购买日期进行比较,我真的不认为这是一个真实的答案,因为用户可能会更改设备日期...... .

请指教……

下面的代码:

所以现在打开应用程序时: 我要求产品:

SKPaymentQueue.default().add(self)
        if(SKPaymentQueue.canMakePayments()) {
            print("IAP is enabled, loading")


            let productID: NSSet = NSSet(objects: "test.test1.test2.11")



            let request: SKProductsRequest = SKProductsRequest(productIdentifiers: productID as! Set<String>)
            request.delegate = self
            request.start()
        } else {
            print("please enable IAPS")
        }

收到产品时:

  func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
        print("product request")
        let myProduct = response.products
        for product in myProduct {


            list.append(product)
        }
}

现在当用户按下按钮时:

for product in self.list {
        let prodID = product.productIdentifier
        if(prodID == "test.test1.test2.11") {
            self.p = product
            self.buyProduct()

        }
    }

下面的方法会调用

 func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
        print("add payment")

        for transaction: AnyObject in transactions {
            let trans = transaction as! SKPaymentTransaction

            switch trans.transactionState {
            case .purchased:
                receiptValidation()
                queue.finishTransaction(trans)

                break
            case .failed:
                print("buy error")
                queue.finishTransaction(trans)
                break
            default:
                print("Default")
                break
            }
        }
    }

&我将验证收据:

func receiptValidation() {
        if let appStoreReceiptURL = Bundle.main.appStoreReceiptURL,
            FileManager.default.fileExists(atPath: appStoreReceiptURL.path) {

            do {
                let receiptData = try Data(contentsOf: appStoreReceiptURL, options: .alwaysMapped)

                let receiptString = receiptData.base64EncodedString(options: [])
                let dict = ["receipt-data" : receiptString, "password" : "xxxxxxxxxxx"] as [String : Any]

                do {
                    let jsonData = try JSONSerialization.data(withJSONObject: dict, options: .prettyPrinted)

                    if let sandboxURL = Foundation.URL(string:"https://sandbox.itunes.apple.com/verifyReceipt") {
                        var request = URLRequest(url: sandboxURL)
                        request.httpMethod = "POST"
                        request.httpBody = jsonData
                        let session = URLSession(configuration: URLSessionConfiguration.default)
                        let task = session.dataTask(with: request) { data, response, error in
                            if let receivedData = data,
                                let httpResponse = response as? HTTPURLResponse,
                                error == nil,
                                httpResponse.statusCode == 200 {
                                do {
                                    if let jsonResponse = try JSONSerialization.jsonObject(with: receivedData, options: JSONSerialization.ReadingOptions.mutableContainers) as? Dictionary<String, AnyObject> {

        } else { print("Failed to cast serialized JSON to Dictionary<String, AnyObject>") }
                                }
                                catch { print("Couldn't serialize JSON with error: " + error.localizedDescription) }
                            }
                        }
                        task.resume()
                    } else { print("Couldn't convert string into URL. Check for special characters.") }
                }
                catch { print("Couldn't create JSON with error: " + error.localizedDescription) }
            }
            catch { print("Couldn't read receipt data with error: " + error.localizedDescription) }
        }
    }

【问题讨论】:

    标签: ios swift in-app-purchase subscription auto-renewable


    【解决方案1】:

    强烈建议您存储用户高级状态并在服务器端进行收据验证。这样您就可以在您的服务器上保留有关用户、他们的订阅到期、免费试用状态等的元数据,并在启动时刷新它。然后,您可以根据用户的开始/结束日期设置对 Apple 服务器的智能轮询,以进行收据验证/过期检查(也应该在服务器端完成)。这将保持其高级或非高级状态,并允许您触发必要的客户端 UI。

    【讨论】:

    • 所以我会在本地保存购买日期,然后我会在服务器端与当前日期进行比较?
    • 按照 Apple 的 documentation: 执行所有收据验证服务器端。您应该将客户收据发送到您自己的服务器以安全地实施收据验证。为方便起见,您可以将已验证收据中的必要购买/试用/订阅日期保存在您自己的表格中,或在每次启动时上传并验证客户收据(如果必须)。不要在本地存储任何购买数据。仅使用来自客户的收据。
    猜你喜欢
    • 2016-01-25
    • 2017-10-29
    • 1970-01-01
    • 2015-07-25
    • 1970-01-01
    • 2016-10-23
    • 2014-02-20
    • 2011-06-29
    • 2018-02-17
    相关资源
    最近更新 更多