Downloadable Fonts with Support Library

Shaishav Gandhi
AndroidPub
Published in
5 min readAug 20, 2017

--

One of Google I/O 2017’s exciting developer announcements was first class support for custom fonts starting from Android O and its inclusion in the Support Library which extended font support till API 14 (The Support Library’s minSdk itself has been upgraded to 14). You can now choose from any of the thousands of fonts on Google Fonts and use them in your app.

Advantages of using Downloadable Fonts:

  • Reduced APK Size (You don’t have to bundle all your .ttf files with your APK)
  • Apps in the user’s phone can share fonts from a single source instead of bloating the user’s storage with redundant font files.

With native support for fonts, Android especially emphasized on the second point. A brief overview of how using the font will look like :

Android’s process to get a font

As you can see, all apps that are requesting fonts will go through a single font provider, by specifying a font contract. Hence, if a font has already been requested by AppX, a subsequent AppY will not trigger a download and will be provided the font from the cache.

FontsContract? FontsProvider? Why can’t I just tell Android to get me a font, plain and simple?

Font files are executable and Android has to provide a secure way so that no font files embedded with malicious code is executed by the system.

Thankfully, the implementation to use a font is very simple. Yes, let’s get coding.

First, let’s get started by adding Support Library to our module level build.gradle file.

dependencies {
compile 'com.android.support:support-compat:26.0.1'
}

If you’re using the beta versions of Gradle plugin 3.0, you might want to use implementation instead of compile.

Additionally, Support Library has been moved to Google’s maven repository and you no longer need the SDK Manager to download Support Library. To add Google’s Maven repository to your app, open your project build.gradle file and add the following:

repositories {
google()
// Other repositories here
}

Now that we have everything setup, let’s start adding fonts!

Go to your layout file which contains the TextView you want to apply the font to. Mine looked something like this.

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:context="com.shaishavgandhi.samplefontcompat.MainActivity"
tools:showIn="@layout/activity_main">

<TextView
android:id="@+id/newFont"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Give me a new font!"
android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="I still have old font!"
android:textSize="20sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@+id/newFont"
app:layout_constraintRight_toRightOf="parent"/>

</android.support.constraint.ConstraintLayout>

Once you go in the Design view, click on the TextView and scroll down to the fontFamily property in the right hand pane.

Click on More Fonts which should open the following dialogue.

And this is where we get to play! Check out all the fonts that are listed here and choose your favorite one. I picked out a whacky (and arguably ugly) one, Chelsea Market.

Be sure to select “Create downloadable font” and click OK.

This will have created three files : chelsea_market.xml under res/fonts, font_certs.xml and preloaded_fonts.xml under res/values. Let’s see what all those files contain :

chelsea_market.xml

<?xml version="1.0" encoding="utf-8"?>
<font-family xmlns:app="http://schemas.android.com/apk/res-auto"
app:fontProviderAuthority="com.google.android.gms.fonts"
app:fontProviderPackage="com.google.android.gms"
app:fontProviderQuery="Chelsea Market"
app:fontProviderCerts="@array/com_google_android_gms_fonts_certs">
</font-family>

This file provides a definition to Android about the font family. As you can see, it lists the fontProvider, fontProviderCerts etc which have been auto created by Android Studio.

font_certs.xml

<?xml version="1.0" encoding="utf-8"?>
<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>
<!-- Huge string cert here -->
</item>
</string-array>
<string-array name="com_google_android_gms_fonts_certs_prod">
<item>
<!-- Huge string cert here -->
</item>
</string-array>
</resources>

This file basically has the certificates mentioned in your res/font/font_name.xml. It contains a huge encrypted certificate which will verify the font.

preloaded_fonts.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
<array name="preloaded_fonts" translatable="false">
<item>@font/chelsea_market</item>
</array>
</resources>

This file is generated by Android Studio to help us preload the fonts so that there is no delay in our font being rendered when the app opens. Layout inflation and rendering are synchronous tasks. The first render might take a while since Android is still fetching your font. Declaring it in the Manifest means that Android will get it at the start of your app, instead of getting it when it starts to render the view to which you applied the font.

We do so, by adding the following meta tag in AndroidManifest.xml (If you generated it with Android Studio, it should already have been added to the manifest). Doing so w

<meta-data android:name="preloaded_fonts" android:resource="@array/preloaded_fonts"/>

Now, we can add the font to the TextView we want like so :

<TextView
android:id="@+id/newFont"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/chelsea_market"
android:text="Give me a new font!"
android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>

Let’s run our app and have a look!

Awesome! As you can see, the TextView we added the font to has the new font. However, in most cases, you might want to use the same font across the app and not add it to every TextView. A simple way to do it is to go to your styles.xml and add this to the theme of your app.

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="android:fontFamily">@font/chelsea_market</item>
</style>

And then in AndroidManifest.xml

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">

Doing this will result in :

And that’s it. Try out the new downloadable fonts, reduce your APK size, load multiple fonts and have fun!

--

--