iOS应用内购买:尝试在有效订阅期内赎回订阅优惠时,返回SKErrorDomain代码= 0

时间:2019-06-17 17:11:23

标签: ios swift in-app-purchase subscription

目标:

我想在当前处于活动状态且未过期的自动续订订阅中兑换订阅优惠。

我尝试过的事情:

我在Xcode 10.2上设置了一个Store Kit演示项目,以测试新的订阅优惠。在遵循WWDC 2019主题演讲和大量故障排除之后,我能够实现以下目标:

  1. 使用StoreKit成功设置了一个为期1个月的自动续订。
  2. 点击/ verifyReceipt端点并成功解密收据数据。
  3. 设置本地服务器并成功生成签名。
  4. 在Appstore Connect上设置订阅优惠(免费1个月)。
  5. 可续订的订阅到期后成功兑换了订阅优惠。

我当前的问题:

每当我尝试申领订阅优惠并且我的自动续订订阅仍处于活动状态时,都会从StoreKit中收到以下错误消息:

Error Domain=SKErrorDomain Code=0 "Cannot connect to iTunes Store" UserInfo={NSLocalizedDescription=Cannot connect to iTunes Store}

但是,令人惊讶的是,尽管在日志中收到了上述错误消息,但试图索要要约的消息时弹出一个警告框,提示“您已准备就绪。您的购买已成功。[环境:沙箱]”。

根据SKErrorDomain上的Apple文档(链接:https://developer.apple.com/documentation/storekit/skerror/code),代码0为“未知错误”。这是我碰到的砖墙。

在此演示项目的开发过程中,我收到了其他错误代码,例如ErrorCode = 12,这意味着我解决了“无效签名”,因此,我确定签名没有问题。在下面查看我的设置以获取更多背景信息。

我敦促您在这里忽略我的非最佳编码实践。我把这些作为概念证明,而不是用于生产。

这是点击“索赔奖励”按钮的操作,该按钮试图兑现订阅优惠:

// PrimaryVC.swift

@IBAction func aClaimReward(_ sender: UIButton) {

        // Hard code offer information
        let username = "mail@mysandbox.com" // sandbox username
        guard let usernameData =  username.data(using: .utf8) else { return }
        let usernameHash = usernameData.md5().toHexString()

        // Enums for simplifying the product identifiers.
        let productIdentifier = IAPProduct.autoRenewable.rawValue
        let offerIdentifier = IAPProduct.reward.rawValue

        // Call prepare offer method and get discount in completion block
        IAPService.shared.prepareOffer(usernameHash: usernameHash, productIdentifier: productIdentifier, offerIdentifier: offerIdentifier) { (discount) in

            // Find the autorenewable subscription in products set
            guard let product = IAPService.shared.products.filter({ $0.productIdentifier == IAPProduct.autoRenewable.rawValue }).first else {
                return
            }

            // Complete transaction
            self.buyProduct(product: product, forApplicationUsername: usernameHash, withOffer: discount)
        }
    }

这是在上述操作结束时使用的buyProduct()方法的代码:

// PrimaryVC.swift

func buyProduct(product: SKProduct, forApplicationUsername usernameHash: String, withOffer offer: SKPaymentDiscount) {

        // Create payment object
        let payment = SKMutablePayment(product: product)

        // Apply username and offer to the payment
        payment.applicationUsername = usernameHash
        payment.paymentDiscount = offer

        // Add payment to paymentQueue
        IAPService.shared.paymentQueue.add(payment)
    }

我创建了一个应用内购买服务类,其中许多应用内购买逻辑都存在。该单例用于上面详细介绍的按钮操作中,其使用的方法如下:

// IAPService.swift

import SwiftyJSON
import Alamofire

// ...

func prepareOffer(usernameHash: String, productIdentifier: String, offerIdentifier: String, completion: @escaping (SKPaymentDiscount) -> Void) {

        // Create parameters dictionary
        let parameters: Parameters = [
            "appBundleID": "my.bundle.id",
            "productIdentifier": productIdentifier, // "my.product.id",
            "offerID": offerIdentifier, // "REFERRALBONUSMONTH"
            "applicationUsername": usernameHash
        ]

        // Generate new signature by making get request to local server.
        // I used the starter code from the wwdc2019 lecture on subscription offers

        AF.request("https://mylocalserver/offer", parameters: parameters).responseJSON { response in

            var signature: String?
            var keyID: String?
            var timestamp: NSNumber?
            var nonce: UUID?

            switch response.result {
            case let .success(value):
                let json = JSON(value)

                // Get required parameters for creating offer
                signature = json["signature"].stringValue
                keyID = json["keyID"].stringValue
                timestamp = json["timestamp"].numberValue
                nonce = UUID(uuidString: json["nonce"].stringValue)

            case let .failure(error):
                print(error)
                return
            }

            // Create offer
            let discountOffer = SKPaymentDiscount(identifier: offerIdentifier, keyIdentifier: keyID!, nonce: nonce!, signature: signature!, timestamp: timestamp!)

            // Pass offer in completion block
            completion(discountOffer)
        }
    }

结论:

根据WWDC2019订阅优惠讲座,即使在活跃订阅期间,用户也应该能够兑换订阅优惠,但是当我尝试在活跃订阅期间兑换订阅优惠时,我仍然得到SKErrorCode = 0。我可以在自动续订的订阅到期后兑换该订阅,并且已经验证了收据并在收据上看到了订阅优惠的数据。

关于我可能要去哪里的任何想法?还是这是苹果方面的问题?

0 个答案:

没有答案