본문 바로가기
Development/Android

Kotlin Multiplatform Mobile(KMM) - Start!

by du.it.ddu 2023. 4. 5.
반응형

최근 크로스 플랫폼에 대한 관심이 많아지고 있다.
그 중에서 가장 관심이 높았던 것은 Flutter와 Kotlin Multiplatform Mobile(KMM)이었다.

Flutter는 3.0 이후, 벌써 3.7 버전이 릴리즈 되었다. (이 마저도 시간이 꽤 지났다.)
https://medium.com/flutter/whats-new-in-flutter-3-7-38cbea71133c

 

What’s new in Flutter 3.7

Material 3 updates, iOS improvements, and much more!

medium.com

그만큼 구글에서도 크로스 플랫폼에 대한 지원을 아낌없이 하고 있다고 봐도 될 것 같고,
그에 따라 여러가지 기업에서도 Flutter를 도입하는 사례가 늘고 채용공고도 많아지고 있다.
Android, iOS 네이티브 개발자도 크로스플랫폼에 대한 역량을 키우는 것이 어느정도 중요해졌다고 생각한다.


구글 뿐만 아니라 Kotlin 진영에서도 크로스플랫폼에 대한 관심을 가지고 프레임워크를 개발하고 있다.
https://kotlinlang.org/docs/multiplatform-mobile-getting-started.html

 

Get started with Kotlin Multiplatform Mobile | Kotlin

 

kotlinlang.org

안드로이드 개발자는 Kotlin을 반드시 사용하게 되는데, Kotlin을 활용한 크로스 플랫폼이라니, 이보다 더 반가울 수는 없다.
나도 관심을 가지고 있었는데, 버전이 너무 낮기 때문에 쓰기 좀 그랬다는 것이다.
그래서 개념정도만 알고, 안정적인 버전이 될 때 까지 기다리고 있었고, 최근 Beta 버전까지 올라온 것을 알게 되었다.

Alpha에서 Beta까지 릴리즈 된 것만 해도 꽤 큰 발전이라고 생각한다. 아직 버전이 0.5.x 이지만, 머지 않아 1.0.0이 릴리즈 되기를 기대하면서 내용을 정리하고, 간단한 앱을 하나 개발해보고자 한다. (아마도 Pokedex. 개인적으로 최고의 샘플 앱이라고 생각한다.)


환경 설정

모든 개발이 그렇듯, 먼저 KMM 개발을 위한 환경을 설정해야 한다.
https://kotlinlang.org/docs/multiplatform-mobile-setup.html

 

Set up an environment | Kotlin

 

kotlinlang.org

설치해야 할 항목이 좀 있지만, 금방 할 수 있다. Android Studio가 사실상 메인이라고 보면 된다.

  • Android Studio (https://developer.android.com/studio)
  • Xcode (iOS 개발을 원한다면? 아마 필수는 아니지 않을까..)
  • JDK (Java --version 명령어를 실행했을 때, 이미 설치되어 있다면 스킵해도 될 것이다.)
  • Kotlin Multplatform Mobile plugin (Android Studio의 플러그인 설치탭에서 설치할 수 있다.)
  • Kotlin plugin (Android Studio를 설치했다면 자연스레 설치될 것이다.)

Mac 사용자라면, 환경설정이 잘 되었고 KMM 개발을 원활하게 할 수 있는지를 KDoctor를 통해 확인할 수 있다.
Flutter의 flutter doctor와 동일한 역할을 한다고 보면 될 것 같다.

brew install kdoctor
kdoctor

HomeBrew가 설치되어 있다면, 터미널에서 위 커맨드를 사용하면 된다.

Xcode는 설치도 하고 앱 실행도 했는데 왜 X표시가 나타나는지는 잘 모르겠지만.. 당장 iOS까지 개발할 계획은 아니기 때문에 그냥 둔다.
내가 어떤 환경이 문제가 있고 해결 방법은 무엇인지 등을 알려준다.
잘 따라하면 어렵지 않게 완료할 수 있다.


첫번째 프로젝트 생성

Android Studio를 실행해서 Kotlin Multiplatfom Mobile App을 선택하고 다음을 누른다.

그 다음은 프로젝트의 경로와 패키지명 등인데, 생략하도록 하겠다.
그리고 그 다음을 보자.

다음은 Koltin Multiplatform App 을 위한 설정이 나온다.
누가봐도 크로스플랫폼과 연관있는 설정으로 보인다. 아직 생소한 개념이니 그대로 두고 마침을 누르자.


Kotlin Multiplatform App 구조 뜯어보기

프로젝트를 생성하고 나면, 위와 같은 폴더 구조를 볼 수 있다.
androidApp과 iosApp 폴더는 프로젝트 생성 단계의 마지막에서 설정해주었던 그 이름으로 생성된 폴더다.
각각은 오로지 Android, iOS앱을 위한 코드를 갖고 있다.
예를 들면 Android는 AndroidManifest, iOS는 Info.plist 같은 것들이 되겠다.
그리고 이들은 shared 모듈을 함께 공유한다. 즉, 의존성 그래프는 아래와 같이 그려진다.

KMM의 컨셉을 생각하면 굉장히 당연하고 간단하다.
그리고 우리는 Shared module에 공유할 코드를 Koltin으로 작성하게 된다.

Shared module

Shared module 내부를 보면, commonMain, androidMain, iosMain 세 폴더로 나뉘어 있다.
이것이 나뉘어져 있는 이유는 KMM의 컨셉과 크로스플랫폼의 특성을 생각하면 이해가 좀 더 쉬워진다.

KMM은 Kotlin으로 플랫폼에 종속적이지 않은 코드를 commonMain에 작성하고, 이를 공유하여 UI를 각각의 네이티브에서 고유한 디자인 철학으로 구현하게 된다.
그런데, 어떤 기능은 네이티브의 특성을 이용해야 할 수도 있다. 이를테면 앱의 버전, SDK 버전을 가져오는 것이 될 수 있다.
이런 경우에 androidMain, iosMain에 코드를 구성하고, 이 코드를 commonMain에서 가져와서 사용하는 것이다.

이러한 예제는 프로젝트 생성 시 작성되어 있는 코드를 보면 쉽게 이해할 수 있다.

commonMain

// commonMain
class Greeting {
    private val platform: Platform = getPlatform()

    fun greet(): String {
        return "Hello, ${platform.name}!"
    }
}

interface Platform {
    val name: String
}

expect fun getPlatform(): Platform

commonMain의 내부를 보면, Greeting이란 클래스가 있고 내부에서 Platform 클래스를 생성하고 있다.
Platform은 인터페이스이고, Platform 인터페이스 객체를 가져오는 함수로 getPlatform 함수가 구현되어 있다.
여기서 expect 키워드가 사용되었는데, 이는 androidMain, iosMain에서 구현된 함수를 사용하겠다는 의미다.
추상화를 생각하면 이해가 쉬울 것이다.

androidMain, iosMain

// iosMain
import platform.UIKit.UIDevice

class IOSPlatform: Platform {
    override val name: String = UIDevice.currentDevice.systemName() + " " + UIDevice.currentDevice.systemVersion
}

actual fun getPlatform(): Platform = IOSPlatform()


// androidMain
class AndroidPlatform : Platform {
    override val name: String = "Android ${android.os.Build.VERSION.SDK_INT}"
}

actual fun getPlatform(): Platform = AndroidPlatform()

androidMain, iosMain에 작성된 Platform 코드의 내용이다.
commonMain에 expect 키워드가 사용된 getPlatform함수를 actual 키워드를 사용하여 구현하고 있다.

즉, 각 네이티브에서 구현해야 할 기능이 있다면 expectactual 키워드를 사용하면 된다.

이렇게 된다면 commomMain, androidMain, iosMain을 각각 개발한다고 할 때, 서로 인터페이스(expect)를 정하고 각각 구현(actual)하면 되기 때문에 크로스플랫폼과 네이티브와의 연결도 손쉽게 할 수 있다고 생각된다.

이제 다음 포스팅은 간단한 예제를 통해 앱을 개발해보도록 하겠다.

반응형