Kotlin Multiplatform(KMP)란?

코틀린 멀티플랫폼을 사용하면 Server, Android, iOS, Desktop, Web 여러 플랫폼에서 단일 코드베이스로 모든 애플리케이션간에 로직을 공유할 수 있게 된다. 심지어 컴포즈 멀티플랫폼을 사용한다면 일반적인 UI를 모든 플랫폼에서 공유할 수 있다.

KMP 도입배경

첨부된 이미지와 같이 사용자가 업로드 하고자 하는 이미지의 대표 색상을 추출하는 로직이 필요했다. 안드로이드의 경우 Palette API를 사용하면 간단히 구현할 수 있다. 문제는 Android, iOS, Web 모두 이 기능이 필요했고, 주어진 동일한 이미지에 대해 동일한 컬러 값을 도출 할 수 있어야 했다. 하지만 Palette 라이브러리는 안드로이드 전용이였다. 동일한 컬러값을 뽑는 기능을 각 플랫폼에서 구현하던지 아니면 싱글 코드베이스로 모든 플랫폼이 공유하던지 둘중 하나였다. 그렇게 KMP를 선택했다. 그때는 가능할 것만 같았다.

선녀 같았던 KMP

안드로이드 앱 개발자 입장에서 KMP는 선녀와도 같았다. 익숙한 코틀린향기, 떡주무르듯 주물러본 IntelliJ IDE(안드로이드 스튜디오 와 같다), 눈감고도 빌드 할 수 있는 Gradle 시스템.. 시작이 좋았다.

코틀린 멀티플랫폼 공식문서도 나름 잘 되어있어서 하루만에 내가 필요한 것들은 다 얻었다. 실제로 제공하는 예제들도 꽤나 직관적이고, 잘 동작했었다.

난 확신이 들었다.

“이거다! 이게 미래다! 잘만 된다면 모든 플랫폼이 삼국통일을 이룰 수 있겠어”

아무것도 모르고 지껄였던 과거의 나

KMP로 AAR 라이브러리 만들고 배포

실제 공식문서와 깃헙에 존재하는 수많은 샘플 프로젝트. 모두들 코틀린 멀티플랫폼 좋다라고 하니 나라고 안할 이유가 없었다. 하지만 기쁨도 잠시, 내가 하고자 하는 것은 코틀린 멀티플랫폼으로 애플리케이션을 만드는 것이 아니다.

첫번째 위기였다. 안드로이드, iOS, Web앱을 만드는 가이드 문서는 있지만 이들을 위한 라이브러리 생성 및 배포 방법은 상세한 내용이 없었다. 나는 우선 익숙한 안드로이드 용 라이브러리(AAR)을 빌드해보기로 결정했다.

./gradlew build

어떤 태스크를 실행해야 할지 막막했다 우선 빌드를 했다. 성공했다!

root/build 에 빌드한 산출물들이 보이기 시작했다. outputs 가보니 익숙한 것들이 보이기 시작한다.

안드로이드 프로젝트에 이식했다. “어? 되는데?” 하지만 기쁨도 잠시 클래스를 찾지 못한다는 에러를 뿜어냈다. 이유는 뭔지 모르겠다. 검색해도 나오지도 않는다.

결국 난 공식문서에 나와있는데로 Maven으로 배포를 했고, 안드로이드 프로젝트에 KMP 라이브러리 첫 이식에 성공했다.

iOS / Web 용 라이브러리 배포

안드로이드 앱 개발자이기 때문에 라이브러리 형태가 AAR이라는건 너무나도 잘알고 있었다. iOS 및 Web도 왕년에 조금 했었기 때문에 프레임워크 및 자바스크립트 형태로 라이브러리가 나오겠구나 지레짐작은 했다. 하지만 난 그쪽 플랫폼 실무자가 아니므로 결국 타 플랫폼 담당자분께 필요한 내용이 무엇인지 물어보았다.

iOS 개발자분은 XCFramework가 필요하다고 했다. 구글에 해당 라이브러리를 빌드하려면 어떻게 하는지 찾아봤다.

./gradlew assembleXCFramework

바로 산출물이 나왔다. iOS개발자에게 전달하니 잘 동작한다고 한다. 너무 순조롭다.

이제 웹 개발자에게 가서 물어보았다. 자바스크립트면 된다고 한다. 검색 해보았지만 별다른 방법을 찾을 수 없어, /build 디렉토리에 한번 더 방문에서 뒤지기 시작했다. 그럴싸 한걸 찾았다.

“웹 개발자님, 이거면 되나요?”

몇번의 핑퐁을 거친 끝에, 해당 JS 라이브러리가 잘 이식 되는 것을 확인했다. 이렇게 모든 플랫폼이 코틀린으로 작성한 코드가 동작하는 것을 확인했다.

고통의 서막

사실 타플랫폼으로 라이브러리를 전달하기 전에 위기가 한번 있었다. 바로 Palette 라이브러리를 KMP에 이식해야 하는 것이다. 해당 라이브러리는 Android 의존성이 있으므로 그걸 다 걷어내야 했었다. 덤으로 java.util.*과 같은 자바 의존적인 것도 다 걷어내야한다. 왜냐하면 코틀린으로 작성하고 있지만 내가 작성하고 있는 코드는 JVM에서만 동작하는게 아니기 때문이다.

Palette 라이브러리에는 클래스 파일이 3개밖에 없다. “너무 쉬운데?” 라는 생각이 들며 호기롭게 시작했던 과거의 나에게 한마디 하고 싶었다.

S.T.A.Y

왜냐면 그게 고통의 서막이였으니까…

일단 안드로이드에 의존적인 부분중에 첫번째 위기는 android.graphics.Bitmap 이었다. 코틀린에서는 비트맵을 어떻게 다룰 것인가? 일단 난 IntArray와 사이즈(width, height)를 갖고 있는 비트맵 모델 클래스를 하나 생성했다. 그리고 비트맵 및 Color와 관련된 내부로직은 그대로 코틀린으로 배껴왔다.

Palette 내부에는 PriorityQueue 라는 안드로이드 SDK에 포함된 자료구조가 있는데, 이건 도저히 가져올 엄두가 안났다. 그냥 이건 ArrayDeque로 대체했다. 프로그램이 제대로 안도는건 나중 문제다.

그외에도 ColorUtils.java 등 수많은 의존성들이 필요했는데 다 복붙했다. 마지막 하나 내부적으로 비트맵을 리사이즈 하는 로직이 있는데 이건 native(JNI)를 타고 들어가는 바람에 결국 코틀린 이미지 라이브러리 KorIM 을 찾아 이르게 된다.

이것 말고도 더 많은 Pain point들이 있었지만 다열거 할수가 없다.

플랫폼 별 상이한 결과

일단 안드로이드용 샘플 앱을 만들어서 웹 샘플앱과 비교했다. 색상이 다르다. 달라도 너무 다르다.

아무래도 코틀린으로 작성한 코드가 자바스크립트로 전환이 될 때 뭔가 문제가 있는듯 하다. 매핑되는 자료형이 달라 문제가 되는듯 싶다.

삼국통일을 꿈꾸었지만 난 김춘추가 될수는 없나보다. 아쉽지만 Web은 KMP배포대상에서 제외하고, iOS라도 안드로이드와 함께하기로 결정했다.

Android 샘플 앱과 iOS 샘플앱을 비교해보았다.

도출되는 컬러는 비슷했다. 하지만 미묘하게 컬러코드가 다르다.

iOS개발에 사용되는 언어인 Swift는 코틀린과 많은 유사성을 갖기 때문에 빌드 산출물도 큰차이가 없어보였을 뿐 차이가 없는 것이 아니었다. 몇몇 케이스에서 웹과 동일한 문제를 보였다. 컬러값이 달라도 너무 다르고, 동일한 이미지 버퍼에 대해 컬러를 아예 못찾는 경우도 생겼다.

KMP 프로젝트를 포기하다

결국 코틀린으로 작성한 로직이 모든 플랫폼에 동작은 할 수 있지만, 여러가지 이유로 완벽하게 내가 기대한 대로 동작하 지는 않는다는 것을 깨닫았다.

일주일 동안 나를 비롯한 너무 많은 사람들이 이 프로젝트에 협조하느라 고생했어서 더 일찍 포기를 못했었다. 좀 더일찍 포기했더라면 덜 고생시켰을텐데… 산출물도 못만들고 동료들에게 미안함도 많이 들고 너무나도 아쉬웠다.

실패한 내용이지만 이 글을 포스팅하는 이유는 앞으로도 나와 같은 실수나 시련을 겪지 않길 바라는 마음에서다. 예전부터 리액트네이티브니 플루터니 하는 크로스 개발 플랫폼에 대한 부정적인 인식을 갖고 있었다. 그럼에도 불구하고 KMP를 시도 해 본것은 익숙한 인텔리J의 UI/UX와 빌드시스템, 그리고 코틀린이라는 익숙하고 강력한 언어 때문이었다.

시간이 좀 더 지나 KMP가 더 쓸만해지면 모를까, 당분간 내인생에 KMP 는 없다.

카테고리: Kotlin

2개의 댓글

eastar · 2023년 9월 23일 5:45 오후

컴퓨터에서 “동일한 입력값은 동일한 결과값” 거의 진리에 가까운 이야기 일꺼라 생각됩니다.

결국 어딘가 다른 코드가 다른 결과 라기 보다는
다른 입력값이 다른 결과 값을 내보낸것이 아닐까 싶긴 합니다.

이미지라는 입력 데이터가 아니라 api의 json 같은 입력값이라면
혹은 이미지에 pixel 정보 배열이 입력 값이 였다면
좀 더 낙관적인결과가 있었을것 같아요..

적어도 3가지 플렛폼에 배포 할수 있는 무언가를 만들수 있다는것 까지는
이번에 수확으로 생각하고
다음번에도 포기하지 말고 도전~ 해봤으면 좋겠네요

    Charlezz · 2023년 10월 5일 2:22 오후

    – 디코더를 직접 다루지 않았기 때문에 동일한 입력(이미지 버퍼, 픽셀 정보 배열)을 만들기 어려웠습니다.
    – 코틀린 코드가 다른 언어로 변환되는 과정에서 자료형 매핑이 원하는대로 이루어지지 않았습니다. 그로인해 비트쉬프팅 같은 연산에서 오류가 발생한 것 같구요(추정)

    위 두가지 내용을 직접 확인한 것만 해도 큰 수확이라고 생각하고, 말씀하신대로 다음번에도 한번 더 도전해보려고 합니다! 감사합니다.

답글 남기기

Avatar placeholder

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다.