When it comes to displaying text in Android Applications, Fonts are used to describe the styling, size and weight of a typeface. In some cases, developers render text in their applications without overriding the default font being used – which results in the default typeface for applications being applied. On the other hand, many applications rely on custom fonts to express their brand and create a consistent experience across platforms. While these custom fonts can come from many different sources, Google Fonts offers access to over 1000 open source font families and in this post, we’ll take a look at how we can take 5 steps to access these fonts on-the-fly using Jetpack Compose 🚀
This post is sponsored by Practical Jetpack Compose.
Why not sponsor this blog and reach thousands of developers every month?
Step 1: Adding the dependency
To get started with using downloadable fonts, we’re first going to need to add the dependency to our project. The library is currently in beta, so be sure to pass on any feedback using the Issue Tracker.
implementation 'androidx.compose.ui:ui-text-google-fonts:1.2.0-beta02
Step 2: Configuring the Font Provider
With this dependency in place, we can get started with configuring our project to support downloadable Google Fonts. This configuration is done in the form of the GoogleFont.Provider class, which requires 3 pieces of information:
- providerAuthority – a string value representing the authority of the font provider for the download request
- providerPackage – a string value representing the the package of the font provider for the download request
- certificates – a resource array containing the certificates for the provider to be signed with
Because we are downloading fonts specifically from Google Fonts, we need to pass the corresponding credentials for Google Fonts. While the authority and package values are simple string references, the certificates argument takes the form of a resource array containing the required hashes for accessing the fonts provider. We’ll need to add a new file to the resources directory of our application which will hold these values, which we’ll call font_certs.xml. The current recommended approach is to copy in the content from this file – these are the credentials used grant access to the Google Fonts provider.
<resources>
<array name="com_google_android_gms_fonts_certs">
<item>@array/com_google_android_gms_fonts_certs_dev</item>
<item>@array/com_google_android_gms_fonts_certs_prod</item>
</array>
<string-array name="com_google_android_gms_fonts_certs_dev">
<item>
MIIEqDCCA5CgAwIBAgIJANWFuGx90071MA0GCSqGSIb3DQEBBAUAMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAeFw0wODA0MTUyMzM2NTZaFw0zNTA5MDEyMzM2NTZaMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBANbOLggKv+IxTdGNs8/TGFy0PTP6DHThvbbR24kT9ixcOd9W+EaBPWW+wPPKQmsHxajtWjmQwWfna8mZuSeJS48LIgAZlKkpFeVyxW0qMBujb8X8ETrWy550NaFtI6t9+u7hZeTfHwqNvacKhp1RbE6dBRGWynwMVX8XW8N1+UjFaq6GCJukT4qmpN2afb8sCjUigq0GuMwYXrFVee74bQgLHWGJwPmvmLHC69EH6kWr22ijx4OKXlSIx2xT1AsSHee70w5iDBiK4aph27yH3TxkXy9V89TDdexAcKk/cVHYNnDBapcavl7y0RiQ4biu8ymM8Ga/nmzhRKya6G0cGw8CAQOjgfwwgfkwHQYDVR0OBBYEFI0cxb6VTEM8YYY6FbBMvAPyT+CyMIHJBgNVHSMEgcEwgb6AFI0cxb6VTEM8YYY6FbBMvAPyT+CyoYGapIGXMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbYIJANWFuGx90071MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADggEBABnTDPEF+3iSP0wNfdIjIz1AlnrPzgAIHVvXxunW7SBrDhEglQZBbKJEk5kT0mtKoOD1JMrSu1xuTKEBahWRbqHsXclaXjoBADb0kkjVEJu/Lh5hgYZnOjvlba8Ld7HCKePCVePoTJBdI4fvugnL8TsgK05aIskyY0hKI9L8KfqfGTl1lzOv2KoWD0KWwtAWPoGChZxmQ+nBli+gwYMzM1vAkP+aayLe0a1EQimlOalO762r0GXO0ks+UeXde2Z4e+8S/pf7pITEI/tP+MxJTALw9QUWEv9lKTk+jkbqxbsh8nfBUapfKqYn0eidpwq2AzVp3juYl7//fKnaPhJD9gs=
</item>
</string-array>
<string-array name="com_google_android_gms_fonts_certs_prod">
<item>
MIIEQzCCAyugAwIBAgIJAMLgh0ZkSjCNMA0GCSqGSIb3DQEBBAUAMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDAeFw0wODA4MjEyMzEzMzRaFw0zNjAxMDcyMzEzMzRaMHQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgCggEBAKtWLgDYO6IIrgqWbxJOKdoR8qtW0I9Y4sypEwPpt1TTcvZApxsdyxMJZ2JORland2qSGT2y5b+3JKkedxiLDmpHpDsz2WCbdxgxRczfey5YZnTJ4VZbH0xqWVW/8lGmPav5xVwnIiJS6HXk+BVKZF+JcWjAsb/GEuq/eFdpuzSqeYTcfi6idkyugwfYwXFU1+5fZKUaRKYCwkkFQVfcAs1fXA5V+++FGfvjJ/CxURaSxaBvGdGDhfXE28LWuT9ozCl5xw4Yq5OGazvV24mZVSoOO0yZ31j7kYvtwYK6NeADwbSxDdJEqO4k//0zOHKrUiGYXtqw/A0LFFtqoZKFjnkCAQOjgdkwgdYwHQYDVR0OBBYEFMd9jMIhF1Ylmn/Tgt9r45jk14alMIGmBgNVHSMEgZ4wgZuAFMd9jMIhF1Ylmn/Tgt9r45jk14aloXikdjB0MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChMLR29vZ2xlIEluYy4xEDAOBgNVBAsTB0FuZHJvaWQxEDAOBgNVBAMTB0FuZHJvaWSCCQDC4IdGZEowjTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBAUAA4IBAQBt0lLO74UwLDYKqs6Tm8/yzKkEu116FmH4rkaymUIE0P9KaMftGlMexFlaYjzmB2OxZyl6euNXEsQH8gjwyxCUKRJNexBiGcCEyj6z+a1fuHHvkiaai+KL8W1EyNmgjmyy8AW7P+LLlkR+ho5zEHatRbM/YAnqGcFh5iZBqpknHf1SKMXFh4dd239FJ1jWYfbMDMy3NS5CTMQ2XFI1MvcyUTdZPErjQfTbQe3aDQsQcafEQPD+nqActifKZ0Np0IS9L9kR/wbNvyz6ENwPiTrjV2KRkEjH78ZMcUQXg0L3BYHJ3lc69Vs5Ddf9uUGGMYldX3WfMBEmh/9iFBDAaTCK
</item>
</string-array>
</resources>
With this certificates file in place, we can now instantiate a GoogleFont.Provider reference, passing in the authority and package of the Google Fonts store, along with the certificates reference that we just defined.
@OptIn(ExperimentalTextApi::class)
val provider = GoogleFont.Provider(
providerAuthority = "com.google.android.gms.fonts",
providerPackage = "com.google.android.gms",
certificates = R.array.com_google_android_gms_fonts_certs
)
Step 3: Declaring a Google Font
Within the compose google font package comes a new class, GoogleFont, which is used to declare the Google Fonts that we wish to use.
class GoogleFont(val name: String, val bestEffort: Boolean = true)
The constructor of this class contains two fields:
- name – this is the name of the font (in the form of a string) that is to be loaded from Google Fonts
- bestEffort – if the requested font has been loaded successfully, but the specified weighting, width or italic is not available, then by default the closest match will be loaded. If you wish to disable this behaviour then you can pass a value of false for the bestEffort flag
To see this class in action, let’s use it to declare a reference to the Raleway font from Google Fonts.
@OptIn(ExperimentalTextApi::class)
val RalewayFont = GoogleFont(name = "Raleway")
Using this declared GoogleFont we can then utilise the additional Font
function that comes bundled with the Compose Google Fonts library – this will allow us to define a font that can be applied to a Text composable. If you’re familiar with Fonts in Jetpack Compose, then you’ve likely already used one of the Font functions from the Compose Text package. The main difference with this Font function is that it takes both a GoogleFont reference, along with a GoogleFont.Provider that is used to retrieve the specified Font.
@ExperimentalTextApi
fun Font(
googleFont: GoogleFont,
fontProvider: GoogleFont.Provider,
weight: FontWeight = FontWeight.W400,
style: FontStyle = FontStyle.Normal
)
Using the Raleway reference that we previously created using the GoogleFont class, we can use this Font function to create a reference to a Compose Font
. Alongside passing this Raleway reference, we’ll also need to pass the GoogleFont.provider reference that we previously defined using the certificates and provider information.
Font(googleFont = RalewayFont, fontProvider = provider)
Step 4: Setting up a Font Family
While the above gives us a reference to a Font, we need to configure a FontFamily so that we can provide this to a Text composable. The constructor for the FontFamily class takes a collection of Font references that make up the family of our font, so we can simply pass the Font that we defined above.
@OptIn(ExperimentalTextApi::class)
val RalewayFontFamily = FontFamily(
Font(googleFont = RalewayFont, fontProvider = provider)
}
Alongside this single Font
reference, we can utilise the other supported arguments of this class to provide multiple weightings to the FontFamily that is to be used for the specified Text composable. When these weights are specified, the additional weightings for the declared font will be loaded from Google Fonts.
@OptIn(ExperimentalTextApi::class)
val RalewayFontFamily = FontFamily(
Font(googleFont = RalewayFont, fontProvider = provider),
Font(googleFont = RalewayFont, fontProvider = provider, weight = FontWeight.Medium),
Font(googleFont = RalewayFont, fontProvider = provider, weight = FontWeight.Bold)
)
Step 5: Applying the Font
Now that we have the FontFamily defined, we can go ahead and utilise this within our composables. For the Text composable we can provide this for the fontFamily argument of the Text composable.
Text(
text = "Jetpack Compose",
fontFamily = RalewayFontFamily,
)
From the image above, we can see that the custom FontFamily has been applied to the composed Text. Within the FontFamily we also defined a Bold version of the Raleway font, so if we apply a fontWeight to the Text composable we’ll be able to see that the corresponding font weighting is used.
Text(
text = "Jetpack Compose",
fontFamily = RalewayFontFamily,
fontWeight = FontWeight.Bold
)
In some cases we might utilise font weighting that has been configured for our font family. In the case of our RalewayFontFamily we currently only have three weights configured – Normal, Medium and Bold. Let’s see what happens when we try to utilise a weighting that isn’t available in our font family.
Text(
text = "Jetpack Compose",
fontFamily = RalewayFontFamily,
fontWeight = FontWeight.Black
)
We can see here that the font weight of Bold has been applied, this is because of the bestEffort flag from the GoogleFont class that we saw earlier in this post. As mentioned previously, by default, the closest matching font will be used when the specified one is not available within the font family. In this case, the Black weight is not available within our font family, so the closest matching one (Bold
) has been applied. If we had disabled bestEffort by passing a false flag, then only an exact match would be applied and the default weighting would be set. The same applies for any other styling that can be applied to a font.
With these 5 steps from above, we’ve learnt how to configure our Jetpack Compose project for use with downloadable Google Fonts, followed by how to apply our chosen fonts to the Text composables in our project. With this fonts we can bring more individuality to the text in our applications, while also creating a consistent brand across our products.
I’d love to hear how you’re using downloadable Google Fonts in your project, let’s connect on Twitter!