То, что нужно знать о проверке чека App Store (App Store receipt)

  • Tutorial

В StackOverflow по-прежнему появляется много вопросов о валидации App Store чеков, поэтому мы решили написать статью на эту тему в формате вопросов и ответов.


image


Что представляет собой App Store чек?


Это зашифрованный файл в формате PKCS#7, который содержит в себе информацию обо всех покупках в приложении. Находится в бандле приложения и его можно легко получить, вызвав: Bundle.main.appStoreReceiptURL.


Всегда ли есть этот файл?


Если приложение было скачано из App Store, то да, всегда. А если было установлено через Xcode или Testflight, то первоначально у приложения sandbox-чек отсутствует до первой покупки или восстановления чека.


Что значит "провалидировать чек"?


Это означает расшифровать файл, получить JSON дату и сверить совершенные пользователем покупки. Сделать это можно локально или отправив запрос в Apple.


В каких случаях разработчику требуется валидация чека?


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


При восстановлении покупок.
Если пользователь переустановил ваше приложение или запустил с другого устройства, вы должны предоставить ему доступ к функционалу, за который он уже заплатил. Расшифровав App Store чек, вы сможете выяснить, была ли приобретена встроенная покупка.


При покупке авто-возобновляемых подписок.
Для определения текущего статуса подписки и даты истечения.


Какие покупки можно восстановить при валидации?


Существует 4 вида встроенных покупок:


  • расходуемые (consumable purchases),
  • нерасходуемые (non-consumable purchases),
  • невозобновляемые подписки (non-renewing subscriptions),
  • авто-возобновляемые подписки (auto-renewable Subscriptions).
    Восстановить можно все, кроме расходуемых покупок. К ним можно отнести, например, монетки в вашем приложении – что-то, что можно купить сколько угодно раз. Вы должны сами сохранять текущее количество монеток у пользователя на своем сервере.

Какие способы валидации существуют?


Их три:


  • локальная валидация с использованием OpenSSL,
  • валидация по запросу в Apple прямо с iOS устройства,
  • валидация по запросу в Apple с использованием вашего сервера.

Какой способ валидации лучше?


Локальная валидация сложна и требует много времени и усилий на реализацию. А еще вы должны будете добавить OpenSSL библиотеку в ваш проект. В некоторых случаях придется обновлять чек.


Apple не рекомендует проверять чеки на самом iOS-устройстве. Это небезопасно: запрос можно перехватить с помощью man-in-the-middle атаки.


Лучше всего валидировать чеки на сервере. Тем более, что Apple время от времени добавляет туда новые поля, например, grace_period_expires_date и subscription_group_identifier. На своем сервере мы сможете быстро вносить изменения без обновления приложения. А еще предыдущие два метода валидации можно легко обмануть, просто поменяв системное время на iOS устройстве.


Для чего нужен Shared Secret?


Это специальная строка-ключ, которая необходима для расшифровки чеков с авто-возобновляемыми покупками. Apple использует Shared secret как параметр в HTTPS запросе к Apple.


Где взять Shared Secret?


Перейдите в App Store Connect, откройте приложение, перейдите во вкладку Функции, в разделе Встроенные покупки увидите кнопку Общий ключ для приложения. Сгенерируйте новый ключ, если его еще нет.


Пример кода для валидации чека


func validateReceipt(){

        #if DEBUG
                   let urlString = "https://sandbox.itunes.apple.com/verifyReceipt"
               #else 
                   let urlString = "https://buy.itunes.apple.com/verifyReceipt"
               #endif

        guard let receiptURL = Bundle.main.appStoreReceiptURL, let receiptString = try? Data(contentsOf: receiptURL).base64EncodedString() , let url = URL(string: urlString) else {
                return
        }

        let requestData : [String : Any] = ["receipt-data" : receiptString, 
                                            "password" : "YOUR_SHARED_SECRET", 
                                            "exclude-old-transactions" : false]
        let httpBody = try? JSONSerialization.data(withJSONObject: requestData, options: [])

        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        request.setValue("Application/json", forHTTPHeaderField: "Content-Type")
        request.httpBody = httpBody
        URLSession.shared.dataTask(with: request)  { (data, response, error) in
            // convert data to Dictionary and view purchases
        }.resume()        
    }

Это пример валидации чека на iOS. Не забудьте заменить значение YOUR_SHARED_SECRET на ваш shared secret.


Получив data, сконвертируйте его в Dictionary:


DispatchQueue.main.async {
    if let data = data, let jsonData = try? JSONSerialization.jsonObject(with: data, options: .allowFragments){
    // your non-consumable and non-renewing subscription receipts are in `in_app` array
    // your auto-renewable subscription receipts are in `latest_receipt_info` array
  }                
}

Пример расшифрованного App Store чека


Здесь можно посмотреть пример чека с двумя транзакциями в приложении с авто-возобновляемой подпиской.


В чем отличия между in_app и latest_receipt_info?


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


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



Заключение


Мы в Apphud реализовали валидацию App Store чеков для приложений с авто-возобновляемыми подписками в удобном open-source SDK. А еще Apphud помогает отслеживать статус подписки, анализировать ключевые метрики, автоматически предлагать скидки отписавшимся пользователям и многое другое. Если при работе с подписками вы испытываете боль, попробуйте наше решение бесплатно.

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.

А как вы валидируете покупки?

  • 3.7%Локально с использованием OpenSSL1
  • 18.5%На iOS устройстве5
  • 51.8%На своем сервере14
  • 3.7%Использую готовый сервис: Apphud, RevenueCat или другой1
  • 22.2%Вообще не валидирую6
  • +13
  • 3,8k
  • 2
Apphud
48,22
Сервис для работы с подписками в iOS-приложениях
Поделиться публикацией
AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее
Реклама

Комментарии 2

    0
    Ответье пожалуйста, для чего вы ставите тег «objective-c» на статью, в которой отсутствует код Objective-C?
      0
      Убрали

    Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

    Самое читаемое