Downloadable Fonts: How does it work?

Gonzalo Martin
AndroidPub
Published in
4 min readAug 30, 2017

--

Android 8.0 (Oreo) brought a bunch of new features. One of them is DownloadableFonts. In this article I will try to expose that feature with a simple sample. You can review this sample in this repo.

Introduction

Several times when you develop a cool android application, you need to improve the look & feel. One special component are fonts. You can make a pretty design using a proper font for your texts.

The common way to apply fonts is using a local font in your assets folder (downloaded by you previously). Then, when the app is started, you use to apply them programmatically.

Well, this way is not bad but (according with Google) it brings a few problems:

  • APK size is increased
  • App installation success rate is reduced
  • Cellular data traffic increased, phone memory and disk space is affected when multiple APKs can share the same font though a provider

Well, let’s go for the first and common way to add a font into our application. Let’s start to create a simple application (with a title and a description) that applies fonts to some texts.

Getting started with the common way

Let’s download DroidSerif font and move those ttf files into assets/fonts/droid_serif folder

I’ve used Builder pattern to build a FontHandler that manages the font to apply into a TextView. Usually, you can call it of this way:

FontHandler fontHandler = new FontHandler.Builder()
.provider(new LocalFontProvider(LocalFontProvider.DROID_SERIF))
.addTextView(title, FontHandler.FontStyle.BOLD)
.addTextView(text)
.build();

We put the title with Bold style and the description with a Regular style (by default).

LocalFontProvider will have the local typeface setup and it would looks like this:

public class LocalFontProvider implements FontProvider {

// Droid Serif Font
private static final String DROID_SERIF_FOLDER = "fonts/droid_serif";
public static final String DROID_SERIF = DROID_SERIF_FOLDER + "/droid_serif-";

// Droid Sans Font
private static final String DROID_SANS_FOLDER = "fonts/droid_sans";
public static final String DROID_SANS = DROID_SANS_FOLDER + "/droid_sans-";

private String fontName;

public LocalFontProvider(String fontName) {
this.fontName = fontName;
}

@Override
public Typeface getTypeface(Context context, String fontStyleName) {
String name = fontName + fontStyleName + ".ttf";
return Typeface.createFromAsset(context.getAssets(), name);
}
}

Note it is implementing FontProvider. It’s an interface that has one method to retrieve a Typeface

public interface FontProvider {
Typeface getTypeface(Context context, String fontStyleName);
}

You can find the FontHandler implementation here:

Finally, we have to apply the font to our texts. We can do that from out MainActivity

FontHandler fontHandler = new FontHandler.Builder()
.provider(new LocalFontProvider(LocalFontProvider.DROID_SERIF))
.addTextView(title, FontHandler.FontStyle.BOLD)
.addTextView(text)
.build();

fontHandler.applyFont(callback);

And you can find the rest of activity implementation here

Well not bad. This way, you have set the font in your texts. Good job!

Good job

You can find these changes in the following commit:

Getting started with Downloadable Fonts

Let’s introduce into the new feature by Android Oreo. We will have a new provider to get the fonts. But first, let’s explain how this feature works.

How does Downloadable Fonts work?

A font provider is an application that retrieves fonts and caches them locally so other apps can request and share fonts

downloadable fonts process

You can use the Downloadable Fonts feature in the following ways:

We are going to expose here the third way: Via support library (as resource in XML).

Using Downloadable Fonts Via support library (as resource in XML)

Android 8.0 (API level 26) and Support Library 26 offer a faster and more convenient way to declare a custom font as a resource in the XML layout. This means, there is no need to bundle the font as an asset.

First of all, we have to create our certificates. Let’s use the same as Android provides in its sample. You can find more info about certificates here.

Note: for create your own certificate, check this post.

Let’s create it in res/values folder and name it as font_certs.xml

<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>
[HASH]
</item>
</string-array>
<string-array name="com_google_android_gms_fonts_certs_prod">
<item>
[HASH]
</item>
</string-array>
</resources>

You can copy & paste the provided hash by Android from its sample.

Let’s create our font file resource. Let’s named it montserrat.xml.

<font-family xmlns:android="http://schemas.android.com/apk/res/android"
android:fontProviderAuthority="com.google.android.gms.fonts"
android:fontProviderPackage="com.google.android.gms"
android:fontProviderQuery="Montserrat"
android:fontProviderCerts="@array/com_google_android_gms_fonts_certs">
</font-family>

You can note there the special properties to use:

  • fontProviderAuthority: The font provider name (e.g. com.google.android.gms.fonts
  • fontProviderPackage: The font provider package to verify the identity of the provider (e.g. com.google.android.gms)
  • fontProviderQuery: The string query of the font (just use the font name)
  • fontProviderCerts: A list of sets of hashes for the certificates to verify the identity of the provider (we’ll use this one)

And the last step is how to call that from our code. Well, that is very easy. Just call to

context.getResources().getFont(R.font.montserrat)

That line belongs to our new CustomDownloadableFontProvider class.

Just call it from our MainActivity using FontHandler Builder and that’s it! :)

You can find these changes in the following commit:

I will be publishing the rest of the ways in the next weeks. Feel free to comment or ask any questions. Happy coding!

--

--