Транзакции и проверка в Xamarin.iOS
Восстановление прошлых транзакций
Если приложение поддерживает типы продуктов, которые можно восстановить, необходимо включить некоторые элементы пользовательского интерфейса, чтобы пользователи могли восстановить эти покупки. Эта функция позволяет клиенту добавлять продукт на дополнительные устройства или восстанавливать продукт на том же устройстве после очистки или удаления и повторной установки приложения. Следующие типы продуктов можно восстановить:
- Непотребляемые продукты
- Автоматическое возобновление подписки
- Бесплатные подписки
Процесс восстановления должен обновлять записи, которые хранятся на устройстве для выполнения продуктов. Клиент может в любой момент выбрать восстановление на любом из своих устройств. Процесс восстановления повторно отправляет все предыдущие транзакции для этого пользователя; Затем код приложения должен определить, какие действия следует предпринять с этой информацией (например, проверка, если на устройстве уже есть запись об этой покупке, а если нет, создайте запись покупки и включите продукт для пользователя).
Реализация восстановления
Кнопка восстановления пользовательского интерфейса вызывает следующий метод, который активирует RestoreCompletedTransactions в элементе SKPaymentQueue
.
public void Restore()
{
// theObserver will be notified of when the restored transactions start arriving <- AppStore
SKPaymentQueue.DefaultQueue.RestoreCompletedTransactions();
}
StoreKit отправит запрос на восстановление серверам Apple асинхронно.
Так как наблюдатель CustomPaymentObserver
транзакций зарегистрирован в качестве наблюдателя транзакций, он получит сообщения, когда серверы Apple отвечают. Ответ будет содержать все транзакции, которые пользователь когда-либо выполнял в этом приложении (на всех своих устройствах). Код выполняет циклы по каждой транзакции, обнаруживает восстановленное состояние и вызывает UpdatedTransactions
метод для его обработки, как показано ниже:
// called when the transaction status is updated
public override void UpdatedTransactions (SKPaymentQueue queue, SKPaymentTransaction[] transactions)
{
foreach (SKPaymentTransaction transaction in transactions)
{
switch (transaction.TransactionState)
{
case SKPaymentTransactionState.Purchased:
theManager.CompleteTransaction(transaction);
break;
case SKPaymentTransactionState.Failed:
theManager.FailedTransaction(transaction);
break;
case SKPaymentTransactionState.Restored:
theManager.RestoreTransaction(transaction);
break;
default:
break;
}
}
}
Если для пользователя нет восстанавливаемых продуктов, UpdatedTransactions
не вызывается.
Самый простой код для восстановления данной транзакции в примере выполняет те же действия, что и при покупке, за исключением того, что OriginalTransaction
свойство используется для доступа к идентификатору продукта:
public void RestoreTransaction (SKPaymentTransaction transaction)
{
// Restored Transactions always have an 'original transaction' attached
var productId = transaction.OriginalTransaction.Payment.ProductIdentifier;
// Register the purchase, so it is remembered for next time
PhotoFilterManager.Purchase(productId); // it's as though it was purchased again
FinishTransaction(transaction, true);
}
Более сложная реализация может проверка других transaction.OriginalTransaction
свойств, таких как исходная дата и номер квитанции. Эта информация будет полезна для некоторых типов продуктов (таких как подписки).
Завершение восстановления
У CustomPaymentObserver
него есть два дополнительных метода, которые будут вызываться StoreKit после завершения процесса восстановления (успешно или сбоем), показанного ниже:
public override void PaymentQueueRestoreCompletedTransactionsFinished (SKPaymentQueue queue)
{
Console.WriteLine(" ** RESTORE Finished ");
}
public override void RestoreCompletedTransactionsFailedWithError (SKPaymentQueue queue, NSError error)
{
Console.WriteLine(" ** RESTORE FailedWithError " + error.LocalizedDescription);
}
В примере этих методов ничего не делать, однако реальное приложение может выбрать реализацию сообщения пользователю или другим функциям.
Защита покупок
Два примера в этом документе используются NSUserDefaults
для отслеживания покупок:
Потребляемые средства — "баланс" кредитных покупок — это простое NSUserDefaults
целочисленное значение, которое увеличивается при каждой покупке.
Non-Consumables — каждая покупка фильтра фотографий хранится в виде пары NSUserDefaults
"ключ-значение".
Использование NSUserDefaults
кода сохраняет пример кода простым, но не предлагает очень безопасное решение, так как это возможно для технических пользователей для обновления параметров (обход механизма оплаты).
Примечание. В реальных приложениях должен быть реализован безопасный механизм хранения приобретенного содержимого, который не распространяется на пользователей. Это может включать шифрование и (или) другие методы, включая проверку подлинности удаленного сервера.
Этот механизм также должен быть разработан для использования встроенных функций резервного копирования и восстановления iOS, iTunes и iCloud. Это гарантирует, что после того, как пользователь восстановит резервную копию предыдущих покупок, будет немедленно доступен.
Ознакомьтесь с руководством по безопасному кодированию Apple для получения дополнительных рекомендаций для iOS.
Проверка квитанций и доставленные сервером продукты
Примеры этого документа до сих пор состоят исключительно из приложения, взаимодействующего непосредственно с серверами App Store для проведения транзакций покупки, которые разблокируют функции или возможности, уже закодированные в приложении.
Apple обеспечивает дополнительный уровень безопасности покупки, позволяя получать квитанции о покупке независимо от другого сервера, что может быть полезно для проверки запроса перед доставкой цифрового содержимого в рамках покупки (например, цифровой книги или журнала).
Встроенные продукты . Как и в примерах в этом документе, приобретенный продукт существует как функциональные возможности, предоставляемые приложением. Покупка в приложении позволяет пользователю получить доступ к функциям. Идентификаторы продуктов жестко закодируются.
Продукты , предоставляемые сервером— продукт состоит из скачиваемого содержимого, хранящегося на удаленном сервере до тех пор, пока не будет выполнена успешная транзакция, при этом содержимое будет загружено. Примеры могут включать книги или журналы. Идентификаторы продуктов обычно создаются с внешнего сервера (где содержимое продукта также размещено). Приложения должны реализовать надежный способ записи при завершении транзакции, чтобы, если загрузка содержимого завершается сбоем, она может быть повторно предпринята, не запутав пользователя.
Продукты, предоставляемые сервером
Содержимое некоторых продуктов, таких как книги и журналы (или даже игровой уровень), необходимо скачать с удаленного сервера во время покупки. Это означает, что для хранения и доставки содержимого продукта после его приобретения требуется дополнительный сервер.
Получение цен на продукты, предоставляемые сервером
Так как продукты доставляются удаленно, с течением времени можно добавлять больше продуктов (без обновления кода приложения), таких как добавление дополнительных книг или новых вопросов журнала. Таким образом, приложение может обнаруживать эти новости и отображать их пользователю, дополнительный сервер должен хранить и доставлять эти сведения.
Сведения о продукте должны храниться в нескольких местах: на сервере и в Подключение iTunes. Кроме того, каждый продукт будет иметь файлы содержимого, связанные с ним. Эти файлы будут доставлены после успешной покупки.
Когда пользователь хочет приобрести продукт, приложение должно определить, какие продукты доступны. Эти сведения могут быть кэшированы, но должны быть доставлены с удаленного сервера, где хранится главный список продуктов.
Сервер возвращает список идентификаторов продуктов для анализа приложения.
Затем приложение определяет, какие из этих идентификаторов продуктов отправляются в StoreKit для получения цен и описаний.
StoreKit отправляет список идентификаторов продуктов на серверы Apple.
Серверы iTunes отвечают на допустимые сведения о продукте (описание и текущая цена).
Приложение
SKProductsRequestDelegate
передает сведения о продукте для отображения пользователю.
Приобретение продуктов, предоставляемых сервером
Так как удаленный сервер требует проверки допустимости запроса на содержимое (т. е. был оплачен), сведения о получении передаются вместе для проверки подлинности. Удаленный сервер перенаправит эти данные в iTunes для проверки и, если это успешно, включает содержимое продукта в ответ на приложение.
Приложение добавляет в
SKPayment
очередь. Если требуется, пользователь получит запрос на получение идентификатора Apple ID и попросите подтвердить оплату.StoreKit отправляет запрос серверу для обработки.
По завершении транзакции сервер отвечает с получением транзакции.
Подкласс
SKPaymentTransactionObserver
получает квитанцию и обрабатывает его. Так как продукт должен быть скачан с сервера, приложение инициирует сетевой запрос к удаленному серверу.Запрос на скачивание сопровождается данными квитанции, чтобы удаленный сервер смог проверить, что он авторизован для доступа к содержимому. Сетевой клиент приложения ожидает ответа на этот запрос.
Когда сервер получает запрос на содержимое, он анализирует данные квитанции и отправляет запрос непосредственно на серверы iTunes, чтобы убедиться, что квитанция является допустимой транзакцией. Сервер должен использовать некоторую логику, чтобы определить, следует ли отправлять запрос в рабочую или песочницу URL-адрес. Apple предлагает всегда использовать рабочий URL-адрес и переключиться на песочницу, если состояние получения 21007 (квитанция песочницы, отправленная на рабочий сервер). Дополнительные сведения см. в руководстве по программированию проверки квитанций Apple.
iTunes проверка квитанцию и возвратит состояние нуля, если оно допустимо.
Сервер ожидает ответа iTunes. Если он получает допустимый ответ, код должен найти связанный файл содержимого продукта, чтобы включить в ответ на приложение.
Приложение получает и анализирует ответ, сохраняя содержимое продукта в файловой системе устройства.
Приложение включает продукт, а затем вызывает StoreKit
FinishTransaction
. Затем приложение может отобразить приобретенное содержимое (например, отобразить первую страницу приобретенной книги или журнала).
Альтернативная реализация для очень больших файлов содержимого продукта может включать простое хранение квитанции транзакции на шаге 9, чтобы транзакция могла быть быстро завершена, и предоставить пользовательский интерфейс для пользователя, чтобы скачать фактическое содержимое продукта в некоторое время. Последующий запрос на скачивание может повторно отправить хранимую квитанцию, чтобы получить доступ к требуемому файлу содержимого продукта.
Написание кода проверки квитанций на стороне сервера
Проверка квитанции на стороне сервера может выполняться с помощью простого HTTP-запроса POST/ответа, охватывающего шаги 5–8 на схеме рабочего процесса.
SKPaymentTansaction.TransactionReceipt
Извлеките свойство в приложении. Это данные, которые необходимо отправить в iTunes для проверки (шаг 5).
В кодировке Base64 данные о получении транзакций (на шаге 5 или #6).
Создайте простую полезные данные JSON следующим образом:
{
"receipt-data" : "(base-64 encoded receipt here)"
}
HTTP POST JSON для https://buy.itunes.apple.com/verifyReceipt рабочей среды или https://sandbox.itunes.apple.com/verifyReceipt тестирования.
Ответ JSON будет содержать следующие ключи:
{
"status" : 0,
"receipt" : { (receipt repeated here) }
}
Состояние нуля указывает на действительную квитанцию. Сервер может продолжить выполнение содержимого приобретенного продукта. Ключ квитанции содержит словарь JSON с теми же свойствами, что SKPaymentTransaction
и объект, полученный приложением, поэтому код сервера может запрашивать этот словарь для получения таких сведений, как product_id и количество покупки.
Дополнительные сведения см. в документации по программированию проверки квитанций Apple.