시나리오 : 코틀린 멀티 플랫폼(KMP) 초기 환경 설정을 처음부터 시작해보았다.
KMP를 사용하기 위해서 젯브레인에서 제공하는 템플릿으로 동작확인을 하다가 템플릿으로 구성되어있는 부분까지 프로젝트 세팅부터 A-Z를 직접 진행해보았다.
https://github.com/JetBrains/compose-multiplatform-ios-android-template/#readme
금방 진행하겠지라고 생각했지만 생각보다 삽질을 많이했던 시간이었다.
차근차근 하나씩 진행해보자
*참고*
코코아팟 관련해서 프로젝트를 생성한다면 iOS distribution에서 옵션을 CocoaPods dependency manger를 선택하고 프로젝트를 생성하자 ( Regular framework로 한 다음에 설정하면 되지않을까해서 다양한 방법을 시도해봤지만 성공하지 못했다. 성공하신 분들은 HowTo 알려주시면 감사드립니다! )
MainView.kt 파일을 생성해서 AOS, iOS에서 공통적으로 사용할 UI를 만들어보자.
Shared > src > comonMain > kotlin > com.example.myapplication [설정한 패키지] > MainView.kt
그런데...응?
Compable을 import 할 수 없다늬... 라이브러리를 추가해서 해결하자.
shared > build.gradle.kts
plugins {
...
id("org.jetbrains.compose")
...
}
commonMain에도
implementation(compose.runtime)
implementation(compose.foundation)
implementation(compose.material) 를 추가해주자.
kotlin {
...
sourceSets {
val commonMain by getting {
dependencies {
//put your multiplatform dependencies here
implementation(compose.runtime)
implementation(compose.foundation)
implementation(compose.material)
}
}
...
}
...
}
그리고 한번 sync 를 맞춰주자.
compose의 버전을 지정해주자.
plugins {
...
id("org.jetbrains.compose") version "1.5.1"
...
}
다시 한번 sync
그냥 되는거 하나 없... ㅠㅠㅠ
gradle.properties에서 아래 속성을 추가한다.
org.jetbrains.compose.experimental.uikit.enabled=true
이제 싱크를 클릭하면 정상적으로 빌드가 된다고 뜬다.
✅ 이제 다시 코드로 돌아가서 보면 import 가 가능하다! 🥳
벌써 하얗게 불태운 이 느낌....
간단하게 파라미터로 받아오는 문자열을 보여주는 화면을 만들어보자.
@Composable
fun App(
sayHello: String,
modifier: Modifier = Modifier.fillMaxSize()
.background(Color.White)
){
Text(text = sayHello)
}
2.2.1 shared > src > androidMain > .... > Platform.android.kt 파일에서 안드로이드에서 호출할 Composable을 만들어 준다.
@Composable
fun MainView()= App(sayHello = getPlatform().name)
전체코드
import androidx.compose.runtime.Composable
actual fun getPlatformName(): String = "Android"
@Composable
fun MainView()= App(sayHello = getPlatform().name)
2.2.2 프로젝트에서 > androidApp > src > main > java > ... > MainActivity.kt에서 MainView() 를 호출하자.
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MyApplicationTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colors.background
) {
MainView()
}
}
}
}
}
2.2.3 안드로이드 실행
안드로이드부터 실행되는지 먼저 실행시키려고 해보니 레드카펫을 깔아주....아니 에러를 깔아주는 안스...
고지가 멀지 않았다. compileSdk와 targetSdk를 34로 업데이트하고 Gradle 싱크까지하고 실행하니 정상적으로 동작하는걸 확인할 수 있었다. 👍👍👍
자 이제 iOS 시뮬레이터에도 적용해보도록 하자.
Composable 어노테이션을 작성할 필요없이 ComposeUIViewController를 이용해서 Composable 화면을 SwfitUI 어플리케이션에 임베딩할 수 있다.
fun MainViewController() = ComposeUIViewController { App(sayHello = getPlatform().name) }
프로젝트에서 iosApp > iosApp > iOSApp.swift 파일을 열어서 코드를 작성해 보자.
전체코드
import UIKit
import SwiftUI
import shared // 공통으로 사용할 모듈인 shared를 import 해준다
@main
struct iOSApp: App {
var body: some Scene {
WindowGroup {
ZStack {
Color.white.ignoresSafeArea(.all) // status bar color
ComposeView()
.ignoresSafeArea(.all, edges: .bottom) // Compose has own keyboard handler
}.preferredColorScheme(.light)
}
}
}
//ComposeUIViewController로 생성했기 때문에 UIViewControllerRespentable 프로토콜을 사용하여
//SwiftUI환경에서 사용할 수 있도록 해준다.
struct ComposeView: UIViewControllerRepresentable {
func makeUIViewController(context: Context) -> UIViewController {
Platform_iosKt.MainViewController()
}
func updateUIViewController(_ uiViewController: UIViewController, context: Context) {}
}
configuration 을 iosApp으로 변경하고 Run을 클릭해보자 .
정상적으로 동작되는것을 확인할 수 있다. (안드로이드 구동시킬 때보다 금방 됨 😄)
마지막으로 템플릿에서 확인할 수있는 버튼 클릭 이벤트를 구현해보자.
구현할 기능
1.버튼을 클릭
2.이미지가 애니메이션과 함께 짜-잔 등장
shared > build.gradle.kts 에서 아래의 코드 2줄을 넣어주자.
// 컴포즈에서 제공하는 resources라이브러리는 아직 실험적인 단계임으로 해당 어노테이션과 함께 사용해야한다.
@OptIn(org.jetbrains.compose.ExperimentalComposeLibrary::class)
implementation(compose.components.resources)
전체코드
kotlin {
...
sourceSets {
val commonMain by getting {
dependencies {
//put your multiplatform dependencies here
...
@OptIn(org.jetbrains.compose.ExperimentalComposeLibrary::class)
implementation(compose.components.resources)
...
}
}
...
}
...
}
그리고 android 안에 sourceSets 경로를 추가해준다. 이 경로를 추가해주고 sync 를 맞추게 되면 우리가 생성해뒀던 resources 폴더가 resources root가 되어있다는걸 확인할 수 있다.
android {
...
sourceSets["main"].resources.srcDirs("src/commonMain/resources")
...
}
이 파일은 example 에서 제공하는 파일을 동일하게 복붙하여 사용하였다.
START
@Composable
fun App(
sayHello: String,
modifier: Modifier = Modifier.fillMaxSize()
.background(Color.White)
){
// 코드작성
}
간단하게 버튼과 이미지를 컬럼으로 감싸서 구현했다.
Column (modifier = modifier){
Button(
onClick = {
// 버튼 클릭시
}) {
Text(sayHello)
}
Image(
painterResource("compose-multiplatform.xml"),
null
)
}
이렇게 실행하게 되면 아래와 같이 버튼과 이미지가 나온다.
버튼 클릭 시 애니메이션이 보였다 없어졌다 할 수 있도록 showImage 변수로 컨트롤 해보자.
var showImage by remember { mutableStateOf(false) }
Button(
onClick = {
showImage = !showImage
}) {
Text(sayHello)
}
Column (modifier = modifier){
...
AnimatedVisibility(showImage) {
Image(
painterResource("compose-multiplatform.xml"),
null
)
...
}
FINAL
@OptIn(ExperimentalResourceApi::class)
@Composable
fun App(
sayHello: String,
modifier: Modifier = Modifier.fillMaxSize()
.background(Color.White)
){
Column (modifier = modifier){
var showImage by remember { mutableStateOf(false) }
Button(
onClick = {
showImage = !showImage
}) {
Text(sayHello)
}
AnimatedVisibility(showImage) {
Image(
painterResource("compose-multiplatform.xml"),
null
)
}
}
}
두 플랫폼에서 버튼 클릭에 따라서 이미지가 애니메이션과 함께 동작하는 것을 확인할 수 있었다.
마무리
- 템플릿을 사용해서 바로 개발을 진행해도 좋지만 이렇게 A-Z 환경설정부터 간단한 기능 테스트를 해보니 훨씬 이해하기 좋았다.
깃 주소 :
https://github.com/PotatoArtie/Potato-iOS/tree/master/Labs/Playground/MyApplication
[Review] 스튜디오봇 사용후기 - Android Studio Bot (0) | 2023.10.12 |
---|---|
[KMP] 코틀린 멀티 플랫폼이란? (적용사례, 내부구조, 컴파일방식) (0) | 2023.09.25 |
댓글 영역