카카오 로그인 성공 여부를 코루틴으로 반환받기

Callback을 Coroutine으로 변경

Sangmeebee
6 min readOct 11, 2022
Photo by Arseny Togulev on Unsplash

코루틴의 장점 중 하나는 이른바 콜백지옥이라고 불리는 인덴트가 반복되는 코드를 제거 할 수 있다는 점입니다. 비동기 처리를 코드의 순서대로 실행시키며 가독성을 높이고, 보다 심플한 코드를 작성할 수 있도록 도와줍니다.

단, 기존의 라이브러리나, 안드로이드에서는 callback으로 비동기 처리를 하고 있는 API들이 존재합니다.

코루틴에서는 기존 콜백을 좀 더 간편하게 사용할 수 있도록 suspendCoroutine, suspendCancellableCoroutine을 제공합니다.

참고) callbackFlow를 이용하여 “카카오 로그인 성공 여부를 Flow로 반환받기”에 대해서 작성한 글도 있으니 callbackFlow에 대해서 궁금하신 분들은 참고하시기 바랍니다.

suspendCoroutine vs suspendCancellableCoroutine

suspend inline fun <T> suspendCoroutine(
crossinline block: (Continuation<T>) -> Unit
): T

suspendCoroutine은 suspend 함수 내에서 현재 continuation 인스턴스를 얻고 현재 실행 중인 코루틴을 일시 중단합니다. continuation의 resume()resumeWithException()을 통해서 값을 반환해주거나 throw exception을 해줄 수 있습니다.

inline suspend fun <T> suspendCancellableCoroutine(crossinline block: (CancellableContinuation<T>) -> Unit): T

suspendCancellableCoroutine suspendCoroutine과 같은 코루틴을 일시 중단하지만 블록에 CancellableContinuation객체를 제공합니다. 이 함수는 코루틴의 작업이 일시 중단된 동안 취소되거나 완료되면 CancellationException을 throw합니다.

이부분이 suspendCoroutine과의 차이점입니다.

  • suspendCancellableCoroutine은 호출하는 코루틴이 취소나 완료되면 CancellationException이 발생하고 continuationd.invokeOnCancellation을 통해 resume이 수행되지 못하는 경우를 대비하거나, cancel에 대한 callback을 받을 수 있는 resume을 사용하는 방법도 있습니다.
  • suspendCoroutine은 호출하는 코루틴이 취소나 완료에 상관없이 작업을 완료하고 resume이나 resumeWithException을 통해 해당 값을 반환합니다.

suspendCoroutine과 마찬가지로 resume()resumeWithException()을 통해서 값을 반환해주거나 throw exception을 해줄 수 있습니다.

uspendCoroutine과 suspendCancellableCoroutine가 위에서 알아본대로 동작하는지 테스트 코드를 작성해봤습니다. suspendCoroutine을 사용하여 1초 후에 1000을 반환해주는 suspendCoroutineTest() 메소드와 suspendCancellableCoroutine을 사용하여 1초 후에 100을 반환해주는 suspendCancellableCoroutineTest()메소드가 존재합니다.

main에서 500 밀리세컨드 후에 각각 메소드가 실행된 코루틴을 종료하면 어떤 결과가 나올까요?

1000 // suspendCoroutineTest의 결과값
hihi // suspendCancellableCoroutineTest의 결과값

suspendCoroutine은 코루틴의 완료/취소 여부와 관계없이 1000이 출력됐고, suspendCancellableCoroutine은 코루틴이 완료/취소되면 Exception이 발생하여 종료되었고 resume에 cancel에 대한 콜백이 실행되어 hihi가 출력됐다는 것을 알 수 있습니다.

아래 코드는 Kakao Developers에서 제공하는 로그인 구현 관련 예제입니다.

callback의 응답값에 카카오톡으로 로그인이 성공했는지 실패했는지, 실패했으면 카카오 어카운트를 통해 로그인을 시도하고 성공했는지 실패했는지 구현 되어있습니다.

이 코드를 알아본 suspendCoroutine을 사용하여, 카카오 로그인 API의 callback의 결과값을 반환하는 suspend function을 제작해보겠습니다. (참고로 저는 viewModel에 uiState를 가지고 있고 로그인이 성공하면 uiState의 isLogin을 true로 바꿔주는 방식으로 uiEvent를 처리하고 있기때문에 suspendCorutine을 채택하여 구현했습니다.)

  • UserApiClient의 전역함수로 login을 추가합니다.(다른 로그인 메소드도 추가될 수 있음으로 Kakao Api에서 제공하는 UserApiClient 클래스의 전역함수로 추가 했습니다)
  • loginWithKakaoTalk()과 loginWithKakaoAccount()는 각각 카카오 API에서 제공해주는 카카오톡으로 로그인과 카카오계정으로 로그인 함수를 호출해주고 callback 메소드에 Continuation 확장함수로 제작한 resumeTokenOrException() 메소드를 호출하게 제작했습니다.
  • resumeTokenOrException에서 error가 있다면 resumeWithException()을 통해 error을 throw해주고, token이 있다면 resume()을 통해 token을 반환해주는 로직을 제작했습니다.

제작한 Utility를 위와 같이 사용할 수 있습니다. 저는 signInUiState라는 UIState를 만들고 로그인버튼을 누르면 uiState의 doLogin을 true로 업데이트 시켜주었습니다. 그럼 fragment에서 doLogin을 observe하고 있다가 true가 되었다는 것을 알면 UserApiClient의 전역함수로 만들어 놓은 login메소드를 호출하고 Result로 단일 값을 반환 받았으니, onSuccess와 onFailure을 통해서 알맞게 핸들링해주면 됩니다.

여기까지 카카오 로그인 성공 여부를 코루틴으로 반환받는 방법에 대해 알아봤습니다.

--

--