안녕하세요 오늘은 Compose Multiplatform으로 간단한 샘플앱을 만들던 도중 한글이 깨지는 상황이 발생하여 이를 어떻게 해결했는지를 간단하게 남겨보고자 포스팅을 시작합니다.
관련 Repository: https://github.com/kez-lab/KotlinRPCSample
저는 간단하게 퀴즈 앱을 만들어보고자 아래와 같이 Title, Button 형태의 Screen을 제작하게 되었습니다.
이 과정에서 한글이 위 사진처럼 X박스의 형태로 깨진다는 것을 확인하였고, 아직 알파버전인 Wasm이기에 Wasm자체에 문제라는 것을 직감하고 해결방법을 찾아나섰습니다.
근본적인 이슈의 이유는 잘 모르겠지만, 한글을 지원하는 폰트가 아닌 경우에 한글이 깨진다는 것을 알게되었으며 이를 통해서 커스텀 폰트를 적용한다면 한글 깨짐 에러를 잡을 수 있다는 것을 확인했습니다.
참고 자료는 유광무님과 김만두님의 블로그를 참고하였습니다.
https://holykisa.tistory.com/117
https://kimmandooo.tistory.com/172
해결 방법은 Compose Multiplatform 1.7.0이 나오게 되면서 굉장히 간단해졌습니다.
Compose Multiplatform 프로젝트에서 커스텀 폰트를 사용하려면 compose.components.resources 라이브러리가 필요합니다.
composeApp 모듈의 build.gradle.kts 파일에 아래 종속성을 추가합니다.
commonMain.dependencies {
implementation(compose.components.resources)
}
아래 사진처럼 composeApp의 commonMain 모듈 내에서 composeResources/font라는 디렉터리 내에 폰트 파일을 넣습니다.
저는 한글을 지원하는 폰트인 IBMPlexSansKR 를 사용했습니다! (Google Font에서 다운받았습니다.)
build 를 진행하면 composeApp 모듈 내에 generated/. . . /commonMainResourceAccessors 내에 Font0... 라는 클래스 파일이 생성 된 것을 볼 수 있습니다.
해당 클래스 내부를 확인해보면 IBMPlexSansKR_Medium 라는 변수가 생성된 것을 볼 수 있는데요. 해당 변수를 참조하여 Font객체를 생성할 수 있습니다.
private object CommonMainFont0 {
public val IBMPlexSansKR_Medium: FontResource by
lazy { init_IBMPlexSansKR_Medium() }
}
@InternalResourceApi
internal fun _collectCommonMainFont0Resources(map: MutableMap<String, FontResource>) {
map.put("IBMPlexSansKR_Medium", CommonMainFont0.IBMPlexSansKR_Medium)
}
internal val Res.font.IBMPlexSansKR_Medium: FontResource
get() = CommonMainFont0.IBMPlexSansKR_Medium
private fun init_IBMPlexSansKR_Medium(): FontResource =
org.jetbrains.compose.resources.FontResource(
"font:IBMPlexSansKR_Medium",
setOf(
org.jetbrains.compose.resources.ResourceItem(setOf(),
"composeResources/kotlinrpcsample.composeapp.generated.resources/font/IBMPlexSansKR-Medium.ttf", -1, -1),
)
)
Compose Multiplatform에서는 Res.font를 통해 폰트를 로드할 수 있으며, 이를 FontFamily로 변환하여 사용할 수 있습니다.
여기서 주의사항은 꼭 Font객체에 대한 import를 org.jetbrains.compose.resources.Font 로 참조해야합니다.
만약 androidx.compose.ui.text.font.Font 로 참조하게 된다면 FontResource객체를 인자 값으로 활용하지 못하기 때문에 Res.font를 활용할 수 없습니다.
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Typography
import androidx.compose.runtime.Composable
import androidx.compose.ui.text.font.FontFamily
import kotlinrpcsample.composeapp.generated.resources.IBMPlexSansKR_Medium
import kotlinrpcsample.composeapp.generated.resources.Res
import org.jetbrains.compose.resources.Font
@Composable
fun QuizTheme(content: @Composable () -> Unit) {
val font = Font(Res.font.IBMPlexSansKR_Medium)
MaterialTheme(
typography = Typography(
FontFamily(font)
),
content = content
)
}
저는 QuizTheme라는 새로운 테마 Composable을 적용하여 Typography의 FontFamily로 IBMPlexSansKR_Medium을 적용한 것을 알 수 있습니다.
결과물을 보시면 아시다시피 한글이 굉장히 이쁘게 나오는 것을 알 수 있습니다!
오늘도 역시 CMP 덕분에 다사다난한 하루를 보내게 되었지만 매번 발전해나가는 Jetbrains 덕분에 다행히 발뻗고 잘 수 있을 것 같네요 하핳 감사합니다!