I am writing a suite of apps. Some will be multiplatform, using Compose Multiplatform for the UI. One will be only deployed on Android.
I defined the design system using Compose Multiplatform and Compose Resources. This includes a custom font, in commonMain/composeResources/font/ of my design system module:

This works well, even from a regular Android project. However, that Android project also uses a third-party library, where I need to use the same custom font. That library uses the legacy View system, so I have a second copy of my custom font in res/font/ of the module that needs it.
Everything runs and looks correct, but the result is that I have two copies of this font. The font is over 800KB, and ideally I would only have one copy.
Is there a way that I can use a font defined in Compose Resources with a View?
Right now, I am using the Android font resource in a style, via <item name="android:fontFamily">@font/inter_variable</item>. Probably I can switch that to configuring the font in Kotlin. So, for example, if there is a way I can get a Typeface for the Compose Resources font, I may be able to use that with setTypeface() on a TextView.
Since Compose Multiplatform 1.7.3, The resources are getting packed as Android assets already,
Therefore Typeface.createFromFile(File(Res.getUri('font/path/in/multiplat/commons/'))) should work.
Using Nima's answer as inspiration, I wound up with:
@OptIn(ExperimentalResourceApi::class)
public fun createTypefaceFromComposeResource(context: Context, fontFileName: String): Typeface? = Typeface.createFromAsset(
context.assets,
Uri.parse(Res.getUri("font/$fontFileName")).path?.replace("/android_asset/", "")
)
Usage would be something like:
myTextView.typeface = createTypefaceFromComposeResource(context, "myAwesomeFont.ttf")
Res.getUri() returns a string representation of an Android asset Uri: file:///android_asset/path/to/the/resource. Right now I'm playing it safe, parsing the Uri and using path to get rid of the scheme. Unfortunately, the android_asset segment is considered to be part of the path, which is why I remove it using replace(). If you wanted, you could skip the Uri.parse() and use replace() for the whole initial segment.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With