카카오 로그인 성공 여부를 Flow로 반환받기

라이브러리, SDK의 callback에서의 응답값을 Flow로 리턴하는 방법

Sangmeebee
6 min readOct 8, 2022
Photo by Suzanne D. Williams on Unsplash

카카오 로그인 API를 이용하여 토이 프로젝트의 로그인 로직을 구현 하던 중, 카카오 API는 callback을 통하여 로그인이 성공했는지 실패했는지 결과를 알려 준다는 것을 알 수 있었습니다.
저는 이 로직을 별도의 Utility로 만들고 싶었고 두가지 방법을 생각해 볼 수 있었습니다.

  1. callback에서 넘어온 응답값을 통해, UIState(Loading, Success, Error 로 가정..)를 순차적으로 내보내는 Flow로 리턴해주는 메소드를 제작해보자 (callbackFlow를 이용)
  2. callback에서 넘어온 응답값을 반환 값으로 갖는 suspend function을 제작해보자 (suspendCoroutine, suspendCancelableCoroutine을 이용)

두가지 방법은 위와 같이 다른 목적성을 갖고 있습니다.

첫번째 방법(CallbackFlow)은 Flow를 리턴해주기 때문에 지속적으로 값을 전달 받아 처리하고 싶을 때 사용합니다. 현재 예제에서 로그인이 진행중인지, 완료되었는지, 중간에 오류가 발생했는지를 지속적으로 관찰하여 해당하는 UIState를 반환 받아 상태값에 맞는 로직을 처리해 줄 수 있겠죠?

두번째 방법(suspendCoroutine)은 단일 값을 리턴해주기 때문에 일회성 callback에서 사용하기 적합해 보입니다. 사실 카카오에서 제공하는 로그인 API는 일회성 callback이기 때문에 (로그인 성공 or 실패) 두번째 방법이 첫번째 방법보다는 더 나은 방법이라고 생각이 듭니다.

이번 글에서는 첫번째 방법인 callback에서의 응답값을 Flow로 반환시켜주는 메소드로 변경시키는 방법에 대해서 소개할 것입니다. SuspendCoroutine을 이용하여 callback의 응답값을 반환하는 suspend fucntion을 제작하는 방법이 궁금하신 분들은 아래 링크를 통해 확인해주세요!

첫번째 방법을 구현하기 전에, callback을 Flow를 리턴해주는 함수로 변환하기 위해 제공되는 callbackFlow 에 대해 간단히 알아봅시다.

callbackFlow (Callback을 Flow로 변경)

공식문서에서는 callbackFlow를 다음과 같이 소개하고 있습니다. “ProducerScope를 통해 빌더의 코드 블록에 제공된 SendChannel로 전송되는 element를 사용하여 coldFlow의 인스턴스를 만듭니다. 다른 컨텍스트에서 또는 동시에 실행되는 코드에서 element를 생성할 수 있습니다.”

코드를 통해 이해를 돕자면,

public fun <T> callbackFlow(@BuilderInference block: suspend ProducerScope<T>.() -> Unit): Flow<T> = CallbackFlowBuilder(block)

위와 같이 정의되있는 callbackFlow는 block을 파라미터로 전달 받고, CallbackFlowBuilder()에게 전달합니다. 여기서 block은 ProducerScope이라는 걸 알 수 있습니다.
즉, 내부적으로 channel을 생성하고 CallbackFlowBuilder를 통해서 channel을 flow로 변환시켜 반환해주는구나! 정도로 알면 될 것 같습니다. 그럼 우리는 callbackFlow의 block을 정의할때 channel api를 사용하면 되겠죠?

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

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

이 코드를 callbackFlow를 사용하여 Flow를 반환해주는 function으로 재탄생 시켜보겠습니다!

간단히 함수를 설명하겠습니다.

  • UserApiClient의 전역함수로 login을 추가합니다.(다른 로그인 메소드도 추가될 수 있음으로 Kakao Api에서 제공하는 UserApiClient 클래스의 전역함수로 추가 했습니다)
  • login함수는 callbackFlow를 통해 Flow<UiState> 를 반환합니다.
    카카오톡으로 로그인이 가능하다면 카카오톡 애플리케이션을 활용해서 로그인을 시도, 아니라면 카카오 계정을 활용해서 로그인을 시도합니다.
  • awaitClose는 flow가 cancel 되거나 close 될 때(channel.close()가 명시적으로 호출될 때) 해당 블록을 호출시킵니다. 따라서 해당 block안에서는 resource를 해체하는 코드가 들어가야 합니다. 또한 awaitClose를 명시하지 않을 경우 컴파일러는 observer leak이 발생할 수 있다고 판단하기 때문에 반드시 block의 맨 마지막에 명시해야 하며, 그렇지 않을 경우 exception이 발생하므로 주의해야 합니다.
  • 카카오톡 애플리케이션을 활용해서 로그인을 시도하는 메소드, 카카오 계정을 활용해서 로그인을 시도하는 메소드 둘다 ProducerScope의 확장함수로 제작했습니다. 그렇기때문에 channel api를 사용할 수 있게되고, trySend를 통해서 결과값을 전달해줬습니다.
  • UiState.Loading을 제외한 Success나 Error를 send하면 더이상 ProducerScope는 필요 없어지기 때문에 close()를 통해 해당 코루틴을 닫아줬습니다. 그럼 최종적으로 awaitClose가 호출되는것을 확인하실 수 있을겁니다.

제작한 로그인 메소드는 이런식으로 사용하면 되겠죠?

여기까지 callbackFlow를 통해 callback을 Flow로 변경하는 방법을 Kakao Login API를 예로 들어 설명해봤습니다.

--

--