본문으로 건너뛰기

에러 핸들링

이 문서에서 다루는 에러는 API 호출 시 Promise가 reject되어 catch 같은 로직으로 잡을 수 있는 에러입니다.

API 호출에서 에러가 발생하는 시점의 동기화​

정보

현재 지원하는 플랫폼인 Android와 iOS는 에러가 발생하는 조건에 거의 차이가 없습니다.

예를 들어 카카오 네이티브 SDK의 me 함수는 Android와 iOS에서 유저 정보를 가져옵니다.

Kakao SDK는 내부적으로 콜백 방식을 사용합니다(이 패키지는 ReactiveX를 쓰지 않습니다).

대부분의 API 래퍼 함수는 다음 형태로 구현됩니다.

ios.swift
@objc public func me(
_ resolve: @escaping RCTPromiseResolveBlock,
reject: @escaping RCTPromiseRejectBlock
) {
onMain {
UserApi.shared.me { user, error in
if let error {
RNCKakaoUtil.reject(reject, error)
} else if let user {
resolve([
"id": user.id as Any
//...
])
} else {
RNCKakaoUtil.reject(reject, RNCKakaoError.responseNotFound(name: "user"))
}
}
}
}
android.kt
@ReactMethod
override fun me(promise: Promise) =
onMain {
UserApiClient.instance.me { user, error ->
if (error != null) {
promise.rejectWith(error)
} else if (user == null) {
promise.rejectWith(RNCKakaoResponseNotFoundException("user"))
} else {
promise.resolve(
argMap().apply {
putIntIfNotNull("id", user.id?.toInt())
// ...
},
)
}
}
}

Kakao SDK의 콜백 함수는 항상 첫 번째 인자로 결과값을, 두 번째 인자로 에러를 전달합니다.

에러가 null이 아니면 에러가 발생한 상태입니다.

이 패키지는 첫 번째 인자에 유효한 값이 있는지도 확인합니다.

노트

이 검사는 아마 의미 없는 동작(TILT)일 것입니다.

두 검사에서 모두 문제가 없으면 결과값을 반환합니다.

에러의 형태​

JavaScript의 catch에 전달되는 에러 객체는 플랫폼별로 조금 다릅니다.

카카오 네이티브 SDK는 플랫폼별 에러 코드를 사용하며 이 패키지는 모든 에러의 인터페이스를 통합하기보다 SDK가 반환한 유효한 값을 그대로 전달합니다.

대부분의 에러는 code로 구별할 수 있으며 대략 다음 구조로 전달됩니다.

이 패키지는 에러를 쉽게 처리할 수 있도록 유효한 값을 전달합니다.

  • Android
{
"message": "authentication tokens don't exist.",
"code": "TokenNotFound",
"nativeStackAndroid": [],
"userInfo": {
"isAppsFailed": false,
"isInvalidTokenError": false,
"isClientFailed": true,
"fatal": true,
"isAuthFailed": false,
"isApiFailed": false,
"nativeErrorMessage": "authentication tokens don't exist."
}
}
  • iOS
{
"code": "TokenNotFound",
"message": "authentication tokens not exist.",
"nativeStackIOS": [
"0 KakaoExample 0x000000010069dc9c RCTJSErrorFromCodeMessageAndNSError + 112",
"1 KakaoExample 0x00000001009a023c ___ZZN8facebook5react15ObjCTurboModule13createPromiseERNS_3jsi7RuntimeENSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEEU13block_pointerFvU13block_pointerFvP11objc_objectEU13block_pointerFvP8NSStringSH_P7NSErrorEEENK3$_0clES4_RKNS2_5ValueEPSQ_m_block_invoke.59 + 388",
"2 KakaoExample 0x00000001002c5e20 $sSo8NSStringCSgACSo7NSErrorCSgIeyByyy_SSSgAGs5Error_pSgIegggg_TR + 380",
// ...
],
"domain": "RNCKakaoErrorDomain",
"userInfo": {
"isAuthFailed": false,
"isInvalidTokenError": false,
"isAppsFailed": false,
"isClientFailed": true,
"isApiFailed": false,
"fatal": false,
"nativeErrorMessage": "The operation couldn’t be completed. (KakaoSDKCommon.SdkError error 0.)"
}
}

주요 필드는 code와 message이며 추가 정보는 userInfo에 포함됩니다.

경고

code는 카카오 네이티브 SDK의 열거형 케이스 이름을 그대로 사용하므로 플랫폼별로 케이스 이름이 다르게 정의되어 있으면 값이 다를 수 있습니다. 대부분은 동일합니다.

에러를 핸들링하는 예시​

사용 가능한 code 값은 Android와 iOS 공식 API 문서에서 확인할 수 있습니다.

다음 방법으로 대부분의 에러를 정확히 구별해 처리할 수 있습니다.

 selectSingleFriend({ mode: 'popup', options: {} })
.then((res) => showMessage({ message: formatJson(res) }))
.catch((e) => {
if (e && typeof e === 'object') {
if (e.code === 'TokenNotFound') {
showMessage({ type: 'warning', message: '토큰을 얻어오지 못했습니다' });
} else {
// ...
}
} else {
showMessage({ type: 'warning', message: '알 수 없는 에러입니다' });
}
})

패키지 에러 코드​

카카오 네이티브 SDK의 에러 외에 react-native-kakao 자체의 에러 code도 있습니다.

이 패키지의 에러 코드에는 항상 Package- 접두사가 붙습니다.

패키지 에러 코드는 다음과 같습니다.

  • Package-Unknown: 알 수 없는 프로그래밍 에러, Activity나 ViewController 표시 실패, URL 열기 실패 등 분류되지 않은 모든 에러입니다. 자세한 정보는 message에서 확인할 수 있습니다.
  • Package-APIResponseNotFound: 카카오 네이티브 SDK의 API 콜백에서 error가 없는데도 결과값이 반환되지 않은 경우입니다.
  • Package-SDKNotInitialized: SDK를 초기화하지 않고 Kakao API를 사용하려 할 때 발생합니다. 모든 API가 이 에러를 반환하는 것은 아닙니다. 초기화 전에 호출하면 앱이 비정상 종료될 수 있는 API에서 종종 이 상태를 미리 검사합니다.
  • Package-KakaoAppNotAvailable: 예를 들어 카카오톡 설치가 필요한 API에서 카카오 관련 앱에 접근할 수 없어 실패한 경우입니다. 카카오 관련 앱이 설치되어 있어도 해당 앱을 열 권한을 설정하지 않아 접근할 수 없는 경우도 포함됩니다.
  • Package-Assertion: 패키지의 JavaScript 로직에서 Assertion 검사를 통과하지 못했을 때 발생합니다.

Android의 ActivityNotFoundException​

Android에서 Context가 필요한 API는 React Native Module이 제공하는 getCurrentActivity()를 사용합니다.

ReactApplicationContext는 테마 정보가 필요한 작업이나 startActivity 같은 호출에서 추가 플래그를 요구해 예기치 못한 결과가 발생할 수 있기 때문입니다.

따라서 getCurrentActivity()가 null을 반환해도 에러를 반환합니다.