Обработка ошибок в 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 предоставляет следующие свойства:
| Свойство | Тип | Описание |
|---|---|---|
adaptyCode | number | Числовой код ошибки (например, 1003 для cantMakePayments) |
localizedDescription | string | Понятное пользователю сообщение об ошибке |
detail | string | undefined | Дополнительная информация об ошибке (необязательно) |
message | string | Полное сообщение об ошибке с кодом и описанием |
Коды ошибок
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('Purchase successful:', result.profile);
} else if (result.type === 'user_cancelled') {
console.log('User cancelled the purchase');
} else if (result.type === 'pending') {
console.log('Purchase is pending');
}
} catch (error) {
if (error instanceof AdaptyError) {
switch (error.adaptyCode) {
case ErrorCodeName.cantMakePayments:
console.log('In-app purchases not allowed');
break;
case ErrorCodeName.productPurchaseFailed:
console.log('Purchase failed:', error.detail);
break;
default:
console.error('Purchase error:', error.localizedDescription);
}
}
}
}
Обработка сетевых ошибок
async function fetchFlow(placementId: string) {
try {
const flow = await adapty.getFlow({ placementId });
return flow;
} 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
| Ошибка | Код | Описание |
|---|---|---|
| unknown | 0 | Неизвестная или непредвиденная ошибка. |
| clientInvalid | 1 | Клиенту не разрешено выполнять это действие. |
| paymentCancelled | 2 | Пользователь отменил платёж. Никаких действий не требуется, но с точки зрения бизнес-логики вы можете предложить скидку или напомнить о покупке позже. |
| paymentInvalid | 3 | Один из параметров платежа не был распознан стором. |
| paymentNotAllowed | 4 | Пользователю не разрешено проводить платежи. Возможные причины: - Платежи не поддерживаются в стране пользователя. - Пользователь является несовершеннолетним. |
| storeProductNotAvailable | 5 | Запрошенный продукт отсутствует в App Store. Убедитесь, что продукт доступен для используемой страны. |
| cloudServicePermissionDenied | 6 | Пользователь не предоставил доступ к информации облачного сервиса. |
| cloudServiceNetworkConnectionFailed | 7 | Устройству не удалось подключиться к сети. |
| cloudServiceRevoked | 8 | Пользователь отозвал разрешение на использование этого облачного сервиса. |
| privacyAcknowledgementRequired | 9 | Пользователь ещё не принял политику конфиденциальности стора. |
| unauthorizedRequestData | 10 | Запрос сформирован некорректно. |
| invalidOfferIdentifier | 11 | Идентификатор оффера недействителен. Возможные причины: - В App Store не настроен оффер с таким идентификатором. - Оффер был отозван. - Идентификатор оффера указан с опечаткой. |
| invalidSignature | 12 | Подпись в платёжной скидке недействительна. Убедитесь, что вы заполнили поле In-app purchase Key ID и загрузили файл In-App Purchase Private Key. Подробнее — в разделе Configure App Store integration. |
| missingOfferParams | 13 | Проблемы с интеграцией Adapty или с офферами. Подробнее о настройке — в разделах Configure App Store integration и Offers. |
| invalidOfferPrice | 14 | Указанная в сторе цена больше не действительна. Офферы всегда должны представлять сниженную цену. |
Пользовательские коды Android
| Ошибка | Код | Описание |
|---|---|---|
| adaptyNotInitialized | 20 | Необходимо правильно настроить Adapty SDK с помощью метода activate. Подробнее — в разделе Install & configure Adapty SDK. |
| productNotFound | 22 | Запрошенный для покупки продукт недоступен в сторе. |
| currentSubscriptionToUpdateNotFoundInHistory | 24 | Исходная подписка, которую необходимо продлить, не найдена. |
| billingServiceTimeout | 97 | Запрос достиг максимального таймаута до получения ответа от Google Play. Это может быть вызвано, например, задержкой при выполнении действия, запрошенного вызовом Play Billing Library. |
| featureNotSupported | 98 | Запрошенная функция не поддерживается Play Store на данном устройстве. |
| billingServiceDisconnected | 99 | Критическая ошибка: соединение клиентского приложения со службой Google Play Store через BillingClient было разорвано. |
| billingServiceUnavailable | 102 | Временная ошибка: служба Google Play Billing в данный момент недоступна. В большинстве случаев это означает проблему с сетевым подключением между устройством и серверами Google Play Billing. |
| billingUnavailable | 103 | Ошибка выставления счёта пользователя в процессе покупки. Примеры случаев, когда это может произойти: 1. Приложение Play Store на устройстве пользователя устарело. 2. Пользователь находится в неподдерживаемой стране. 3. Пользователь является корпоративным и администратор запретил совершение покупок. 4. Google Play не может списать средства с платёжного метода пользователя. Например, срок действия кредитной карты истёк. 5. Пользователь не вошёл в приложение Play Store. |
| developerError | 105 | Критическая ошибка: неправильное использование API. |
| billingError | 106 | Критическая ошибка: внутренняя проблема в самом Google Play. |
| itemAlreadyOwned | 107 | Расходуемая покупка уже была приобретена. |
| itemNotOwned | 108 | Запрошенное действие над элементом не удалось выполнить. |
| billingNetworkError | 112 | Проблема с сетевым соединением между устройством и системами Play. |
Пользовательские коды StoreKit
| Ошибка | Код | Описание |
|---|---|---|
| noProductIDsFound | 1000 | Ни один из продуктов пейвола недоступен в сторе. Если вы столкнулись с этой ошибкой, выполните следующие шаги для её устранения: 1. Убедитесь, что все продукты добавлены в дашборд Adapty. 2. Убедитесь, что Bundle ID приложения совпадает с указанным в Apple Connect. 3. Проверьте, что идентификаторы продуктов из сторов совпадают с добавленными в дашборде. Обратите внимание, что идентификаторы не должны содержать Bundle ID, если только он уже не включён в сторе. 4. Убедитесь, что статус платного приложения активен в налоговых настройках Apple. Проверьте актуальность налоговой информации и действительность сертификатов. 5. Убедитесь, что к приложению привязан банковский счёт, позволяющий монетизировать его. 6. Убедитесь, что продукты доступны во всех регионах. Также проверьте, что продукты находятся в состоянии “Ready to Submit”. |
| productRequestFailed | 1002 | Не удалось загрузить доступные продукты. Возможная причина: - Кэш ещё не был создан и одновременно отсутствует подключение к интернету. |
| cantMakePayments | 1003 | Встроенные покупки не разрешены на этом устройстве. |
| noPurchasesToRestore | 1004 | Google Play не нашёл покупки для восстановления. |
| cantReadReceipt | 1005 | На устройстве нет действительного чека. Это может возникать при тестировании в песочнице. Никаких действий не требуется, но с точки зрения бизнес-логики вы можете предложить скидку или напомнить о покупке позже. |
| productPurchaseFailed | 1006 | Покупка продукта не удалась. Эта ошибка оборачивает базовую ошибку StoreKit — прочитайте обёрнутую ошибку (или включите подробные логи, чтобы увидеть её в консоли) для выяснения реальной причины. Обёрнутая ошибка, как правило, является одним из кодов StoreKit 0–14 в таблице выше — чаще всего paymentCancelled, paymentInvalid, paymentNotAllowed или invalidOfferPrice. Если не удаётся определить конкретную причину, попробуйте создать новый профиль песочницы; если ошибка воспроизводится, обратитесь в службу поддержки Apple. |
| refreshReceiptFailed | 1010 | Чек не был получен. Применимо только к StoreKit 1. |
| receiveRestoredTransactionsFailed | 1011 | Восстановление покупок не удалось. |
Пользовательские сетевые коды
| Ошибка | Код | Описание |
|---|---|---|
| notActivated | 2002 | Необходимо правильно настроить Adapty SDK с помощью метода activate. Подробнее — в разделе Install & configure Adapty SDK. |
| badRequest | 2003 | Некорректный запрос. |
| serverError | 2004 | Ошибка сервера. |
| networkFailed | 2005 | Сетевой запрос завершился с ошибкой. |
| decodingFailed | 2006 | Ошибка декодирования ответа. |
| encodingFailed | 2009 | Ошибка кодирования запроса. |
| analyticsDisabled | 3000 | Невозможно обработать аналитические события, так как вы отказались от их сбора. Подробнее — в разделе Analytics integration. |
| wrongParam | 3001 | Один или несколько параметров указаны некорректно: пустое значение там, где оно не допускается, неверный тип и т. д. |
| activateOnceError | 3005 | Метод .activate нельзя вызывать более одного раза. |
| profileWasChanged | 3006 | Профиль пользователя был изменён в процессе операции. |
| unsupportedData | 3007 | Формат данных не поддерживается SDK. |
| persistingDataError | 3100 | Ошибка при сохранении данных. |
| fetchTimeoutError | 3101 | Пейвол не удалось загрузить в отведённое время. Чтобы избежать этой ситуации, настройте локальные резервные пейволы. |
| operationInterrupted | 9000 | Операция была прервана системой. |