ios - 如何在生产中获得原始应用程序版本?

标签 ios swift receipt-validation

我们最近将一款可购买的应用程序转变为“免费增值”模式。我们正在使用 Bundle.main.appStoreReceiptURL 提取收据,然后检查“original_application_version”以查看用户是否从 App Store 下载了较旧的付费版本,或者他们是否下载了较新的免费版本以及非消耗性应用程序购买升级到完整版。

这在测试 Sandbox 时非常有效,但在生产中,旧版本的应用程序无法正确验证它们是在免费增值版本之前下载的。

使用 productionStoreURL 和从 Bundle.main.appStoreReceiptURL 获取的收据调用以下代码:

private let productionStoreURL = URL(string: "https://buy.itunes.apple.com/verifyReceipt")
private let sandboxStoreURL = URL(string: "https://sandbox.itunes.apple.com/verifyReceipt")

private func verifyIfPurchasedBeforeFreemium(_ storeURL: URL, _ receipt: Data) {
    do {
        let requestContents:Dictionary = ["receipt-data": receipt.base64EncodedString()]
        let requestData = try JSONSerialization.data(withJSONObject: requestContents, options: [])

        var storeRequest = URLRequest(url: storeURL)
        storeRequest.httpMethod = "POST"
        storeRequest.httpBody = requestData

        URLSession.shared.dataTask(with: storeRequest) { (data, response, error) in
            DispatchQueue.main.async {
                if data != nil {
                    do {
                        let jsonResponse = try JSONSerialization.jsonObject(with: data!, options: []) as! [String: Any?]

                        if let statusCode = jsonResponse["status"] as? Int {
                            if statusCode == 21007 {
                                print("Switching to test against sandbox")
                                self.verifyIfPurchasedBeforeFreemium(self.sandboxStoreURL!, receipt)
                            }
                        }

                        if let receiptResponse = jsonResponse["receipt"] as? [String: Any?], let originalVersion = receiptResponse["original_application_version"] as? String {
                            if self.isPaidVersionNumber(originalVersion) {
                                // Update to full paid version of app
                                UserDefaults.standard.set(true, forKey: upgradeKeys.isUpgraded)
                                NotificationCenter.default.post(name: .UpgradedVersionNotification, object: nil)
                            }
                        }
                    } catch {
                        print("Error: " + error.localizedDescription)
                    }
                }
            }
            }.resume()
    } catch {
        print("Error: " + error.localizedDescription)
    }
}

private func isPaidVersionNumber(_ originalVersion: String) -> Bool {
    let pattern:String = "^\\d+\\.\\d+"
    do {
        let regex = try NSRegularExpression(pattern: pattern, options: [])
        let results = regex.matches(in: originalVersion, options: [], range: NSMakeRange(0, originalVersion.count))

        let original = results.map {
            Double(originalVersion[Range($0.range, in: originalVersion)!])
        }

        if original.count > 0, original[0]! < firstFreemiumVersion {
            print("App purchased prior to Freemium model")
            return true
        }
    } catch {
        print("Paid Version RegEx Error.")
    }
    return false
}

第一个免费增值版本是 3.2,这是我们当前的版本。所有以前的版本都是 3.1.6 或更早版本。

生产 URL 不应该是问题,否则它不会回退 21007 状态代码来为我们触发沙盒验证。但是,解决此问题特别棘手,因为我们无法针对 Apple 的生产 URL 本身进行测试。

有没有人知道为什么这在沙盒中有效但在生产中无效?

最佳答案

看来拿到收据完全没有问题。

original_application_version 的一些旧值格式不正确,导致我们无法获取要比较的应用版本。

关于ios - 如何在生产中获得原始应用程序版本?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53990592/

相关文章:

ios - iOS 应用程序的收据验证码,不起作用

ios - 类型 'GKEntity' 的值没有成员 'componentForClass' 。为什么我在 swift 3.0 中找不到这个方法?

iOS 8 SpriteKit 框架向后兼容性

ios - 从另一个 View 单击时如何隐藏按钮

ios - 了解 iOS 中的收据验证和收据刷新

ios - 用户购买和下载应用程序时,苹果会开具收据吗?

ios - 如何制作pageControl滑动效果? ScrollView 连续滑动至今

ios - 修改 NSHTTPURLResponse 中的 header

ios - 当我使用 Storyboard 创建我的第一个 CollectionView 时,CollectionViewCell 从顶部开始默认插入?

swift - 如何从字典中制作 Decodable 对象?