Обработка ошибок в iOS SDK
В Adapty SDK есть собственная обёртка для всех типов ошибок — AdaptyError. По сути, каждая ошибка, возвращаемая SDK, является AdaptyError. У неё есть два полезных свойства: originalError и adaptyErrorCode, описанные ниже.
originalError содержит исходную ошибку на случай, если она вам нужна для работы. Это может быть SKError, NSError или обычная Swift Error. Свойство опциональное — некоторые ошибки генерируются напрямую SDK (например, при несогласованных или отсутствующих данных) и не имеют исходной ошибки, вокруг которой изначально строился враппер.
adaptyErrorCode используется для обработки типичных проблем, например:
- недействительные учётные данные
- сетевые ошибки
- отменённые платежи
- проблемы с выставлением счёта
- недействительный чек
- и многое другое
Проверить ошибку на конкретный код и отреагировать соответствующим образом очень просто.
do {
let info = try await Adapty.makePurchase(product: product)
} catch {
if error.adaptyErrorCode == .paymentCancelled {
// purchase was cancelled
// you can offer discount to your user or remind them later
}
}
Включите подробные логи перед отладкой. Большинство AdaptyError оборачивают ошибку StoreKit, сети или бэкенда. Если включить подробные логи (Adapty.logLevel = .verbose — см. Логирование), эта вложенная ошибка выводится в консоль, и обычно сразу становится ясна реальная причина. Свойство originalError заполняется в любом случае — подробные логи просто делают её видимой в консоли.
Если эти решения не помогли, перейдите в раздел Другие проблемы — там описаны шаги, которые стоит выполнить перед обращением в поддержку, чтобы мы могли помочь вам быстрее.
Ошибки StoreKit
| Ошибка | Код | Решение |
|---|---|---|
| unknown | 0 | Код ошибки, указывающий на неизвестную или непредвиденную ошибку. Повторите попытку или обратитесь к разделу Другие проблемы. |
| clientInvalid | 1 | Этот код ошибки означает, что клиенту не разрешено выполнять запрошенное действие. |
| paymentCancelled | 2 | Этот код ошибки означает, что пользователь отменил запрос на оплату. Никаких действий не требуется, однако с точки зрения бизнес-логики вы можете предложить пользователю скидку или напомнить о покупке позже. |
| paymentInvalid | 3 | Эта ошибка означает, что один из параметров платежа не был распознан App Store. |
| paymentNotAllowed | 4 | Этот код ошибки означает, что пользователю не разрешено авторизовывать платежи. |
| storeProductNotAvailable | 5 | Этот код ошибки означает, что запрошенный продукт недоступен в сторе. Попробуйте переустановить приложение. |
| cloudServicePermissionDenied | 6 | Этот код ошибки означает, что пользователь не разрешил доступ к информации облачного сервиса. |
| cloudServiceNetworkConnectionFailed | 7 | Этот код ошибки означает, что устройству не удалось подключиться к сети. |
| cloudServiceRevoked | 8 | Этот код ошибки означает, что пользователь отозвал разрешение на использование этого облачного сервиса. |
| privacyAcknowledgementRequired | 9 | Этот код ошибки означает, что пользователь ещё не принял политику конфиденциальности Apple. |
| unauthorizedRequestData | 10 | Этот код ошибки означает, что приложение пытается использовать свойство, для которого у него нет необходимого entitlement. |
| invalidOfferIdentifier | 11 | Идентификатор предложения недействителен. Например, вы не настроили предложение с таким идентификатором в App Store, или предложение было отозвано. Убедитесь, что нужные предложения настроены в AppStore Connect, и передайте корректный идентификатор предложения. |
| invalidSignature | 12 | Этот код ошибки означает, что подпись в скидке на оплату недействительна. |
| missingOfferParams | 13 | Этот код ошибки означает, что в скидке на оплату отсутствуют параметры. |
| invalidOfferPrice | 14 | Этот код ошибки означает, что цена, указанная вами в App Store Connect, больше не является действительной. Предложения всегда должны представлять собой скидку от обычной цены. |
| noProductIDsFound | 1000 | Эта ошибка означает, что ни один из продуктов, запрошенных на пейволе, недоступен для покупки в App Store, несмотря на то что они там перечислены. Иногда ошибка сопровождается предупреждением Если вы сталкиваетесь с этой ошибкой, следуйте инструкциям в разделе Fix for Code-1000 |
| productRequestFailed | 1002 | В данный момент не удалось получить список доступных продуктов. |
| cantMakePayments | 1003 | Встроенные покупки не разрешены на этом устройстве. См. гайд по устранению неполадок. |
| cantReadReceipt | 1005 | На устройстве нет действительного чека. Это может быть проблемой при тестировании в песочнице. В песочнице у вас не будет действительного файла чека, пока вы не совершите хотя бы одну покупку — убедитесь, что сделали это перед обращением к нему. При тестировании в песочнице также убедитесь, что на устройстве выполнен вход с действительным аккаунтом Apple sandbox. |
| productPurchaseFailed | 1006 | Покупка продукта завершилась ошибкой. Это обёртка над базовой ошибкой StoreKit — прочитайте originalError (или включите подробные логи, чтобы увидеть её в консоли) для выяснения реальной причины. Обёрнутая ошибка, как правило, соответствует одному из кодов StoreKit 0–14 в таблице выше — чаще всего paymentCancelled, paymentInvalid, paymentNotAllowed или invalidOfferPrice. Если не удаётся определить конкретную причину, попробуйте создать новый профиль песочницы; если проблема сохраняется, обратитесь в поддержку Apple. |
| refreshReceiptFailed | 1010 | Операция обновления чека завершилась ошибкой. |
| fetchSubscriptionStatusFailed | 1020 | Не удалось получить статус подписки из App Store. |
| unknownTransactionId | 1030 | Идентификатор транзакции неизвестен. |
| paymentPendingError | 1050 | Платёж в данный момент ожидает обработки. |
Сетевые ошибки
| Ошибка | Код | Решение |
|---|---|---|
| notActivated | 2002 | SDK Adapty не активирован. Чаще всего возникает, когда сплэш-экран или ранний UI-хук вызывает методы Adapty до завершения Adapty.activate. Симптом непостоянен и может не воспроизводиться на симуляторе из-за различий в тайминге на реальном устройстве. Дождитесь завершения обработчика или асинхронного результата activate перед любыми другими вызовами SDK. Полная последовательность описана в порядке вызовов в iOS SDK. |
| badRequest | 2003 | Некорректный запрос. Убедитесь, что вы выполнили все шаги, необходимые для интеграции с App Store. |
| serverError | 2004 | Ошибка сервера. Повторите попытку через некоторое время. Если проблема не устранена, обратитесь в службу поддержки Adapty. |
| networkFailed | 2005 | Ошибка указывает на проблемы с сетевым подключением на устройстве пользователя. Попробуйте отключить VPN или переключиться с мобильной сети на Wi-Fi или наоборот. |
| decodingFailed | 2006 | Ошибка указывает на сбой при декодировании ответа. Проверьте свой код и убедитесь, что отправляемые параметры корректны. Например, ошибка может означать, что используется недействительный API-ключ. |
| encodingFailed | 2009 | Ошибка указывает на сбой при кодировании запроса. |
Общие ошибки
| Ошибка | Код | Решение |
|---|---|---|
| analyticsDisabled | 3000 | Невозможно обработать события аналитики, так как вы отключили её для этого пользователя. |
| wrongParam | 3001 | Ошибка указывает на то, что один или несколько параметров заданы неверно. Если вы используете Paywall Builder и пейвол не отображается из-за этой ошибки, включите Show on device в Paywall Builder. Другая возможная причина — версия локального файла резервного пейвола не совпадает с версией SDK. Скачайте актуальный файл в дашборде. |
| activateOnceError | 3005 | Метод .activate нельзя вызывать более одного раза. |
| profileWasChanged | 3006 | Профиль пользователя изменился в ходе операции. Это происходит, когда метод вызывается во время выполнения Adapty.identify — вызов попадает на профиль, который вот-вот будет заменён, и SDK отклоняет его. Всегда используйте await для identify (или его completion handler), прежде чем делать любые вызовы, связанные с действиями пользователя. Подробнее: Порядок вызовов в iOS SDK. |
| unsupportedData | 3007 | Ошибка указывает на то, что формат данных не поддерживается SDK. |
| unidentifiedUserLogout | 3020 | Метод logout нельзя вызвать для неидентифицированного пользователя. |
| fetchTimeoutError | 3101 | Ошибка указывает на то, что операция получения данных завершилась по таймауту. |
| operationInterrupted | 9000 | Операция была прервана системой. |
Другие проблемы
Если вы ещё не нашли решение, попробуйте следующее:
- Обновите SDK до последней версии: мы всегда рекомендуем использовать актуальные версии SDK — они более стабильны и содержат исправления известных проблем.
- Обратитесь в службу поддержки или получите помощь от других разработчиков на форуме поддержки.
- Напишите в поддержку на [email protected] или в чат: если вы не готовы обновлять SDK или обновление не помогло, свяжитесь с нашей командой поддержки. Обратите внимание: проблема решится быстрее, если вы включите подробное логирование и поделитесь логами с командой. Также можно прикрепить соответствующие фрагменты кода.