Покупки в приложении для iOS: SKErrorDomain Code = 0 возвращается при попытке выкупить предложение подписки в течение действительного периода подписки - PullRequest
3 голосов
/ 17 июня 2019

Цель:

Я хотел бы выкупить предложение о подписке, если подписка с автоматическим продлением в настоящее время активна и срок ее действия не истек.

Что я пробовал:

Я настроил демонстрационный проект Store Kit на Xcode 10.2, чтобы протестировать новые предложения подписки. После выполнения основных положений WWDC 2019 и устранения неполадок я смог достичь следующего:

  1. Успешно настроить подписку с возможностью автоматического продления на 1 месяц с помощью StoreKit.
  2. Нажмите конечную точку / verifyReceipt и успешно расшифровали данные квитанции.
  3. Настройка локального сервера и успешно сгенерированная подпись.
  4. Настройка предложения подписки (1 месяц бесплатно) в Appstore Connect.
  5. Успешно погашенное предложение подписки после истечения срока действия возобновляемой подписки.

Моя текущая проблема:

Всякий раз, когда я пытаюсь получить предложение о подписке, и моя автоматически возобновляемая подписка все еще активна, я получаю следующую ошибку от StoreKit:

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

Удивительно, однако, что при попытке запросить предложение появляется окно с сообщением «Все готово. Ваша покупка прошла успешно. [Среда: Песочница]», несмотря на то, что в журналах появилось сообщение об ошибке выше.

Согласно документации Apple на SKErrorDomain (ссылка: 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, когда я пытаюсь использовать предложение подписки во время активной подписки. Я могу выкупить подписку после истечения срока действия подписки с возможностью автоматического продления, и я проверил квитанцию ​​и увидел данные о предложении подписки на квитанции.

Есть идеи, где я могу пойти не так? Или это проблема со стороны Apple?

...