Slide 1

Slide 1 text

Compose Multiplatform Image Picker 팀명: MoneyKing 시니어: 권대원 주니어: 이지훈 https://github.com/KwonDae/ImagePicker

Slide 2

Slide 2 text

Kotlin Multiplatform 이 아닌 Compose Multiplatform 을 선택한 이유 • 빠르게 프로젝트를 마무리 해야함 • Swift 라는 언어와 SwiftUI에 대한 숙련도가 아직 부족하여, 익숙한 Kotlin 기반의 Compose 로 공통의 UI 를 작성 해보는 것을 둘 다 선호 • Image Picker 라는 단순한 앱이기에, UI 를 Compose, SwiftUI 로 각각 작성 할 필요가 없다고 판단 • 이미지 로드를 위한 Coil 라이브러리가 3버전 부터 Compose Multiplatform 을 지원

Slide 3

Slide 3 text

프로젝트 구조 • commonMain 의 rememberImagePickerLauncher expect 함수를 androidMain, iosMain 에서 actual 함수 로 구현 • Screen 과 Component 는 commonMain 에서 공통으로 관리

Slide 4

Slide 4 text

시연

Slide 5

Slide 5 text

이슈 공유 1. Android 에서는 PhotoPicker 를 통해 별도의 권한 없이 갤러리에 접근할 수 있는데, iOS 에서는??? 2. Coil3 을 통해 네트워크 이미지를 로드할 때, 기존의 Coil2 와 다른 점 3. moko-resources 라이브러리를 통해 국제화를 적용할 때, Android 측 Config Change 관련 이슈 4. Decompose 라이브러리의 Navigation 을 통해 데이터를 전달해야 하는데, 각 플랫폼에서 받아온 사진의 Data Type이 다른 문제

Slide 6

Slide 6 text

이슈 1) iOS 에서는 갤러리에 어떻게 접근? • iOS 에서는 iOS 14 부터 PHPicker 를 사용 • 해당 기능을 구현하는 것이 이번 프로젝트의 핵심 • Peekaboo 라는 Compose Multiplatform 을 지원하는 imagePicker 라이브러리의 내부 코드를 참고해서 구현 https://github.com/TEAM-PREAT/peekaboo

Slide 7

Slide 7 text

이슈 1) iOS 에서는 갤러리에 어떻게 접근? • iosMain 는 iosApp 모듈이 아닌 composeApp 모듈에 포함되어 있기 때문에 Swift 가 아닌, Swift 와 호환 가능한 Kotlin-Native 기반으로 코드를 작성 • PHPickerViewController 를 호출하기 위해 PHPickerViewControllerDelegateProtocol 인터페이스를 구현하는 delegate 객체를 정의 • 결과적으로 선택된 이미지가 NSData 타입으로 내려오는데 이를 Kotlin-Native 에서 사용할 수 있는 ByteArray 타입으로 변환 참고) Compose-multiplatform 이미지 피커 라이브러리 배포하기 composeApp/iosMain/imagePickerLauncher.kt

Slide 8

Slide 8 text

이슈 2) Coil3 를 이용한 Network Image Load (Coil3 에서 제공하는 LocalPlatformContext 를 통해 context 에 접근 가능) 기존과 같이 coil 라이브러리를 주입하 고, 이미지를 로드 해보았지만 image 가 화면에 출력되지 않는 문제 가 발생…

Slide 9

Slide 9 text

이슈 2) Coil3 를 이용한 Network Image Load https://coil-kt.github.io/coil/upgrading_to_coil3/#network-images 기존에 Coil2.x 버전에서는 Network Image 를 로드할 때, Coil 내부에서 OkHttp 를 사용 Coil3 버전에서는 Multiplatform 을 지원하기 위해 OkHttp 가 아닌 Ktor 를 사용하는 것으로 변경 현재 alpha 버전인 Coil3 에서는 ImageLoader 가 기본적으로 network url 형태의 이미지를 로드하는 것을 지원하지 않음 별도로 coil-network 와 ktor 를 import 하여 NetworkFetcher.Factor()를 직접 설정

Slide 10

Slide 10 text

이슈 3) moko-resources Android i18n Config Change Multiplaform 환경에서 resources(string, font, image) 등을 공유하여 사용하기 위해, 국제화를 지 원하기 위해 moko-resources 라이브러리를 사용 iOS 환경, Xcode 에서 resources 들을 복제하기 위한 환경 설정이 추가적으로 필요(공식 문서 참고) moko-resources 0.23.0 버전 기준) Android 기기에서 시스템 언어를 변경한 뒤, 앱에 다 시 진입했을 때, 변경된 언어가 반영이 되지 않는 문 제 (다시 앱을 실행해야 반영) https://github.com/icerockdev/moko-resources

Slide 11

Slide 11 text

이슈 3) moko-resources Android i18n Config Change https://github.com/icerockdev/moko-resources/issues/533

Slide 12

Slide 12 text

이슈 4) Decompose Navigation argument type Decompose 는 Androidx 의 Navigation 과 AAC ViewModel 과 비슷한 State holder 를 Multiplatform 에서 제공하는 라이브러리 문제는 Navigation 을 통해 상세 화면으로 전달해야 할 데이터의 타입이 Android 에서는 android.net.Uri, iOS 에서는 ByteArray 타입으로 같지 않다는 것 (심지어 android.net.Uri 타입은 android 플랫폼 종속성이 있어, commonMain 에서 접근 불가)

Slide 13

Slide 13 text

이슈 4) Decompose Navigation argument type • 전달해야 할 타입을 Kotlinx-Serialization 을 통해 직렬화 할 수 있는 ByteArray 로 통일하여 해결 • Uri 를 ByteArray 로 변환하기 위해, Coil3 를 이용 • 하지만 Coil3 는 Coil2 버전과 차이점이 존재해 오른쪽의 기존의 사용했던 함수를 사용할 수 없음 • 공식 문서도 확인해보았으나, alpha 버전이 나온 지 얼마 되지 않아, 레퍼런스가 없어 해결하는데 어려움이 존재

Slide 14

Slide 14 text

이슈 4) Decompose Navigation argument type

Slide 15

Slide 15 text

이슈 4) Decompose Navigation argument type 영광스럽게도 skydoves 님의 도움을 받아, coil3 에서 사용할 수 있는 함수로 migration 할 수 있었음

Slide 16

Slide 16 text

후기 • 시니어) 권대원 • CMP를 접하기 전에는 컴포즈로 Android, iOS UI를 그린다는것이 상상이 가지 않았 지만, 별개로 존재하는 iOS의 lifecycle 같은 부분들을 주의한다면 KMM 과 크게 다르 지 않다고 느꼈다. • 이번 KMM 스터디를 진행하면서 조금은 익숙해진 덕분에 공통 로직을 생성하여 각 플랫폼 별로 비즈니스 로직을 구현할 수 있었다. 특히 iOS 모듈에서는 kotlin-native 로 구현을 하면서 kotlin-native 에 큰 의존성을 갖고 있다보니, 제한사항을 마주할 수 있다는 생각이 들었다. • 그리고 지훈님이 decompose, moko-resources 등 여러 라이브러리 사용과 아이디어 를 주셔서 많이 배울 수 있었다.

Slide 17

Slide 17 text

후기 • 주니어) 이지훈 • 토이 프로젝트를 하면서 Compose Multiplatform 과 조금이나마 친해질 수 있어서 좋았다. 프로젝트 초기에 환경 설정 단계(coil) 에서 어려움이 있었는데, 대원님께서 해결을 해주셔서, 빠르게 다음 단계로 넘어갈 수 있었다. • 다음에도 이런 좋은 기회가 있다면, Multiplatform 을 지원하는, 써보지 않았던 다른 라이브러리들도 사용 해보면서, 좀 더 규모 있는 앱을 만들어보고 싶다.

Slide 18

Slide 18 text

참고 • 이슈 해결의 대한 더욱 자세한 내용은 하단의 블로그 글 링크를 참고 • [Compose Multiplatform] Coil 을 이용한 Network Image Load • [Compose Multiplatform] moko-resources 를 이용하여 font 적용하기 • [Compose Multiplatform]moko-resources 라이브러리를 통해 국제화(i18n) 적용하기 • [Compose Multiplatform] Decompose 라이브러리를 통해 Navigation 구현하기 (깃허브 레포에도 링크 걸어놨어요!)

Slide 19

Slide 19 text

감사합니다.