kotlinkotlin-multiplatformcompose-multiplatform

Using fonts in a Compose Multiplatform project


I am looking for a way to easily use custom fonts in a Compose Multiplatform project.

I found that we need to use Font from the androidx.compose.ui.text.platform.Font package. But this object takes in parameter data: ByteArray.

Until now, I haven't found a way to use Font to import a font file from the commonMain resource directory.

How to use custom fonts in the commonMain part of a Compose Multiplatform project?

Thank you for your help!


Solution

  • There is a easy way to use common resources directory for both android and desktop.

    create src/commonMain/resources/ directory inside :shared module. then set the android source sets of android and jvm as follows:

    kotlin {
        targetHierarchy.default()
    
        android {
            compilations.all {
                kotlinOptions {
                    jvmTarget = "1.8"
                }
            }
        }
    
        jvm {
            sourceSets {
                named("jvmMain") {
                    resources.srcDir("src/commonMain/resources") // <============= here
                }
            }
        }
    
        sourceSets {
            val commonMain by getting {
                dependencies {
                    // compose libraries
                    implementation(compose.runtime)
                    implementation(compose.foundation)
                    @OptIn(org.jetbrains.compose.ExperimentalComposeLibrary::class)
                    implementation(compose.components.resources)
                }
            }
            
            val jvmMain by getting {
                dependencies {
                    implementation(compose.desktop.currentOs)
                }
            }
        }
    }
    
    android {
        namespace = "a.b.c"
        compileSdk = 33
        defaultConfig {
            minSdk = 21
        }
        sourceSets {
            named("main") {
                manifest.srcFile("src/androidMain/AndroidManifest.xml")
                res.srcDirs("src/commonMain/resources") // <============= here
            }
        }
    }
    

    To get the fonts create a provider file inside :shared:commonMain/ as:

    expect val acmeTypography: Typography
    

    Now implement it inside both :shared:androidMain and :shared:jvmMain as:

    // shared:jvmMain/
    
    import androidx.compose.ui.text.platform.Font
    
    actual val acmeTypography = Typography(
        defaultFontFamily = FontFamily(
            Font(resource = "font/acme_regular.ttf", FontWeight.Normal)
        ),
    )
    
    // shared:androidMain
    import androidx.compose.ui.text.font.Font
    
    actual val acmeTypography = Typography(
        defaultFontFamily = FontFamily(
            Font(R.font.acme_regular, FontWeight.Normal)
        ),
    )