Android KMM 간단히 알아보기
KMM 간단히 알아보기
Android, IOS,웹 애시당초 같은 로직을 언어마다 따로 만든다는게 잘못된거 아닌가? 그냥 C++ 하나 정도면 사람이 프로그램하는게 전혀 문제가 없는데, 뭘또 계속 만드는지…여튼 이런 환경에서 Kotlin 이 어느정도 답을 제시하고 있다.
Kotlin MPP 프로젝트는 IntelliJ에서 해도 되고, 익숙한 Android Studio Plugin (Kotlin Multiplatform Mobile) 을 설치해서 해도 된다.
AndroidStudio 를 이용하면 바로 IOS 도 실행 해볼수 있다.(안되더라)
-
안드로이드스튜이도에서 신규작성을 할때, 맨마지막에 있는 KMM Application을 선택하자.
-
앱이름과 등등 이름을 입력하고 생성하자. 관련 라이브러리 받으라 더럽게 오래 걸린다.
https://github.com/sugoigroup/kotlin_mpp_example/commit/9ce2f2fd791270c86eeae6265837a9b49eb473f5
shared 의 build.gradle.kts를 보면
kotlin {
android()
ios { //ios가 sourceSet에서는 iosMain으로 지정
binaries {
framework {
baseName = "shared" // ios프로젝트를 xcode에서 열어보면 shared란 framework 이름으로 추가되어있다.
}
}
}
sourceSets {
val iosMain by getting
}
}
- Hello 공용모듈을 분석해보자
commonMain 아래에 있는것들이 말그대로 공용함수가 있는곳이다. 프로젝트 작성과 함께Greeting.kt, Platform.kt 가 있다.
kotlin 에서는
expect : 이 키워드를 붙인 클래스나 함수는 각 플랫폼에서 동일하게 사용될것 같은 (마치 인터페이스같은) 것이라는 의미이다.
actual : 앞서 expect로 외부에서 불러내면 , 각 플랫폼에따라서 상황에 맞는 동작을 해야되는데 actual 키워드를 클래스나 함수 앞에 붙여준다. 따라서 expect 가 붙어있는 것들은 각 플랫폼(iosMain, AndroidMain, jsMain등)에 aspect로 쌍을 이뤄서 써줘야한다.
그래서
--shared/commonMain/.../Greeting.kt
//Greeting 클래스는 외부의 각플랫폼에서 불러낼수 있다. 단, 어떤 플랫폼에서 불러내든 동일한 처리와 결과같을 가지게 된다.
class Greeting {
fun greeting(): String {
return "Hello, ${Platform().platform}!" // Platform().platform 이라는 expect(실제의 구현체가 있을지 없을지 모르는 예상의) 키워드가 붙은 클래스를 불러냈다.
}
}
--shared/commonMain/.../Platform.kt
// expect가 붙은 Platform 클래스는 platform(문자형변수)를 가지고있고, 외부에서 Greeing.greeting()을 불러실행할떄, Platform().platform 형식으로 값을 가져다가 출력한다. 이곳에는 단지 expect만 지정했기때문에 실제 구현체는 공용모듈안의 각 플랫폼에서 진행하자.
expect class Platform() {
val platform: String
}
--shared/androidMain/Platform.kt
// exctual라인옆에 <E> 가 보인다. expect에 대응하는 안드로이드플랫폼용 actual을 구현하자.
// actual이 조금 지저분하다. 여튼 안드로이드는 SDK_INT로 버젼을 확인하니 해당 코드를 넣어주었다
actual class Platform actual constructor() {
actual val platform: String = "Android ${android.os.Build.VERSION.SDK_INT}"
}
--shared/iosMain/Platform.kt
// ios코드가 재밌다. UIDevice클래스(랩퍼겠지?)를 이용하여 버젼을 출력하는 코드를 넣었다..
actual class Platform actual constructor() {
actual val platform: String = UIDevice.currentDevice.systemName() + " " + UIDevice.currentDevice.systemVersion
}
이로써 공통 모듈은 준비가 되었다.
이제 각 플랫폼에서 공통모듈을 불러내서 Greeting함수만 실행하면 각 플랫폼의OS버젼이 출력된다.
안드로이드의 gradle.build 에 공용모듈의 의존성을 추가(implementation(project(":shared"))한다음소스에서 클래스와 함수 불러내면 된다.
--androidApp/.../MainActivity.kt
호출:Greeting().greeting();
결과:"Hello, Android 28!"
결국 shared모듈을 의존성에 추가하면, 공통 Greeting클래스라 expect된 Platform().platform을 호출하고 androidMain플랫폼에 actual하여 적어준대로 "Android ${android.os.Build.VERSION.SDK_INT}"를 출력하게 된다.
안드로이드와 비슷하게, ios프로젝트 내부에 공용모듈인 shared.framework을 추가되었고, swift언어로 클래스와 함수를 불러냈다.
--iosApp/.../ContentView.swift
호출:Greeting().greeting();
결과:"Hello, ios ....!"
마찬가지로, expect된 Platform().platform을 iosMain 에서 “UIDevice.currentDevice.systemName() + " " + UIDevice.currentDevice.systemVersion” 식으로 출력했다.
- 그럼 나도 추가해보자. 일단 멀티플랫폼에서 사용할만한게…환전?! 환전예상가격을 조회하는 어플을 만든다 할때, 미국달러를 나라별 환전금액으로 변환해주는 로직을 안드로이드와 아이폰 양쪽에서 만들필요없이 공통로직에서 처리하면 좋을것 같다.
https://github.com/sugoigroup/kotlin_mpp_example/commit/5c7956fa68dd2fb6dc93ad278d99804bb5eae352
--commonMain/.../ExchangeMoney.kt
외부에서 사용할 클래스와 함수를 expect 정의
expect class ExchangeMoney(baseDollor: Double) {
fun toYen(): Double
fun toWon(): Double
}
--commonMain/.../ExchangeMoneyCalcurator.kt
각 플랫폼에서 expect함수를 통해 actual 선언된 함수를 이용할때, 플랫폼에 상관없이 똑같이 처리할 로직을 넣음
class ExchangeMoneyCalcurator(val baseDollor: Double, val country: String) {
fun calc(): Double {
val rate: Double = when (country) {
"YEN" -> 0.91
"WON" -> 0.95
else -> 1.0
}
return baseDollor * rate
}
}
--androidMain/.../ExchangeMoney.kt
expect 함수들을 actual로 구현. 단 공통로직은 ExchangeMonetCalcurator를 호출하여 구현
actual class ExchangeMoney actual actual class ExchangeMoney actual constructor(val baseDollor: Double) {
actual fun toYen(): Double {
return ExchangeMoneyCalcurator(baseDollor, "YEN").calc()
}
actual fun toWon(): Double {
return ExchangeMoneyCalcurator(baseDollor, "WON").calc()
}
}
--iosMain/.../ExchangeMoney.kt
actual class ExchangeMoney actual constructor(val baseDollor: Double) {
actual fun toYen(): Double {
return ExchangeMoneyCalcurator(baseDollor, "YEN").calc()
}
actual fun toWon(): Double {
return ExchangeMoneyCalcurator(baseDollor, "WON").calc()
}
}
Android 에서 사용해보자.
--androidApp/.../MainActivity.kt
tv.text = ("3 달라는 한국돈으로 " + ExchangeMoney(3.0).toWon())
iOS 에서 사용해보자.
--iodApp/.../ContentView.swift
Text("3 달라는 엔화로" + String(ExchangeMoney(baseDollor: 3.0).toYen()))
이밖에 멀티플랫폼에서 사용할만한 라이브러리가 있다.
https://github.com/AAkira/Kotlin-Multiplatform-Libraries
GraghSQL, SQLDelight, Realm, Koin, LiveData, coroutine, uuid, firebase, moko-widget 등 디비와 통신, 로직에 사용할 만한 라이브러리 들이 있다
0 comments:
댓글 쓰기