Обработка ошибок в Capacitor SDK

Каждая ошибка, возвращаемая SDK, является экземпляром AdaptyError. Пример:

Включите подробные логи перед отладкой. Большинство AdaptyError оборачивают исходную ошибку StoreKit, Play Billing, сети или бэкенда. При включённых подробных логах (adapty.setLogLevel({ logLevel: 'verbose' }) — см. Логирование) обёрнутая ошибка выводится в консоль, что обычно сразу указывает на реальную причину. Свойство detail у AdaptyError заполняется вне зависимости от уровня логирования — подробные логи просто выводят его в консоль.


try {
  const result = await adapty.makePurchase({ product });
  
  // Обработка результата покупки
  if (result.type === 'success') {
    console.log('Покупка успешна:', result.profile);
  } else if (result.type === 'user_cancelled') {
    console.log('Пользователь отменил покупку');
  } else if (result.type === 'pending') {
    console.log('Покупка ожидает подтверждения');
  }
} catch (error) {
  if (error instanceof AdaptyError) {
    console.error('Ошибка Adapty:', error.adaptyCode, error.localizedDescription);
    
    // Обработка конкретных кодов ошибок
    switch (error.adaptyCode) {
      case ErrorCodeName.cantMakePayments:
        console.log('Встроенные покупки недоступны на этом устройстве');
        break;
      case ErrorCodeName.notActivated:
        console.log('SDK Adapty не активирован');
        break;
      case ErrorCodeName.productPurchaseFailed:
        console.log('Покупка не удалась:', error.detail);
        break;
      default:
        console.log('Произошла другая ошибка:', error.detail);
    }
  } else {
    console.error('Ошибка не связана с Adapty:', error);
  }
}

Свойства ошибки

Класс AdaptyError предоставляет следующие свойства:

СвойствоТипОписание
adaptyCodenumberЧисловой код ошибки (например, 1003 для cantMakePayments)
localizedDescriptionstringПонятное пользователю сообщение об ошибке
detailstring | undefinedДополнительная информация об ошибке (необязательно)
messagestringПолное сообщение об ошибке с кодом и описанием

Коды ошибок

SDK экспортирует константы и утилиты для работы с кодами ошибок:

Константа ErrorCodeName

Сопоставляет строковые идентификаторы с числовыми кодами:


ErrorCodeName.cantMakePayments // 1003
ErrorCodeName.notActivated // 2002
ErrorCodeName.networkFailed // 2005

Константа ErrorCode

Сопоставляет числовые коды со строковыми идентификаторами:


ErrorCode[1003] // 'cantMakePayments'
ErrorCode[2002] // 'notActivated'
ErrorCode[2005] // 'networkFailed'

Вспомогательные функции


// Get numeric code from string name:
getErrorCode('cantMakePayments') // 1003

// Get string name from numeric code:
getErrorPrompt(1003) // 'cantMakePayments'

Сравнение кодов ошибок

Важно: error.adaptyCode — это число, поэтому сравнивайте его напрямую с числовыми кодами:

// Option 1: Use ErrorCodeName constant (recommended) ✅
if (error.adaptyCode === ErrorCodeName.cantMakePayments) {
  console.log('Cannot make payments');
}

// Option 2: Compare with numeric literal ✅
if (error.adaptyCode === 1003) {
  console.log('Cannot make payments');
}

// NOT like this ❌ - compares number to string and will never match
if (error.adaptyCode === ErrorCode[1003]) {
}

Глобальный обработчик ошибок

Вы можете настроить глобальный обработчик ошибок для перехвата всех ошибок Adapty:


// Set up global error handler
AdaptyError.onError = (error: AdaptyError) => {
  console.error('Global Adapty error:', {
    code: error.adaptyCode,
    message: error.localizedDescription,
    detail: error.detail
  });
  
  // Handle specific error types globally
  if (error.adaptyCode === ErrorCodeName.notActivated) {
    // SDK not activated - maybe retry activation
    console.log('SDK not activated, attempting to reactivate...');
  }
};

Типовые паттерны обработки ошибок

Обработка ошибок при покупке


async function handlePurchase(product: AdaptyPaywallProduct) {
  try {
    const result = await adapty.makePurchase({ product });
    
    if (result.type === 'success') {
      console.log('Покупка выполнена успешно:', result.profile);
    } else if (result.type === 'user_cancelled') {
      console.log('Пользователь отменил покупку');
    } else if (result.type === 'pending') {
      console.log('Покупка ожидает подтверждения');
    }
  } catch (error) {
    if (error instanceof AdaptyError) {
      switch (error.adaptyCode) {
        case ErrorCodeName.cantMakePayments:
          console.log('Встроенные покупки не разрешены');
          break;
        case ErrorCodeName.productPurchaseFailed:
          console.log('Покупка не выполнена:', error.detail);
          break;
        default:
          console.error('Ошибка покупки:', error.localizedDescription);
      }
    }
  }
}

Обработка сетевых ошибок


async function fetchPaywall(placementId: string) {
  try {
    const paywall = await adapty.getPaywall({ placementId });
    return paywall;
  } catch (error) {
    if (error instanceof AdaptyError) {
      switch (error.adaptyCode) {
        case ErrorCodeName.networkFailed:
          console.log('Network error, retrying...');
          // Implement retry logic
          break;
        case ErrorCodeName.serverError:
          console.log('Server error:', error.detail);
          break;
        case ErrorCodeName.notActivated:
          console.log('SDK not activated');
          break;
        default:
          console.error('Paywall fetch error:', error.localizedDescription);
      }
    }
    throw error;
  }
}

Системные коды StoreKit

ОшибкаКодОписание
unknown0Неизвестная или непредвиденная ошибка.
clientInvalid1Клиенту не разрешено выполнять запрошенное действие.
paymentCancelled2

Пользователь отменил запрос на оплату.

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

paymentInvalid3Один из параметров платежа не был распознан стором.
paymentNotAllowed4

Пользователю не разрешено авторизовывать платежи. Возможные причины:

- Платежи не поддерживаются в стране пользователя.

- Пользователь является несовершеннолетним.

storeProductNotAvailable5Запрошенный продукт отсутствует в App Store. Убедитесь, что продукт доступен для нужной страны.
cloudServicePermissionDenied6Пользователь не разрешил доступ к информации облачного сервиса.
cloudServiceNetworkConnectionFailed7Устройству не удалось подключиться к сети.
cloudServiceRevoked8Пользователь отозвал разрешение на использование облачного сервиса.
privacyAcknowledgementRequired9Пользователь ещё не ознакомился с политикой конфиденциальности стора.
unauthorizedRequestData10Запрос сформирован некорректно.
invalidOfferIdentifier11

Идентификатор офера недействителен. Возможные причины:

- Офер с таким идентификатором не настроен в App Store.

- Офер был отозван.

- Идентификатор офера указан с опечаткой.

invalidSignature12Подпись в платёжной скидке недействительна. Убедитесь, что заполнено поле In-app purchase Key ID и загружен файл In-App Purchase Private Key. Подробнее — в разделе Настройка интеграции с App Store.
missingOfferParams13

Проблема с интеграцией Adapty или с оферами.

Подробнее — в разделах Настройка интеграции с App Store и Оферы.

invalidOfferPrice14Указанная в сторе цена больше не действительна. Оферы всегда должны предоставлять скидку относительно обычной цены.

Пользовательские коды Android

ОшибкаКодОписание
adaptyNotInitialized20Необходимо правильно настроить SDK Adapty с помощью метода Adapty.activate. Узнайте, как это сделать для React Native.
productNotFound22Запрошенный для покупки продукт недоступен в сторе.
invalidJson23JSON пейвола недействителен. Исправьте его в дашборде Adapty. Подробнее — в разделе Настройка пейвола с помощью Remote Config.
currentSubscriptionToUpdateNotFoundInHistory24Исходная подписка, которую необходимо обновить, не найдена.
pendingPurchase25Покупка находится в статусе ожидания, а не завершена. Подробнее — на странице Обработка отложенных транзакций в документации Android Developer.
billingServiceTimeout97Запрос превысил максимальное время ожидания до получения ответа от Google Play. Причиной может быть, например, задержка при выполнении действия, запрошенного вызовом Play Billing Library.
featureNotSupported98Запрошенная функция не поддерживается Play Store на текущем устройстве.
billingServiceDisconnected99Критическая ошибка: соединение клиентского приложения с сервисом Google Play Store через BillingClient разорвано.
billingServiceUnavailable102Временная ошибка: сервис Google Play Billing сейчас недоступен. В большинстве случаев это означает проблему с сетевым подключением между клиентским устройством и сервисами Google Play Billing.
billingUnavailable103

Ошибка выставления счёта пользователю в процессе покупки. Примеры ситуаций, в которых это может произойти:

1. Приложение Play Store на устройстве пользователя устарело.

2. Пользователь находится в неподдерживаемой стране.

3. Пользователь является корпоративным, и администратор отключил для него возможность совершать покупки.

4. Google Play не может списать средства с платёжного метода пользователя. Например, срок действия кредитной карты истёк.

5. Пользователь не авторизован в приложении Play Store.

developerError105Критическая ошибка: некорректное использование API.
billingError106Критическая ошибка: внутренняя проблема самого Google Play.
itemAlreadyOwned107Расходуемая покупка уже была приобретена.
itemNotOwned108Запрошенное действие с элементом завершилось неудачей, так как он не принадлежит пользователю.

Пользовательские коды StoreKit

ОшибкаКодОписание
noProductIDsFound1000

Ни один из продуктов пейвола не доступен в сторе.

Если вы столкнулись с этой ошибкой, выполните следующие шаги для её устранения:

1. Убедитесь, что все продукты добавлены в дашборд Adapty.

2. Проверьте, что Bundle ID приложения совпадает с указанным в Apple Connect.

3. Убедитесь, что идентификаторы продуктов из стора совпадают с теми, что добавлены в дашборд. Обратите внимание: идентификаторы не должны содержать Bundle ID, если только он уже не включён в идентификатор в сторе.

4. Убедитесь, что статус оплаты приложения активен в налоговых настройках Apple. Проверьте актуальность налоговой информации и действительность сертификатов.

5. Проверьте, привязан ли к приложению банковский счёт — это необходимо для монетизации.

6. Проверьте доступность продуктов во всех регионах. Убедитесь, что продукты находятся в статусе “Ready to Submit”.

productRequestFailed1002

Не удаётся получить доступные продукты в данный момент. Возможная причина:

- Кэш ещё не создан, и одновременно отсутствует подключение к интернету.

cantMakePayments1003Встроенные покупки не разрешены на этом устройстве.
noPurchasesToRestore1004Google Play не нашёл покупку для восстановления.
cantReadReceipt1005

На устройстве нет действительного чека. Это может быть проблемой при тестировании в песочнице.

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

productPurchaseFailed1006Не удалось выполнить покупку продукта. Эта ошибка оборачивает базовую ошибку StoreKit — прочитайте вложенную ошибку (или включите подробные логи для просмотра в консоли), чтобы узнать реальную причину. Вложенная ошибка, как правило, соответствует одному из кодов StoreKit 0–14 из таблицы выше — чаще всего paymentCancelled, paymentInvalid, paymentNotAllowed или invalidOfferPrice. Если определить конкретную причину не удаётся, попробуйте создать новый профиль песочницы; если проблема сохраняется, обратитесь в поддержку Apple.
refreshReceiptFailed1010Чек не был получен. Применимо только к StoreKit 1.
receiveRestoredTransactionsFailed1011Не удалось восстановить покупки.

Пользовательские сетевые коды

ОшибкаКодОписание
notActivated2002Необходимо правильно настроить SDK Adapty с помощью метода Adapty.activate. Узнайте, как это сделать для React Native.
badRequest2003Некорректный запрос.
serverError2004Ошибка сервера.
networkFailed2005Сетевой запрос не выполнен.
decodingFailed2006Ошибка декодирования ответа.
encodingFailed2009Ошибка кодирования запроса.
analyticsDisabled3000Невозможно обработать аналитические события, так как вы отключили их сбор. Подробнее — в разделе Интеграция аналитики.
wrongParam3001Один или несколько параметров некорректны: пустые там, где это недопустимо, или имеют неверный тип.
activateOnceError3005Метод .activate нельзя вызывать более одного раза.
profileWasChanged3006Профиль пользователя был изменён во время операции.
fetchTimeoutError3101Пейвол не удалось загрузить в установленный срок. Чтобы избежать этой ситуации, настройте локальные резервные пейволы.
operationInterrupted9000Операция была прервана системой.