Обработка ошибок в 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 не активирован. Чаще всего возникает, когда splash-экран или ранний UI-хук вызывает методы Adapty до завершения Adapty.activate. Симптом нестабильный и может не воспроизводиться на симуляторе, поскольку тайминги на реальном устройстве отличаются. Дождитесь завершения activate через completion handler или async-результат, прежде чем делать любые другие вызовы SDK. Полная последовательность описана в Порядок вызовов в iOS SDK. |
| badRequest | 2003 | Некорректный запрос. При вызове getPaywall это чаще всего означает, что запрошенный плейсмент не существует в приложении, которому принадлежит ваш API-ключ. Убедитесь, что ID плейсмента скопирован точно и что API-ключ и плейсмент относятся к одному приложению в дашборде Adapty. |
| serverError | 2004 | Ошибка сервера. Повторите попытку через некоторое время. Если проблема не исчезает, обратитесь в службу поддержки Adapty. Этот код также покрывает троттлинг: если вы слишком часто обращаетесь к одному и тому же эндпоинту (например, часто обновляете профиль), сервер отвечает кодом 429, и SDK блокирует этот эндпоинт до истечения интервала повтора. |
| networkFailed | 2005 | Ошибка указывает на проблемы с сетевым подключением на устройстве пользователя. Попробуйте отключить VPN или переключиться с мобильной сети на Wi-Fi или наоборот. |
| decodingFailed | 2006 | Ошибка указывает на сбой декодирования ответа — SDK получил данные, которые не может разобрать. Если она возникает при загрузке локального файла резервного пейвола, файл устарел относительно ожиданий SDK: скачайте свежий файл со страницы Placements. Несовпадение версий резервного пейвола также может проявляться как ошибка 3001. |
| encodingFailed | 2009 | Ошибка указывает на сбой кодирования запроса. |
Общие ошибки
| Ошибка | Код | Решение |
|---|---|---|
| analyticsDisabled | 3000 | Обработка аналитических событий невозможна, так как вы отключили её. |
| wrongParam | 3001 | Ошибка указывает на некорректные параметры. Если вы используете старый Paywall Builder и не можете отобразить пейвол из-за этой ошибки, включите Show on device в настройках билдера. Другая возможная причина — версия локального файла резервного пейвола не совпадает с версией SDK. Скачайте новый файл в дашборде. |
| activateOnceError | 3005 | Метод .activate нельзя вызывать более одного раза. |
| profileWasChanged | 3006 | Профиль пользователя был изменён во время операции. Это происходит, когда метод вызывается во время выполнения Adapty.identify — вызов попадает на профиль, который вот-вот будет заменён, и SDK отклоняет его. Всегда дожидайтесь завершения identify (через await или обработчик завершения) перед любым пользовательским вызовом. См. Порядок вызовов в iOS SDK. |
| unsupportedData | 3007 | Ошибка указывает на то, что формат данных не поддерживается SDK. |
| unidentifiedUserLogout | 3020 | Вызов метода logout для неидентифицированного пользователя невозможен. |
| fetchTimeoutError | 3101 | Ошибка указывает на истечение времени ожидания операции fetch. |
| operationInProgress | 3201 | Другая операция того же типа ещё выполняется. Возвращается методом showStoreMessages, если предыдущий вызов всё ещё показывает сообщения App Store. Дождитесь завершения и попробуйте снова. |
| resolverFailure | 3202 | SDK не удалось найти ресурс, необходимый для операции. Возвращается методом showStoreMessages из UIKit, если вы не передали window scene и нет активной сцены переднего плана. Передайте сцену явно или вызовите метод повторно, когда приложение будет на переднем плане. |
| operationInterrupted | 9000 | Операция была прервана системой. |
Медленная загрузка сразу после updateProfile
Если вы задаёте пользовательские атрибуты через updateProfile и запрашиваете плейсмент в той же сессии, SDK может вычислить хеш сегмента для плейсмента на основе атрибутов, которые ещё не успели примениться. SDK повторяет запрос после обновления хеша сегмента, поэтому симптом проявляется как замедленная загрузка, а не ошибка. Загрузка завершается неудачей только в том случае, если после повторной попытки расхождение сохраняется — это означает, что запись атрибута не прошла.
Чтобы избежать повторного запроса, дождитесь завершения updateProfile перед загрузкой плейсмента. Подробнее — в разделе Порядок вызовов в iOS SDK.
Другие проблемы
Если вы ещё не нашли решение, попробуйте следующее:
- Обновите SDK до последней версии: мы всегда рекомендуем использовать актуальные версии SDK — они более стабильны и содержат исправления известных проблем.
- Обратитесь в службу поддержки или получите помощь от других разработчиков на форуме поддержки.
- Напишите в поддержку на support@adapty.io или в чат: если вы не готовы обновлять SDK или обновление не помогло, свяжитесь с нашей командой поддержки. Обратите внимание: проблема решится быстрее, если вы включите подробное логирование и поделитесь логами с командой. Также можно прикрепить соответствующие фрагменты кода.