Получение оригинальной версии покупки, загруженной пользователем - PullRequest
0 голосов
/ 04 февраля 2019

, поэтому я изменяю свое приложение с платного на бесплатное и хочу, чтобы платные клиенты пользовались расширенными функциями.Один из способов сделать это - просто проверить их первоначальную версию приложения и посмотреть, платная ли это версия, а затем просто предоставить им расширенные функции, но я могу найти только текущую версию приложения пользователя вместо первоначальной купленной версии.,

Я читал, и, возможно, это может быть связано с проверкой квитанции, но если есть способ получить оригинальную версию приложения для покупки, может кто-нибудь помочь.

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

let version : String! = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String
print(version)

Спасибо

1 Ответ

0 голосов
/ 04 февраля 2019

Как я уже писал в комментариях, я не уверен, что это правильный процесс, но для приложения, которое я сделал, я проверяю квитанцию ​​со следующим кодом:

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

Важно также отметить, что Apple не рекомендует напрямую проверять через серверы AppStore (так как идентификация не может быть проверена, и это может привести катаки в середине)

Используйте доверенный сервер для связи с App Store.Использование вашего собственного сервера позволяет вам разрабатывать приложение, чтобы распознавать и доверять только вашему серверу, а также обеспечивает подключение вашего сервера к серверу App Store.Невозможно создать надежное соединение между устройством пользователя и App Store напрямую, поскольку вы не контролируете ни один из этих концевых соединений и, следовательно, можете быть подвержены атаке «человек посередине».

Но, если вам в этом поможет, вот две конечные точки Apple для (отладка / производство).

    #if DEBUG
    private let appStoreValidationURL = URL(string: "https://sandbox.itunes.apple.com/verifyReceipt")!
    #else
    private let appStoreValidationURL = URL(string: "https://buy.itunes.apple.com/verifyReceipt")!
    #endif

В то время как, что касается SharedSecret вашего приложения, вам нужно пройти поВ квитанции вы можете найти полезную информацию здесь .

  1. Получить квитанцию.
private func loadReceipt() throws -> Data {
        guard let url = Bundle.main.appStoreReceiptURL else {
            throw ReceiptValidationError.noReceiptData
        }

        do {
            let data = try Data(contentsOf: url)
            return data
        } catch {
            print("Error loading receipt data: \(error.localizedDescription)")
            throw ReceiptValidationError.noReceiptData
        }
    }
Затем вы можете прочитать содержимое в формате JSON с помощью
[...]
 // Handle the try. I skipped that to make easier to read 
 let data = try! loadReceipt()
 let base64String = data.base64EncodedString(options: [])

 // Encode data in JSON
 let content: [String : Any] = ["receipt-data" : base64String,
                                       "password" : sharedSecret,
                                       "exclude-old-transactions" : true]

Отправьте запрос квитанции на сервер Apple для проверки.
private func validateLastReceipt(_ data: Data) {

        let base64String = data.base64EncodedString(options: [])

        // Encode data in JSON
        let content: [String : Any] = ["receipt-data" : base64String,
                                       "password" : sharedSecret,
                                       "exclude-old-transactions" : false]
        let json = try! JSONSerialization.data(withJSONObject: content, options: [])

        // build request
        let storeURL = self.appStoreValidationURL

        var request = URLRequest(url: storeURL)
        request.httpMethod = "POST"
        request.httpBody = json

        // Make request to app store

        URLSession.shared.dataTask(with: request) { (data, res, error) in
            guard error == nil, let data = data else {
                self.delegate?.validator(self, didFinishValidateWith: error!)
                return
            }

            do {
                let decoder = JSONDecoder()
                let response = try decoder.decode(ReceiptAppStoreResponse.self, from: data)                                
            } catch {
                // Handle error
            }

            }.resume()
    }

Здесь я создал структуру Decodables. Там вы найдете всю информацию, необходимую для проверки того, что купил пользователь!

private struct ReceiptAppStoreResponse: Decodable {
    /// Either 0 if the receipt is valid, or one of the error codes listed in Table 2-1.
    ///
    /// For iOS 6 style transaction receipts, the status code reflects the status of the specific transaction’s receipt.
    ///
    /// For iOS 7 style app receipts, the status code is reflects the status of the app receipt as a whole. For example, if you send a valid app receipt that contains an expired subscription, the response is 0 because the receipt as a whole is valid.
    let status: Int?

    /// A JSON representation of the receipt that was sent for verification.
//    let receipt: String?

    /// Only returned for receipts containing auto-renewable subscriptions. For iOS 6 style transaction receipts,
    /// this is the base-64 encoded receipt for the most recent renewal. For iOS 7 style app receipts, this is the latest
    /// base-64 encoded app receipt.
    let latestReceipt: String?

    /// Only returned for receipts containing auto-renewable subscriptions. For iOS 6 style transaction receipts,
    /// this is the JSON representation of the receipt for the most recent renewal. For iOS 7 style app receipts,
    /// the value of this key is an array containing all in-app purchase transactions.
    /// This excludes transactions for a consumable product that have been marked as finished by your app.
    let latestReceiptInfo: [ReceiptInfo]?

    /// Only returned for iOS 6 style transaction receipts, for an auto-renewable subscription.
    /// The JSON representation of the receipt for the expired subscription.
    //    let latestExpiredReceiptInfo: String?

    /// Only returned for iOS 7 style app receipts containing auto-renewable subscriptions.
    /// In the JSON file, the value of this key is an array where each element contains the pending renewal information
    /// for each auto-renewable subscription identified by the Product Identifier.
    /// A pending renewal may refer to a renewal that is scheduled in the future or a renewal that failed
    /// in the past for some reason.
    //    let pendingRenewalInfo: String?

    /// Retry validation for this receipt. Only applicable to status codes 21100-21199
    //    let isRetryable: Bool?

    enum CodingKeys: String, CodingKey {
        case status
//        case receipt
        case latestReceipt = "latest_receipt"
        case latestReceiptInfo = "latest_receipt_info"
        //        case latestExpiredReceiptInfo = "latest_expired_receipt_info"
        //        case pendingRenewalInfo = "pending_renewal_info"
        //        case isRetryable = "is-retryable"
    }

}

struct ReceiptInfo: Decodable {

    let originalTransactionID: String?
    let productID: String?

    let expiresDateMS: String?

    let originalPurchaseDateMS: String?

    let isTrialPeriod: String?
    let isInIntroOfferPeriod: String?

    let purchaseDateMS: String?

    enum CodingKeys: String, CodingKey {
        case originalTransactionID = "original_transaction_id"
        case productID = "product_id"

        case expiresDateMS = "expires_date_ms"

        case originalPurchaseDateMS = "original_purchase_date_ms"

        case isTrialPeriod = "is_trial_period"
        case isInIntroOfferPeriod = "is_in_intro_offer_period"

        case purchaseDateMS = "purchase_date_ms"
    }

    func getExpireDate() -> Date? {
        let nf = NumberFormatter()
        guard let expDateString = self.expiresDateMS, let expDateValue = nf.number(from: expDateString) else {
            return nil
        }

        /// It's expressed as milliseconds since 1970!!!
        let date = Date(timeIntervalSince1970: expDateValue.doubleValue / 1000)

        return date

    }

Надеюсь, это поможет!:)

...